Laravel 5.1
我试图为每个扩展我的抽象模型的模型注册一个模型观测器(他们正在扩展Illuminate''Database''Eloquent''model)。
问题是我的GenericModelObserver无法监听继承AbstractModel的模型引发的事件。
让我展示一下到目前为止我做了什么。
创建了一个服务提供者,并将其放在config/app.php 中提供者阵列的最后一个位置
<?php
// app/Providers/ObserverServiceProvider.php
namespace App'Providers;
use App'Models'Quotation;
use App'Models'AbstractModel;
use App'Observers'QuotationObserver;
use App'Observers'GenericModelObserver;
use Illuminate'Support'ServiceProvider;
class ObserverServiceProvider extends ServiceProvider
{
public function boot()
{
AbstractModel::observe(GenericModelObserver::class);
Quotation::observe(QuotationObserver::class);
}
public function register()
{
}
}
然后我有了简单的GenericModelObserver
<?php
// app/Observers/GenericModelObserver.php
namespace App'Observers;
use App'Models'AbstractModel;
class GenericModelObserver
{
public function saving(AbstractModel $model)
{
return $model->valid();
}
}
抽象模型
<?php
// app/Models/AbstractModel.php
namespace App'Models;
use Illuminate'Database'Eloquent'Model;
class AbstractModel extends Model
{
// ...
}
我的报价模型
<?php
// app/Models/Quotation.php
namespace App'Models;
class Quotation extends AbstractModel
{
// ...
}
保存报价时,GenericModelObserver无法监听保存事件或任何其他事件。
这同样适用于没有特定模型观测器的其他模型。
这是正确的策略吗?我不想通过引导方法将观察者绑定到每个模型。
不要扩展模型,而是编写自己的特性,作为观察者
下面我写了一些基本特征:
<?php
namespace App'YourPackage'Traits;
use Illuminate'Database'Eloquent'Model;
trait Observable
{
public static function bootObservable()
{
static::updating(function (Model $model) {
dd('updating');
});
}
}
并通过在模型类中键入use Observable;
来使用它。
为了便于学习,请注意traits是如何引导的:您必须将boot[TraitClassName]
方法放入trait中,才能正确引导它
千万不要在你的特质里写boot
方法,这很危险!
<?php
namespace App'Models;
use Illuminate'Database'Eloquent'Model;
use App'Observers'TeamObserver;
class Team extends Model
{
/**
* The "booting" method of the model.
*
* @return void
*/
protected static function boot()
{
parent::boot();
self::observe(TeamObserver::class);
}
}
为什么不简单地扩展父类,比如BaseObserver
我的缓存系统中有类似的东西
<?php namespace App'Observers;
class BaseObserver {
public function saving($model)
{
//do your thing here that apply to all observers, like caching
}
}
然后在您的Observers
中
<?php namespace App'Observers;
class Quotation extends BaseObserver{
//you can override any of the methods if you wish
}
将AppServiceProvider
中的boot
方法更新为以下内容:
public function boot()
{
# Register all model observers
$filesInFolder = 'File::files(app_path('/Observers'));
foreach($filesInFolder as $path) {
$observerClassName = pathinfo($path)['filename'];
$className = str_replace('Observer', '', $observerClassName);
$observerClassName = 'App''Observers''' . $observerClassName;
$className = 'App''' . $className;
$className::observe($observerClassName);
}
}
模型应遵循以下格式:
App'User
观察员应遵循以下格式:
App'Observers'UserObserver
当模型位于"models"文件夹中时:将此$className = 'App''' . $className;
换成此$className = 'App''Models''' . $className;
在父模型中,您可以执行类似的操作
/**
* If true will attach the observers of the parent class
* @var bool
*/
protected $shouldAttachParentObservers = true;
public static function boot()
{
$instance = new static;
$instance->attachParentObservers();
parent::boot();
}
public function attachParentObservers() {
$parentClass = get_parent_class($this);
if(!empty($parentClass) && $this->shouldAttachParentObservers) {
$eventObservers = [];
foreach ($this->getObservableEvents() as $event) {
$eventObservers[$event] = ($this::$dispatcher->getListeners("eloquent.{$event}: {$parentClass}"));
foreach ($eventObservers[$event] as $observer) {
$eventName = "eloquent.{$event}: {$this::getClassName()}";
$this::$dispatcher->listen($eventName, $observer);
}
}
}
}
/**
* You may use different way to find the class name
*/
public static function getClassName() {
return static::class;
}