BOOTING ELOQUENT MODEL TRAITS
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
TAGGED
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的更多相关文章
- laravel Eloquent 模型(也就是我本时说的Model)
laravel的 Eloquent 模型其实就是我们平时说的MVC里Model,只是换了个名字而已~ 1)Eloquent 是啥? Eloquent 本质就一个查询构建器(laravel里叫查询构建器 ...
- laravel query builder/ Eloquent builder 添加自定义方法
上次干这事已经是一年前了,之前的做法特别的繁琐.冗余,具体就是创建一个自定义 Builder 类,继承自 Query\Builder,然后覆盖 Connection 里面获取 Builder 的方法, ...
- Laravel 事件侦听的几个方法 [Trait, Model boot(), Observer Class]
1 Trait 1.1 可以在 Trait 中定义一个静态的 bootFooBar() 方法,注:FooBar 是你的 Trait 名称 namespace App\Traits; use App\A ...
- Laravel 5.1 文档攻略 —— Eloquent:模型对象序列化
在写api的时候,数据一般是以json格式进行传输的,没有对象可以直接使用.这个时候,对数据的序列化转换就很重要,Eloquent提供了很方便的方法和约定,不仅可以转换,还可以控制里面的键值. 基本用 ...
- Laravel 5.1 文档攻略 —— Eloquent: 读取器和修饰器
date_range 8月前 tag_faces Woody remove_red_eye 1483 chat0 简介 这一章其实很简单,Model的属性不是和数据表的字段一一对应吗? 那么在存储和呈 ...
- Laravel 5.1 文档攻略 —— Eloquent Collection
简介 像all()和get(),还有一些处理模型关系这种会返回多条数据的方法,在Eloquent里面会返回一个collection对象集合(对象装在对象里),而不是像DQB的数组结果集合(对象装在数组 ...
- Laravel 5.1 文档攻略 —— Eloquent:模型关系
简介 其实大家都知道,数据表之间都是可以关联的,前面讲过了,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: E ...
- Laravel教程 四:数据库和Eloquent
Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方 ...
- Laravel 5 基础(七)- Eloquent (laravel 的ORM)
我们来生成第一个模型 php artisan make:model Article #输出 Model created successfully. Created Migration: 2015_03 ...
随机推荐
- 【AtCoder】AGC011
AGC011 A - Airport Bus 大意:有N个人,每个人只能在\([T_i,T_i +K]\)这段区间乘车,每辆车安排C人,问最少安排几辆车 直接扫,遇到一个没有车的在\(T_i +K\) ...
- Python中几个必须知道的函数
Python中自带了几个比较有意思的函数,一般在面试或者笔试基础的时候会问到,其中3个就是map.filter.reduce函数. 1.map(function, iterable) 它第一个要传的元 ...
- unittest参数化(paramunittest)
前言 paramunittest是unittest实现参数化的一个专门的模块,可以传入多组参数,自动生成多个用例前面讲数据驱动的时候,用ddt可以解决多组数据传入,自动生成多个测试用例.本篇继续介绍另 ...
- 论文阅读:《Bag of Tricks for Efficient Text Classification》
论文阅读:<Bag of Tricks for Efficient Text Classification> 2018-04-25 11:22:29 卓寿杰_SoulJoy 阅读数 954 ...
- js判断变量是否为整数
//返回false则不为整数数字,返回ture则反之 var isIntNumber=function(val){ if (isNaN(val) || Math.floor(val) != val) ...
- mysql replace substring 字符串截取处理
SELECT a1,a2,replace(a2, "豫ICP备16006180号-", "") a22,a3,a4,a5 FROM `aaab` order b ...
- php--正则(手机号码)
PHP手机号码正则表达式 php用正则表达式判断手机号码的写法:从文章中匹配出所有的手机号就可以preg_match_all(),如果要检查用户输入的手机号是否正确可这样来检查:preg_match( ...
- LeetCode 腾讯精选50题-- 买卖股票的最佳时机 II
贪心算法: 具体的解题思路如下: II 的解题思路可以分为两部分, 1. 找到数组中差值较大的两个元素,计算差值. 2. 再步骤一最大的元素的之后,继续遍历,寻找差值最大的两个元素 可以得出的是,遍历 ...
- 08 redis缓存穿透、缓存雪崩、缓存击穿
Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题.其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解.如果对数据的一致性要求很 ...
- api校验
服务端代码: import hashlib import time KEY = 'RTYUIFGHJKVBNM' def gen_key(ctime): md5 = hashlib.md5() key ...