【问题标题】:Global filtering - how to use global scope in Laravel Eloquent全局过滤 - 如何在 Laravel Eloquent 中使用全局范围
【发布时间】:2014-11-23 14:07:47
【问题描述】:

我有一个已发布的过滤器,用于我的文章。访客只能查看已发布的文章,登录用户可以查看和应用过滤器(?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('articles.index', [
        'articles' => Article::with('owner')
            ->with('category')
            ->with('tags')
            ->publishedFilter()
            ->get()
    ]);
}

关于文章关系:

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

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

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

【问题讨论】:

    标签: laravel laravel-4 eloquent


    【解决方案1】:

    您可以使用 trait 并在引导方法中添加您的方法或过滤器检查以下内容 http://laravel.com/docs/4.2/eloquent#global-scopes

    【讨论】:

      【解决方案2】:

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


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

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


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

      1 创建一个实现ScopeInterface的类PublishedScope

      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) 在 Eloquent 模型中启动该类

      // the model
      public static function boot()
      {
          parent::boot();
      
          static::addGlobalScope(new PublishedScope);
      }
      

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


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

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

      【讨论】:

      • 另一个很好的答案,非常感谢。我同意published_at 的评论。并且您的网站已被加入书签 :)
      • 在同样实现了 softDelete 特征的模型上使用此代码时发现了一个错误。删除范围时(在 remove() 中) $query->wheres 将比 $query->getRawBindings()['where'] 包含更多的项目 - 在我的情况下,我有 3 个 where 但只有 2 个绑定 - 它取消设置错误的绑定。希望可以节省一些时间:-)
      • 设法通过在 remove() 中向 foreach 循环添加一个计数器来修复它,并且仅在 $where['type'] != 'Null' 时才增加
      • @Leon 谢谢你。是的,这种行为有可能发生 - 请阅读我的编辑以获取更多信息。
      猜你喜欢
      • 1970-01-01
      • 2016-04-14
      • 1970-01-01
      • 2015-12-02
      • 1970-01-01
      • 2012-04-29
      • 2015-07-06
      • 1970-01-01
      • 2023-03-09
      相关资源
      最近更新 更多