使用自定义服务的编译器传递来加载Symfony的参数 [英] Load Symfony's parameter with compiler pass from custom service

查看:74
本文介绍了使用自定义服务的编译器传递来加载Symfony的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据此问题如何从数据库(Doctrine)中加载Symfony的配置参数,我也遇到类似的问题.我需要动态设置参数,并且要从另一个自定义服务中提供数据.

According to this question How to load Symfony's config parameters from database (Doctrine) I have a similar problem. I need to set the parameter dynamically and I want to provide data from another custom service.

因此,我有事件监听器,用于设置当前帐户实体(按子域或当前登录的用户)

So, I have Event Listener which setting current account entity (by sub-domain or currently logged user)

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;
    }

}

services.yml

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 }

非常简单的帐户管理器,仅包含setter和getter.如果我需要访问当前帐户,请致电

And very simply account manager with setter and getter only. If I need access to current account I call

$this->get('app.manager.account_manager')->getCurrentAccount();

一切正常.

现在我正在尝试通过编译器密码从服务中设置一些参数

Now I am trying set some parameter from my service with compiler pass

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
        );
    }

}

AppBundle.php

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);
        }
}

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

I got current_account as null every time, no matter what PassConfig I use. Any ideas?

感谢您的关注.

推荐答案

首次运行Symfony(CLI命令或第一个http请求)时,将执行编译过程.一旦构建(编译)了缓存,该代码就永远不会再次执行.

Compilation pass are executed when you run Symfony for the first time (CLI command or first http request). Once the cache is build (compiled) this code it never gets executed again.

带有参数的解决方案[我不推荐这样做]

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

If your parameter can change from one to another HTTP Request you should not use a parameter as some services may be initialized before your parameter is ready and others after. Although if this is the way you want to go, you can add an event that listens to the kernel request and modify/set the parameter there. Have a look at https://symfony.com/doc/current/components/http_kernel.html#component-http-kernel-event-table

用户/会话中的当前帐户

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

If currentAccount depends on the user logged, why you do not store that info in the user or session and access to it from your services?

这篇关于使用自定义服务的编译器传递来加载Symfony的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆