Laravel 5.1
我试图为每个扩展我的抽象模型的模型注册一个模型观测器(他们正在扩展Illuminate\Database\Eloquent\model)。
问题是我的GenericModelObserver无法监听继承AbstractModel的模型引发的事件。
让我展示一下到目前为止我做了什么。
创建了一个服务提供者,并将其放在config/app.php 中提供者阵列的最后一个位置
<?php
// app/Providers/ObserverServiceProvider.php
namespace AppProviders;
use AppModelsQuotation;
use AppModelsAbstractModel;
use AppObserversQuotationObserver;
use AppObserversGenericModelObserver;
use IlluminateSupportServiceProvider;
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 AppObservers;
use AppModelsAbstractModel;
class GenericModelObserver
{
public function saving(AbstractModel $model)
{
return $model->valid();
}
}
抽象模型
<?php
// app/Models/AbstractModel.php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class AbstractModel extends Model
{
// ...
}
我的报价模型
<?php
// app/Models/Quotation.php
namespace AppModels;
class Quotation extends AbstractModel
{
// ...
}
保存报价时,GenericModelObserver无法监听保存事件或任何其他事件。
这同样适用于没有特定模型观测器的其他模型。
这是正确的策略吗?我不想通过引导方法将观察者绑定到每个模型。
不要扩展模型,而是编写自己的特性,作为观察者
下面我写了一些基本特征:
<?php
namespace AppYourPackageTraits;
use IlluminateDatabaseEloquentModel;
trait Observable
{
public static function bootObservable()
{
static::updating(function (Model $model) {
dd('updating');
});
}
}
并通过在模型类中键入use Observable;
来使用它。
为了便于学习,请注意traits是如何引导的:您必须将boot[TraitClassName]
方法放入trait中,才能正确引导它
千万不要在你的特质里写boot
方法,这很危险!
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use AppObserversTeamObserver;
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 AppObservers;
class BaseObserver {
public function saving($model)
{
//do your thing here that apply to all observers, like caching
}
}
然后在您的Observers
中
<?php namespace AppObservers;
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);
}
}
模型应遵循以下格式:
AppUser
观察员应遵循以下格式:
AppObserversUserObserver
当模型位于"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;
}