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

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

问题描述

我有一个发布的过滤器,我用于我的文章。客人只能查看已发表的文章,登录的用户可以查看和应用过滤器(?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

  public function index()
{
return View :: make ('category')
- >('category')
- > with('tags')
- > publishedFilter()
- > get()
]);
}

关于文章关系:

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

但理想情况下,我只想在

如何确保所有的

解决方案

h2>更新:只需使用以下命令: https://github.com/jarektkaczyk/laravel-globalscope 对于L5 +中的全局范围




更好的方法是粘贴一点太长,像 SoftDeleting 内核中的东西。



如果你想要,请阅读这个 http://softonsofa.com/laravel-how-to-define-and-use-eloquent-global-范围/






短路:您需要全局范围。这里是你如何做两个步骤(挤压一点):



1创建一个类已发布的 ScopeInterface

  class PublishedScope实现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()。
$ 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);
}

//检查是否为NULL或NOT NULL类型,
//如果是这样,不要递增键
//,因为没有这些类型的绑定
if(!in_array($ where ['type'],['Null','NotNull']))$ bindingKey ++;
}
}

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

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

2通过调用在您的雄辩模型中引导该类static :: addGlobalScope(new AbcScope)

  //模型
public static function boot()
{
parent :: boot();

static :: addGlobalScope(new PublishedScope);
}

如果我是你,我会使用 published_at 列,并检查 null 而不是 = 1 ,但这取决于你。 p>




编辑 删除方法更新 - 谢谢当使用此范围与 SoftDeletingTrait 时,将@Leon指向意外行为。当您使用 SoftDeletingScope 或另一个使用$($)的 NULL NOT NULL 约束此范围不是第一个使用的(是的, 使用语句在这里),删除方法将无法正常工作。它不会删除任何绑定,而不是它应该。


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;
}

I apply this in my ArticlesController:

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

And on the article relationships:

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

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.

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

解决方案

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.

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 Create a class PublishedScope that implements 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 Boot that class in your Eloquent model by calling static::addGlobalScope(new AbcScope)

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

    static::addGlobalScope(new PublishedScope);
}

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 method updated - thanks to @Leon for pointing out unexpected behaviour, when using this scope together with SoftDeletingTrait. The problem is a bit deeper:

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雄辩中使用全球范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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