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 ...
随机推荐
- jQuery获取当前checkbox的值
背景: 目前想实现登录的“记住我”功能,需要获取当前checkbox是否被点击,百度了一通,全是多个复选框选中了哪一个的解答, 迫于无奈,自己在W3school上面查询了checkbox的所有属性,并 ...
- 题目13 在O(1)时间删除链表节点
///////////////////////////////////////////////////////////////////////////////////// // 3. 题目13 在O( ...
- codeforces 1251D Salary Changing (二分+贪心)
(点击此处查看原题) 题意分析 一共有s元钱,要用这些钱给n个人发工资,发给每个人的工资si有最少和最多限制 si ∈[li,ri],在发给n个人的总工资小于s的情况下,要求发给n个人中的工资的中位数 ...
- redis集群搭建及一些问题
redis 1.简化版redis (本套Redis集群为简化版安装部署,只需解压至普通用户家目录下或者任意目录,解压后修改脚本,执行脚本后即可使用.) 注意,此版本需要在redis配置文件中添加 pr ...
- shell习题第17题:检测磁盘
[题目要求] 写一个shell脚本,检测所有磁盘分区使用率和inode使用率并记录到以当天日期命名的日志文件里,当发现某个分区容量或者inode使用量大于85%时候,发邮件提醒 [核心要点] df d ...
- 8-MySQL DBA笔记-测试基础
第三部分 测试篇 测试需要掌握的知识面很广泛,本篇的关注点是数据库的性能测试和压力测试,对于其他领域的测试,由于涉猎不多,笔者就不做叙述了.DBA的工作职责之一就是评估软硬件,这往往是一项很耗时的工作 ...
- LeetCode:184.部门工资最高的员工
题目链接:https://leetcode-cn.com/problems/department-highest-salary/ 题目 Employee 表包含所有员工信息,每个员工有其对应的 Id, ...
- VUE实现简单的全选/全不选
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- element-ui el-cascader级联选择器设置指定层级不能选中
有时候用element-ui el-cascader级联选择器添加分类时会遇到最多添加几级的限定.看了文档,只要给需要禁止选择的选项添加disabled属性就可以.但是使用一层一层循环遍历数据感觉很麻 ...
- 14.JdbcUtils框架
1.编写自己的JdbcUtils 框架 2.使用 dbUtils 框架 1.视频中自己编写的JdbcUtils框架差不多就是dbUtils框架 2.使用 使用dbutils框架完成curd,以及批处理 ...