laravel的观察者和自定义触发器

前言:

原作者看到可以联系删除

触发器的大致步骤:


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
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值