2017-11-15 7 views
6

Zgodnie z tym pytaniem How to load Symfony's config parameters from database (Doctrine) Mam podobny problem. Muszę ustawić parametr dynamicznie i chcę dostarczyć dane z innej niestandardowej usługi.Załaduj parametr Symfony z przepustką kompilatora z usługi niestandardowej

Tak, mam detektora zdarzeń, które ustawienie podmiot rachunku bieżącym (o subdomenie lub aktualnie zalogowanego użytkownika)

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

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 } 

A bardzo prosto Account Manager z seter i tylko getter. Jeśli potrzebuję dostępu do rachunku bieżącego, zadzwonię pod numer

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

Wszystko działa poprawnie.

Teraz próbuję ustawić jakiś parametr z moich usług z kompilatora przejściu

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

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

dostałem current_account jak zerową za każdym razem, bez względu na to, co PassConfig używam . Jakieś pomysły?

Dziękuję za uwagę.

Odpowiedz

1

Przepustka kompilacji jest wykonywana po uruchomieniu Symfony po raz pierwszy (komenda CLI lub pierwsze żądanie http). Po zbudowaniu (skompilowaniu) pamięci podręcznej ten kod nigdy nie zostanie ponownie wykonany.

Rozwiązanie z parametrami [Nie polecam tego]

Jeśli parametr może zmieniać się od jednego do drugiego żądania HTTP nie należy używać parametru jak niektóre usługi mogą być inicjowane przed parametrem jest gotowy i inni po. Chociaż w ten sposób chcesz iść, możesz dodać wydarzenie, które nasłuchuje na żądanie jądra i zmodyfikuj/ustaw tam parametr. Wystarczy popatrzeć na https://symfony.com/doc/current/components/http_kernel.html#component-http-kernel-event-table

rachunku bieżącym na użytkownika/sesji

Jeśli currentAccount zależy od zalogowanego użytkownika, dlaczego nie przechowywać te informacje w użytkownika lub sesji i dostępu do niego z twoich usług?