php - Laravel 在特征构造函数中传递参数

标签 php laravel dependency-injection traits

我有一个 TimezoneTrait 用于 User 模型。我还有一个 UserRepositoryInterface,它通过服务提供商加载并且适用于所有类,因此绑定(bind)应该没问题:

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。特征不能注入(inject)依赖吗?

最佳答案

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

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

要实现这一点,您可以使用 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
    );
}

关于php - Laravel 在特征构造函数中传递参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47885690/

相关文章:

node.js - NodeJS Express 依赖注入(inject)和数据库连接

laravel - 如何在 laravel 中插入多类别和多列不同类别的帖子?

c# - Web API 请求后需要记录 EF DbContext 的 CaSTLe Windsor 生活方式

php - 如果 SQL 语句有效,则重定向到 URL - ASP.NET 与 PHP

php - 检测是否从 Laravel 5 中的命令行运行

javascript - 在 Laravel 中不使用 if 语句过滤数据库

php - 查看 Swagger API 文档

c# - 在 Azure 函数 V2 上注册第 3 方 DI 框架 (Lamar/Autofac) 的正确方法

javascript - 如何从带有 2 个按钮的表单单击按钮发送 Ajax 请求?

php mysql 时间预订