全局过滤 - 如何在 Laravel Eloquent 中使用全局范围 [英] Global filtering - how to use global scope in Laravel Eloquent

查看:15
本文介绍了全局过滤 - 如何在 Laravel Eloquent 中使用全局范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个已发布的过滤器,用于我的文章.访客只能查看已发布的文章,登录用户可以查看和应用过滤器(?published=0/1):

I have a published filter that I use for my articles. Guests can only view published articles, logged in users can view and apply filter (?published=0/1):

public function scopePublishedFilter($query)
{
    if(!Auth::check()) $query->where('published', '=', 1);
    else
    {
        $published = Input::get('published');
        if (isset($published)) $query->where('published', '=', $published);
    }

    return $query;
}

我在我的 ArticlesController 中应用它:

I apply this in my ArticlesController:

public function index()
{
    return View::make('articles.index', [
        'articles' => Article::with('owner')
            ->with('category')
            ->with('tags')
            ->publishedFilter()
            ->get()
    ]);
}

关于文章关系:

public function articles()
{
    return $this->hasMany('Article')->publishedFilter();
}

但理想情况下,我只想在 Article 模型本身中定义它,因为在实现新功能或视图时很容易忘记包含此过滤器.

But ideally I would like to only define it in the Article model itself, since it's easy to forget to include this filter when implementing new features or views.

如何确保所有从 Article 模型返回的文章在返回前都经过此过滤器?

How can I make sure that all returned articles from the Article model are run through this filter before returned?

推荐答案

更新:只需使用这个:https://github.com/jarektkaczyk/laravel-global-scope L5+ 中的全局作用域

<小时>

更好的方法是粘贴它有点太长,并且像核心中的 SoftDeleting 一样工作.

UPDATE: Just use this: https://github.com/jarektkaczyk/laravel-global-scope for global scopes in L5+


Better way is a bit too long to paste it and works like SoftDeleting thing in the core.

如果需要,请阅读此内容 http:///softonsofa.com/laravel-how-to-define-and-use-eloquent-global-scopes/

Read this if you want it http://softonsofa.com/laravel-how-to-define-and-use-eloquent-global-scopes/

捷径:您需要全局范围.以下是您分两步完成的方法(有点压扁):

Short way: you need global scope for this. And here's how you do it in 2 steps (squashed a bit):

1 创建一个实现ScopeInterface

class PublishedScope implements ScopeInterface {

public function apply(Builder $builder)
{
    $table = $builder->getModel()->getTable();
    $builder->where($table.'.published', '=', 1);
    $this->addWithDrafts($builder);
}

public function remove(Builder $builder)
{
    $query = $builder->getQuery();
    $column = $builder->getModel()->getTable().'.published';
    $bindingKey = 0;
    foreach ((array) $query->wheres as $key => $where)
    {
        if ($this->isPublishedConstraint($where, $column))
        {
            unset($query->wheres[$key]);
            $query->wheres = array_values($query->wheres);
            $this->removeBinding($query, $bindingKey);
        }

        // Check if where is either NULL or NOT NULL type,
        // if that's the case, don't increment the key
        // since there is no binding for these types
        if ( ! in_array($where['type'], ['Null', 'NotNull'])) $bindingKey++;
    }
}

protected function removeBinding(Builder $query, $key)
{
    $bindings = $query->getRawBindings()['where'];
    unset($bindings[$key]);
    $query->setBindings($bindings);
}

protected function addWithDrafts(Builder $builder)
{
    $builder->macro('withDrafts', function(Builder $builder)
    {
        $this->remove($builder);
        return $builder;
    });
}

2 通过调用 static::addGlobalScope(new AbcScope)

// the model
public static function boot()
{
    parent::boot();

    static::addGlobalScope(new PublishedScope);
}

如果我是你,我会使用 published_at 列并检查它是否存在 null 而不是 = 1,但这取决于你.

If I were you I would use published_at column and check it for null instead of = 1, but that's up to you.

edit remove 方法已更新 - 感谢@Leon 在将此范围与 SoftDeletingTrait 一起使用时指出了意外行为.问题有点深了:

edit remove method updated - thanks to @Leon for pointing out unexpected behaviour, when using this scope together with SoftDeletingTrait. The problem is a bit deeper:

当你将这个与 SoftDeletingScope 或另一个一起使用时,它利用 NULLNOT NULL 约束 and这个范围不是第一个使用的(是的,use 语句的顺序在这里很重要),remove 方法将无法按预期工作.它不会删除任何绑定或不应该删除的绑定.

when you use this one with SoftDeletingScope or another one, that utilizes NULL or NOT NULL constraint and this scope is not the first one used (yes, order of use statements matters here), remove method will not work as expected. It will not remove any binding or not the one, that it should.

这篇关于全局过滤 - 如何在 Laravel Eloquent 中使用全局范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆