使用自定义服务的编译器传递加载Symfony的参数

Mik*_*ase 7 php parameters symfony

根据这个问题如何从数据库(Doctrine)加载Symfony的配置参数我有类似的问题.我需要动态设置参数,我想从另一个自定义服务提供数据.

所以,我有事件监听器,它设置当前帐户实体(通过子域或当前登录的用户)

namespace AppBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Doctrine\ORM\EntityManager;
use AppBundle\Manager\AccountManager;

use Palma\UserBundle\Entity\User;

/**
 * Class CurrentAccountListener
 *
 * @package AppBundle\EventListener
 */
class CurrentAccountListener {

    /**
     * @var TokenStorage
     */
    private $tokenStorage;

    /**
     * @var EntityManager
     */
    private $em;

    /**
     * @var AccountManager
     */
    private $accountManager;

    private $baseHost;

    public function __construct(TokenStorage $tokenStorage, EntityManager $em, AccountManager $accountManager, $baseHost) {
        $this->tokenStorage = $tokenStorage;
        $this->em = $em;
        $this->accountManager = $accountManager;
        $this->baseHost = $baseHost;
    }

    public function onKernelRequest(GetResponseEvent $event) {
        $request = $event->getRequest();

        $accountManager = $this->accountManager;
        $accountManager->setCurrentAccount( $this->getCurrentAccount($request) );
    }

    private function getCurrentAccount($request){
        if($this->getCurrentAccountByLoggedUser()) {
            return $this->getCurrentAccountByLoggedUser();
        }
        if($this->getCurrentAccountBySubDomain($request) ) {
            return $this->getCurrentAccountBySubDomain($request);
        }
        return;
    }

    private function getCurrentAccountBySubDomain($request) {
        $host = $request->getHost();
        $baseHost = $this->baseHost;

        $subdomain = str_replace('.'.$baseHost, '', $host);

        $account = $this->em->getRepository('AppBundle:Account')
                ->findOneBy([ 'urlName' => $subdomain ]);

        if(!$account) return;

        return $account;
    }

    private function getCurrentAccountByLoggedUser() {
        if( is_null($token = $this->tokenStorage->getToken()) ) return;

        $user = $token->getUser();
        return ($user instanceof User) ? $user->getAccount() : null;
    }

}
Run Code Online (Sandbox Code Playgroud)

services.yml

app.eventlistener.current_account_listener:
    class: AppBundle\EventListener\CurrentAccountListener
    arguments:
        - "@security.token_storage"
        - "@doctrine.orm.default_entity_manager"
        - "@app.manager.account_manager"
        - "%base_host%"
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Run Code Online (Sandbox Code Playgroud)

而且非常简单的客户经理只有setter和getter.如果我需要访问当前帐户我打电话

$this->get('app.manager.account_manager')->getCurrentAccount();
Run Code Online (Sandbox Code Playgroud)

一切正常.

现在我正在尝试使用编译器传递从我的服务中设置一些参数

namespace AppBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class ParametersCompilerPass implements CompilerPassInterface {

    const ACCOUNT_MANAGER_SERVICE_ID = 'app.manager.account_manager';

    public function process(ContainerBuilder $container) {

        if(!$container->has(self::ACCOUNT_MANAGER_SERVICE_ID)) {
            return;
        }

        $currentAccount = $container->get(self::ACCOUNT_MANAGER_SERVICE_ID)
            ->getCurrentAccount();

        $container->setParameter(
            'current_account', $currentAccount
        );
    }

}
Run Code Online (Sandbox Code Playgroud)

AppBundle.php

    namespace AppBundle;

    use AppBundle\DependencyInjection\Compiler\ParametersCompilerPass;
    use Symfony\Component\DependencyInjection\Compiler\PassConfig;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\HttpKernel\Bundle\Bundle;

    class AppBundle extends Bundle
    {
        public function build(ContainerBuilder $container)
        {
            parent::build($container);

            $container->addCompilerPass(new ParametersCompilerPass(), PassConfig::TYPE_AFTER_REMOVING);
        }
}
Run Code Online (Sandbox Code Playgroud)

无论我使用什么PassConfig,每次都将current_account设为null.有任何想法吗?

感谢您的关注.

alb*_*ert 1

当您第一次运行 Symfony(CLI 命令或第一个 http 请求)时,会执行编译过程。一旦缓存被构建(编译),这段代码就不会再被执行。

带参数的解决方案[我不推荐这个]

如果您的参数可以从一个 HTTP 请求更改为另一个 HTTP 请求,则不应使用参数,因为某些服务可能会在您的参数准备好之前初始化,而另一些服务可能会在参数准备好之后初始化。尽管如果这是您想要的方式,您可以添加一个监听内核请求的事件并在那里修改/设置参数。看一下https://symfony.com/doc/current/components/http_kernel.html#component-http-kernel-event-table

用户/会话中的当前帐户

如果currentAccount取决于登录的用户,为什么您不将该信息存储在用户或会话中并从您的服务访问它?