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

BOOTING ELOQUENT MODEL TRAITS的更多相关文章

  1. laravel Eloquent 模型(也就是我本时说的Model)

    laravel的 Eloquent 模型其实就是我们平时说的MVC里Model,只是换了个名字而已~ 1)Eloquent 是啥? Eloquent 本质就一个查询构建器(laravel里叫查询构建器 ...

  2. laravel query builder/ Eloquent builder 添加自定义方法

    上次干这事已经是一年前了,之前的做法特别的繁琐.冗余,具体就是创建一个自定义 Builder 类,继承自 Query\Builder,然后覆盖 Connection 里面获取 Builder 的方法, ...

  3. Laravel 事件侦听的几个方法 [Trait, Model boot(), Observer Class]

    1 Trait 1.1 可以在 Trait 中定义一个静态的 bootFooBar() 方法,注:FooBar 是你的 Trait 名称 namespace App\Traits; use App\A ...

  4. Laravel 5.1 文档攻略 —— Eloquent:模型对象序列化

    在写api的时候,数据一般是以json格式进行传输的,没有对象可以直接使用.这个时候,对数据的序列化转换就很重要,Eloquent提供了很方便的方法和约定,不仅可以转换,还可以控制里面的键值. 基本用 ...

  5. Laravel 5.1 文档攻略 —— Eloquent: 读取器和修饰器

    date_range 8月前 tag_faces Woody remove_red_eye 1483 chat0 简介 这一章其实很简单,Model的属性不是和数据表的字段一一对应吗? 那么在存储和呈 ...

  6. Laravel 5.1 文档攻略 —— Eloquent Collection

    简介 像all()和get(),还有一些处理模型关系这种会返回多条数据的方法,在Eloquent里面会返回一个collection对象集合(对象装在对象里),而不是像DQB的数组结果集合(对象装在数组 ...

  7. Laravel 5.1 文档攻略 —— Eloquent:模型关系

    简介 其实大家都知道,数据表之间都是可以关联的,前面讲过了,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: E ...

  8. Laravel教程 四:数据库和Eloquent

    Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方 ...

  9. Laravel 5 基础(七)- Eloquent (laravel 的ORM)

    我们来生成第一个模型 php artisan make:model Article #输出 Model created successfully. Created Migration: 2015_03 ...

随机推荐

  1. 选择最佳策略:简单的方式和globals()

    promos = [fidelity_promo, bulk_item_promo, large_order_promo] ➊ def best_promo(order): ➋ "" ...

  2. varchar、nvarchar

    Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示. NCHAR.NVARCHAR.NTEXT.这三种从名字上看比前面三种多了个 ...

  3. LeetCode 899. Orderly Queue

    899. Orderly Queue(有序队列) 题目: 给出了一个由小写字母组成的字符串 S.然后,我们可以进行任意次数的移动. 在每次移动中,我们选择前 K 个字母中的一个(从左侧开始),将其从原 ...

  4. C#picturebox控件图片以json格式上传java后台保存

    关于winform上传图片到Java后端,保存到数据库,有多种方法,本文主要介绍利用picturebox控件,点击按钮上传图片,将图片转化为base64格式,以json格式上传到Java后台,再从ja ...

  5. shiro 权限过滤器 -------(1)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABBEAAAJRCAIAAACcEbhqAAAgAElEQVR4nO3dv67sVtkHYEefhIKUIC ...

  6. 行内块和文字垂直对齐vertical-agign

    vertical-align 垂直对齐 (对于块级元素无效,主要用来控制表单或者图片与文字对齐的) 图片和文字默认是基线对齐 属性: baseline 基线 top 顶线 middle 中线 bott ...

  7. RPC、RMI、REST的区别

    初入职场,接触了不少企业常用的技术,与学校实训使用的技术有很大差异,在这里记录一下RPC.RMI与REST的区别. 概念 RPC(Remote Procedure Call,远程过程调用) 一种通过从 ...

  8. eclipse debug 调试找不到资源问题解决

    eclipse debug 的时候,如果使用maven bulid,就可能找不到class,这种情况就需要先停止服务,然后配置 Run configurations-Source,然后remove掉D ...

  9. JAVA对ArrayList排序

    ava如何对ArrayList中对象按照该对象某属性排序 增加排序功能,打印时:输出学生对象的时候,需要先按照年龄排序,如果年龄相同,则按照姓名排序,如果姓名也相同,则按照学号排序. Code hig ...

  10. Java虚拟机内存基础、垃圾收集算法及JVM优化

    1 JVM 简单结构图   1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...