前言:
原作者看到可以联系删除
触发器的大致步骤:
1, 定义基类(BseModel)方便每个Model继承,
2, 重写Model.php的boot()方法,实现自定义beforeUpdate(等)&afterUpdate(等)
3, 继承基类(BseModel)的模型新增beforeUpdate(等)&afterUpdate(等), 实现触发器
观察者的大致步骤:
1, 新建观察者文件,一般在APP\Observers
2, 注册观察者, 一般可以选择已经存在的ServiceProvider(一般在App\Providers下面)里面或者新建一个都可以, 修改boot()方法
3, 根据laravel提供的的10中方法, 更新观察者文件对应方法里面的代码
可能存在的坑:
1, 不管是自定义触发器还是观察者, 都只支持ORM Query, 类似 User::find(1)->update() 或者 User::where('id',$id)->first()->update
User::find(1)->update();##可以监听
User::where('id',$id)->first()->update();##可以监听
User::where('id',$id)->update();##不可以监听
2, 观察者的命名空间需要注意, 特别是如果有继承关系的, 想下面这样的情况,如果是前一个A在操作,不能观察到后一个A, 虽然是继承关系
class App\Model\API\A extends App\Model\Common\A{}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
先说自定义触发器:
转自:https://my.oschina.net/slothcode/blog/874278
该博客的原文地址已无法打开,不再附上
Laravel框架本身没有自带beforeSave、afterSave的方法事件,但是可以自行加上这些,类似Yii框架,本身就自带这些方法,这类方法就像一个事件、触发器,可以在模型save之前,做一些属性值改变或者更多逻辑补充。
列举一下可以增加哪些before/after事件方法
before/afterCreate()
before/afterSave()
before/afterUpdate()
before/afterDelete()
before/afterValidate()
如何给Model增加这些方法呢?
首先要给所有model定义一个基类,然后所有model都继承这个基类,
<?php
namespace libs\Eloquent;
abstract class Model extends \Illuminate\Database\Eloquent\Model {
}
定义基类之后,我们来看看 \Illuminate\Database\Eloquent\Model,既然要添加对模型的操作,还是得深入了解一下。找到boot方法,上面有注释
/**
* The "booting" method of the model.("引导"模型的方法)
*
* @return void
*/
protected static function boot()
{
$class = get_called_class();
static::$mutatorCache[$class] = array();
// Here we will extract all of the mutated attributes so that we can quickly
// spin through them after we export models to their array form, which we
// need to be fast. This will let us always know the attributes mutate.
// 在这里我们将提取的所有变异属性,这样我们可以很快旋转通过他们出口模型后数组形式,我们需要快。这将让我们永远知道变异的属性。
foreach (get_class_methods($class) as $method)
{
if (preg_match('/^get(.+)Attribute$/', $method, $matches))
{
if (static::$snakeAttributes) $matches[1] = snake_case($matches[1]);
static::$mutatorCache[$class][] = lcfirst($matches[1]);
}
}
static::bootTraits();
}
那么可以从这里入手,在自己定义的基类上重写一下这个方法
/**
* The "booting" method of the model.("引导"模型方法)
* 覆盖之前/之后附加方法挂钩到模型事件。
* @see \Illuminate\Database\Eloquent\Model::boot()
* @return void
*/
public static function boot() {
parent::boot();
$myself = get_called_class();
$hooks = array('before' => 'ing', 'after' => 'ed');
$radicals = array('sav', 'validat', 'creat', 'updat', 'delet');
foreach ($radicals as $rad) {
foreach ($hooks as $hook => $event) {
$method = $hook.ucfirst($rad).'e';
if (method_exists($myself, $method)) {
$eventMethod = $rad.$event;
self::$eventMethod(function($model) use ($method){
return $model->$method($model);
});
}
}
}
}
接着就是其他所有的model层,举个栗子
<?php namespace ifish\Model\Ad;
use libs\Eloquent\Model;
class Ad extends Model
{
protected $table = 'ad_ad';
protected $guarded = ['id'];
public $timestamps = false;
public function beforeCreate() {
$this->channel = 'android';
//或者不返回,因为只有一个布尔假将停止操作
return true;
}
}
只要调用create方法就会触发对应事件,例如
Ad::create($data);
//调用save必须在model内增加beforeSave或者afterSave
Ad::save($data);
之前在公司项目中,大量使用mysql触发器,遇到过的应该懂的,反正就一句话,不好维护,出问题了,不好定位,之后只能改造一下,把触发器都抽离,能用before/after就用,不用可以用观察者,反正怎么灵活怎么来。
再说观察者:
转自:
1,Laravel 的观察者使用记录与两种方式 | Laravel China 社区
2,Laravel 中的模型事件与 Observer | Laravel China 社区
根据文档的观察者,我们平时的使用方式是先创建一个 App\Observers 文件夹,然后创建想要操作的模型对应的 observer,比如说创建一个 UserObserver。
也可以用artisan
php artisan make:observer OrderObserver -m Order
<?php
namespace App\Observers;
use App\User;
class UserObserver
{
}
获得这个类之后,我们需要到 AppServiceProvider 的 boot 方法当中进行注册,也可以是其他的 ServiceProvider,不固定。
public function boot()
{
User::observe(UserObserver::class);
}
别忘了引入 model,做完这些我们就可以各种操作了。
laravel 已经为我们预先定义了 10 种方法:
creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。
这些方法分别是进行时与完成之后。比如我们删除用户的时候,可以用 deleting 方法删除跟这个用户有关联的其他数据。
public function deleting(User $user)
{
Thread::where('user_id', $user->id);
}
希望弄的更清楚的,可以参考 Laravel 中的模型事件与 Observer。
最近跟着 TDD 构建 Laravel 论坛笔记教程做下去,发现原来还能直接在模型当中直接定义 boot 方法,进行同样的操作。
public static function boot()
{
static::deleting(function ($model) {
$model->threads->delete();
});
}
我预先定义了关联关系,所以取到相关的 Thread 能直接删除。
insert 方法不会被监听到,以及批量删除时也同样不会被监听到,必须一条一条创建或者一条一条删除才行。(源码没咋研究,也不是很清楚,只是踩到过这坑)
就比如上面的代码,这样子批量删除 thread 是不会被监听到的,你可以这样写
$model->threads->each->delete();
题外话:
使用 laravel 快一年了,跟着教程学了差不多三分之一,真的学到了许多以前完全不知道的使用方式。因为有 laracasts 的账户,所以先过一遍视频,然后对着翻译教程再来一遍,收获真的巨大,顺便还能帮助译者改正一些小错误,也有不小的成就感。(小声:推荐小白学习,真的不要再说什么去阅读源码了,效果真的不大,过几天基本全忘关了。多写多用才能记住,才能更好的掌握编程这门技能,也是最快的学习方式)。
————————————————
原文作者:tiroGuang
转自链接:https://learnku.com/articles/18511
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。
文章评论