Nor*_*gul 5 php dependency-injection traits laravel
我有一个TimezoneTrait在模型中使用的User。我还有一个UserRepositoryInterface通过服务提供者加载的文件,并且在所有类中都可以正常工作,因此绑定应该没问题:
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
public function provides()
{
return [
UserRepositoryInterface::class,
];
}
Run Code Online (Sandbox Code Playgroud)
现在我遇到的问题是我必须在我的特质中使用该存储库,所以我自然地这样做了:
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
Run Code Online (Sandbox Code Playgroud)
但转储显示存储库是null. 特征不能注入依赖吗?
在特质中定义__constructor实际上是错误的。或者只是一个糟糕的设计。构造函数应该特定于它们所属的类,而不是特征。那么另一个问题是,您在 Model 类中导入特征,这意味着您应该特别遵循其关于如何加载模型中的特征的规则。
在boot模型的构建阶段,它在类中递归搜索导入的特征,并自动静态地调用使用boot{TraitNameHere}命名约定的方法。这证明模型中的特征不参与 Laravel 的依赖注入周期。
为了实现这一点,您可以使用 Laravel 全局帮助程序加载容器内存储的实例,例如 Facade App::make(DefinedKeyHere)。然后将分配的实例存储到静态属性中,使其保留到运行时结束,并且因为调用方法是static.
trait TimezoneTrait
{
protected static $userRepository;
protected static function bootTimezoneTrait()
{
static::$userRepository = \App::make(UserRepositoryInterface::class);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您当前正在尝试避免使用全局帮助程序,那么侦听模型启动事件也很有帮助。EventServiceProvider 内的示例,
Event::listen('eloquent.booting:*', function (Model $model) {
$model->setUserRepository($this->app[UserRepositoryInterface::class]);
});
Run Code Online (Sandbox Code Playgroud)
那么特征就是,
trait TimezoneTrait
{
protected static $userRepository;
public function static setUserRepository(UserRepositoryInterface $userRepository)
{
static::$userRepository = $userRepository;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意我将其定义setUserRepository为静态,但您也可以将其设置为非静态。
为了扩展一下模型事件,模型在执行相关操作时会触发几个事件。
Laravel 5.5 中的示例事件,
public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
Run Code Online (Sandbox Code Playgroud)
实例化(也未序列化)时触发的其他两个默认事件是booting和booted。以及用于触发事件的方法,请注意事件名称。
protected function fireModelEvent($event, $halt = true)
{
// ...
return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
}
Run Code Online (Sandbox Code Playgroud)