php 基于请求的Symfony服务配置

s4chpxco  于 2023-03-07  发布在  PHP
关注(0)|答案(1)|浏览(139)

我有一个配置值,其中我为一个Doctrine事件定义了一个事件侦听器,并且我正在为侦听器中所需的服务使用DI。

$services->set(ExamplePrePersistListener::class)
    ->tag('doctrine.event_listener', ['event' => 'prePersist', 'priority' => 500]);

这个侦听器在http请求期间触发,因此我拥有的依赖项之一是服务(UserBuilder),它从会话中获取登录用户,但现在我需要在cli请求期间触发同一个侦听器,因此我的想法是重构侦听器,以通过接口获得依赖关系(UserBuilderInterface),这样我就可以定义在不同的请求中发送哪个实现。我将以两个实现HttpUserBuilder,CliUserBuilder结束。
我的问题是我如何告诉Symfony根据请求发送每个实现?我如何在配置文件中设置侦听器,以便能够决定给定的实现?

6uxekuva

6uxekuva1#

正如@Cerad在评论中建议的那样,我决定执行一个简单的if check if ('cli' === PHP_SAPI)来判断我是否从cli运行。虽然这解决了我的依赖性问题,比如我的值对象中的依赖性,但这并没有完全解决Doctrine侦听器问题中提出的问题,但我修改了我的初始想法以适应这一点。
Doctrine侦听器的问题是我不知道在运行时发送哪个依赖项,因此一个选择是在services.php配置文件中检查if(并通过args方法发送),但这样做感觉有点笨拙,主要是因为我想迁移到yaml配置。另一个选项是基于配置值将其设置为setter依赖项(is_cli或类似的东西),但是当从CLI运行时,我需要始终设置这个参数。
所以我使用了当前的UserBuilder,并使用@Cerad提到的服务定位器。无论如何,我使用的是Builder模式,因此构建器类可以决定我是否使用CLI,而不是使用两个单独的构建器类(CliUserBuilder和HttpUserBuilder),然后是第三个位置,它决定发送哪一个。第二个位置可能是更好的关注点分离,但我不想仅仅为了它而添加额外的配置层。
我的UserBuilder类如下所示:

final class UserBuilder implements ServiceSubscriberInterface
{
    use ServiceSubscriberTrait;

    public function build(): User
    {
        if ('cli' === PHP_SAPI) {
            return $this->buildFromCliRequest();
        }

        return $this->buildFromHttpRequest();
    }

    public function buildFromCliRequest(): User
    {
        return $this->createUserRepository()->find(
            $this->createConfig()->getAutomatedUserId()
        );
    }

    public function buildFromHttpRequest(): ?User
    {
        // Get user context from the http request
        // $authContext = $this->createRequestStack()->getCurrentRequest() ...

        return $this->createUserRepository()->find(
            $authContext->getUser()->getId()
        );
    }

    /**
     * @return RequestStack
     */
    #[SubscribedService]
    public function createRequestStack(): RequestStack
    {
        return $this->container->get(__METHOD__);
    }

    /**
     * @return UserRepository
     */
    #[SubscribedService]
    public function createUserRepository(): UserRepository
    {
        return $this->container->get(__METHOD__);
    }

    /**
     * @return Config
     */
    #[SubscribedService]
    public function createConfig(): Config
    {
        return $this->container->get(__METHOD__);
    }
}

据我所知,服务定位器只创建这些依赖项的代理,因此它们在被调用之前不会被示例化,这意味着如果我在CLI中,那么RequestStack永远不会被调用。
这也允许我进行最小的重构,所以我想我可以接受它。

相关问题