BOOTING ELOQUENT MODEL TRAITS

So I've learnt a little Laravel/Eloquent trick today that is very much under-documented. Save for a casual mention in the Laravel documentation.

Skip to TL;DR if you're you just want to see the trick.

You may know that you can add a static boot() function to an Eloquent model which is an always-run function. It can be used, for example, to set up any event bindings you might require on that model. For example, you might want to send an email out every time a User is created (bad example), you could do that as follows:

class User extends Eloquent {

    public static function boot()
{
parent::boot(); static::created(function($user){
// Send a mailing...
}
}
}

But what if you want to do that in a trait?

Consider this scenario; I want to add search functionality to a range of models. I could extend the Eloquent Model class with a new class such as SearchableModel, but I would like to build something I can easily drop in other projects without risking stepping on the toes of that application. A trait works here because it can be dropped in easily and is relatively unintrusive, you just get a few extra functions that can be overridden easily.

So I create a SearchableTrait.

trait SearchableTrait {

    public function search($query)
{
// ...
}
}

Pretty simple so far, we can call $model->search('query') and it will return us the models it matches.

However, I'm planning on using a third-party search application (elasticsearch, if anyone is interested) and, rather than searching directly on the database, it uses its own indexing, which requires I set up each row in the index myself. An easy way to do that would be to simply add the model to the index when it's created with the event.

But where do I put this code? I could put a boot() function in there, but the model might override it, thus breaking my search and destroying any chance of being able to write something reusable.

TL;DR

So the Laravel chaps have clearly considered that you need some way of 'booting' your traits as you would an Eloquent model and allowed you to define one for a trait as follows:

trait SearchableTrait {

    public function search($query)
{
// ...
} public static function bootSearchableTrait()
{
static::created(function($item){
// Index the item
});
}
}

So there's a classic bit of Eloquent magic going on here. But if you have a static function on your trait, named boot[TraitName], it will be executed as the boot() function would on an Eloquent model. Which is a handy place to register your model events.

The example in the documentation uses this for registering a global scope to intercept all running queries in order to soft delete models.

As ever with this stuff, there are other nice ways to achieve the same thing, but it's always good having these under-documented quirks in your arsenal to call on if needed. Do you know of any others?

Posted on Jun 02, 2015

 
参考 laravel document 如下:

Global Scopes

Sometimes you may wish to define a scope that applies to all queries performed on a model. In essence, this is how Eloquent's own "soft delete" feature works. Global scopes are defined using a combination of PHP traits and an implementation of Illuminate\Database\Eloquent\ScopeInterface.

First, let's define a trait. For this example, we'll use the SoftDeletes that ships with Laravel:

trait SoftDeletes {

    /**
* Boot the soft deleting trait for a model.
*
* @return void
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
} }

If an Eloquent model uses a trait that has a method matching the bootNameOfTrait naming convention, that trait method will be called when the Eloquent model is booted, giving you an opportunity to register a global scope, or do anything else you want. A scope must implement ScopeInterface, which specifies two methods: apply and remove.

The apply method receives an Illuminate\Database\Eloquent\Builder query builder object and the Model it's applied to, and is responsible for adding any additional where clauses that the scope wishes to add. The remove method also receives a Builder object and Model and is responsible for reversing the action taken by apply. In other words, remove should remove the where clause (or any other clause) that was added. So, for our SoftDeletingScope, the methods look something like this:

/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$builder->whereNull($model->getQualifiedDeletedAtColumn()); $this->extend($builder);
} /**
* Remove the scope from the given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function remove(Builder $builder, Model $model)
{
$column = $model->getQualifiedDeletedAtColumn(); $query = $builder->getQuery(); foreach ((array) $query->wheres as $key => $where)
{
// If the where clause is a soft delete date constraint, we will remove it from
// the query and reset the keys on the wheres. This allows this developer to
// include deleted model in a relationship result set that is lazy loaded.
if ($this->isSoftDeleteConstraint($where, $column))
{
unset($query->wheres[$key]); $query->wheres = array_values($query->wheres);
}
}
}

最新文章

  1. mac下配置openfire
  2. URAL 1932 The Secret of Identifier 题解
  3. style="display"之后不能获取offsetHeight或clientWidth这类测量的值
  4. SDUT 1220 完美数
  5. Qt for iOS,Qt 与Objective C混合编程
  6. java web工程的错误页面的简单配置
  7. Grails教程
  8. Introduction to Json
  9. 在Linux搭建Git服务器
  10. [Swift]LeetCode76. 最小覆盖子串 | Minimum Window Substring
  11. jQuery validdate插件的使用
  12. MySql数据库执行insert时候报错:Column count doesn't match value count at row 1
  13. Ruler.java
  14. ssh文件配置
  15. 第13月第10天 swift3.0
  16. [js]BOM篇
  17. 一维码ITF 25简介及其解码实现(zxing-cpp)
  18. Linux sudo 配置
  19. java SequenceInputStream类(序列输入流)的用法示例
  20. Nutch URL过滤配置规则

热门文章

  1. 在win下开发的项目怎么迁移到linux下面才能正常运行?
  2. MongoDB的复合唯一索引
  3. net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第二章 入门篇-快速入门ASP.NET Core看这篇就够了
  4. 初学java2 认识面向对象 以及运算符 输入输出
  5. HDR10 中的名词解释
  6. jQuery 手写菜单(ing)
  7. Linux学习(四)-Linux常用命令
  8. easyui的combobox默认选中第一个选项
  9. Java 读取 .properties 文件的几种方式
  10. 6. Design Patterns with First-Class Functions