我有一个已发布的过滤器,我用于我的文章。访客只能查看已发布的文章,登录的用户可以查看和应用过滤器(?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
模型中所有返回的文章在返回之前都通过此过滤器运行?
答案 0 :(得分:4)
更好的方法是粘贴它有点太长,并且在核心中就像SoftDeleting
一样。
如果您需要,请阅读此内容http://softonsofa.com/laravel-how-to-define-and-use-eloquent-global-scopes/
简短方法:您需要全球范围。以下是您分两步进行的操作(稍微压扁):
1创建一个实现PublishedScope
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
,但这取决于你。
编辑 remove
方法已更新 - 感谢@Leon在将此范围与SoftDeletingTrait
一起使用时指出了意外行为。问题更深一点:
当您使用SoftDeletingScope
或其他NULL
时,使用NOT NULL
或use
约束和时,此范围不是第一个使用的范围(是,remove
语句的顺序在这里很重要,{{1}}方法将无法按预期工作。它不会删除任何绑定,也不会移除它应该的绑定。
答案 1 :(得分:0)
你可以使用trait并在启动方法中添加你的方法或过滤器检查以下内容 http://laravel.com/docs/4.2/eloquent#global-scopes