Laravel在trait构造函数中传递参数

问题描述 投票:2回答:1

我有一个用于TimezoneTrait模型的User。我也有一个UserRepositoryInterface,通过服务提供商加载,并在所有类中都很好,所以绑定应该没问题:

public function register()
{
    $this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}

public function provides()
{
    return [
        UserRepositoryInterface::class,
    ];
}

现在我遇到的问题是我必须在我的特性中使用该存储库,所以我自然会这样做:

private $userRepository;

public function __construct(UserRepository $userRepository)
{
    $this->userRepository = $userRepository;
}

但转储显示存储库是null。不能将traits注入依赖项吗?

php laravel dependency-injection traits
1个回答
3
投票

在特质中定义__constructor实际上是错误的。或者只是一个糟糕的设计。 Constructors should be specific to a class to which they belong,不是特质。另一个问题是,你在Model类中导入trait,这意味着你应该特别遵循关于a trait in a model is loaded的规则。

在模型的booting阶段,它在类中递归搜索导入的特征,并自动调用静态地使用boot{TraitNameHere}命名约定的方法。这证明模型中的特征不涉及Laravel的依赖注入循环。

为了实现这一点,您可以使用Laravel全局帮助程序在容器内加载存储的实例,例如外观App::make(DefinedKeyHere)。然后将分配的实例存储到静态属性中以使其保留,直到运行时结束,并且因为调用方法是static

trait TimezoneTrait
{
    protected static $userRepository;

    protected static function bootTimezoneTrait()
    {
        static::$userRepository = \App::make(UserRepositoryInterface::class);
    }
}

如果您当前正试图避免使用全局帮助程序,那么监听模型启动事件也很有帮助。 EventServiceProvider中的示例,

Event::listen('eloquent.booting:*', function (Model $model) {
    $model->setUserRepository($this->app[UserRepositoryInterface::class]);
});

然后特征是,

trait TimezoneTrait
{
    protected static $userRepository;

    public function static setUserRepository(UserRepositoryInterface $userRepository)
    {
        static::$userRepository = $userRepository;
    }
}

请注意,我将setUserRepository定义为静态,但您也可以将其定义为非静态。

为了进一步扩展模型事件,模型在执行相关操作时会触发几个事件。

来自Laravel 5.5的示例事件,

public function getObservableEvents()
{
    return array_merge(
        [
            'creating', 'created', 'updating', 'updated',
            'deleting', 'deleted', 'saving', 'saved',
            'restoring', 'restored',
        ],
        $this->observables
    );
}

以及其实例化(也是未序列化的)bootingbooted时触发的其他两个默认事件。以及用于触发事件的方法,请注意事件名称。

protected function fireModelEvent($event, $halt = true)
{
    // ...

    return ! empty($result) ? $result : static::$dispatcher->{$method}(
        "eloquent.{$event}: ".static::class, $this
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.