2012-04-03 2 views
37

Я пытаюсь ввести текущего пользователя в службу. Моя цель состоит в том, чтобы расширить некоторые функциональные возможности, чтобы выводить их на основе пользовательских настроек. В этом примере я хочу вывести любую функцию даты, используя пользовательский часовой пояс.Symfony2: вводить текущего пользователя в Сервис

Нет никакого способа вставить текущего пользователя в сервис, что кажется мне очень странным. При вводе контекста безопасности он не имеет токена, даже если пользователь зарегистрирован в

Я использую пакет пользователя FOS.

services: 
    ... 
    twigdate.listener.request: 
     class: App\AppBundle\Services\TwigDateRequestListener 
     arguments: [@twig, @security.context] 
     tags: 
      - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } 


<?php 

namespace App\AppBundle\Services; 

use Symfony\Component\HttpKernel\HttpKernelInterface; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 

class TwigDateRequestListener 
{ 
    protected $twig; 

    function __construct(\Twig_Environment $twig, SecurityContext $context) { 

     $this->twig = $twig; 
     //$this->user = $context->get...; 

     var_dump($context); die; 
    } 

    public function onKernelRequest(GetResponseEvent $event) { 
     // $this->twig->getExtension('core')->setDateFormat($user->getProfile()->getFormat()); 
     // $this->twig->getExtension('core')->setTimeZone($user->getProfile()->getTimezone()); 
    } 
} 

output: 

object(Symfony\Component\Security\Core\SecurityContext)[325] 
    private 'token' => null 
    private 'accessDecisionManager' => 
    object(Symfony\Component\Security\Core\Authorization\AccessDecisionManager)[150] 
     private 'voters' => 
     array 
      0 => 
      object(Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter)[151] 
       ... 
      1 => 
      object(Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter)[153] 
       ... 
      2 => 
      object(Symfony\Component\Security\Acl\Voter\AclVoter)[155] 
       ... 
     private 'strategy' => string 'decideAffirmative' (length=17) 
     private 'allowIfAllAbstainDecisions' => boolean false 
     private 'allowIfEqualGrantedDeniedDecisions' => boolean true 
    private 'authenticationManager' => 
    object(Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager)[324] 
     private 'providers' => 
     array 
      0 => 
      object(Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider)[323] 
       ... 
      1 => 
      object(Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider)[149] 
       ... 
     private 'eraseCredentials' => boolean true 
    private 'alwaysAuthenticate' => boolean false 

Я что-то не хватает?

ответ

41

Я хотел бы использовать расширение прут для этого:

class UserDateExtension extends \Twig_Extension 
{ 
    private $context; 

    public function __construct(SecurityContext $context) 
    { 
     $this->context = $context; 
    } 

    public function getUser() 
    { 
     return $this->context->getToken()->getUser(); 
    } 

    public function getFilters() 
    { 
     return array(
      'user_date' => new \Twig_Filter_Method($this, "formatUserDate"), 
     ); 
    } 

    public function formatUserDate($date, $format) 
    { 
     $user = $this->getUser(); 
     // do stuff 
    } 

Теперь в services.xml

<service id="user_date_twig_extension" class="%user_date_twig_extension.class%"> 
     <tag name="twig.extension" /> 
     <argument type="service" id="security.context" /> 
    </service> 

Тогда в прута вы можете сделать:

{{ date | user_date('d/m/Y') }} 
+0

Спасибо, что работал отлично. Я до сих пор не понимаю, почему мой первый пример не возвращал объект пользователя, но я получил его работу, и я думаю, что расширение Twig на самом деле является более чистым подходом. Спасибо за быстрый ответ – n0xie

+2

Ну, вы слушали событие kernel.request. Установка токена контекста с помощью аутентификации или чтения токена из сеанса выполняется после отправки всех отправителей 'kernel.request'. Если вы прослушали событие 'kernel.response', вы получили бы желаемый токен. Также извините за неправильный вопрос. Это плохой день для меня :). –

+0

Это имеет смысл. Спасибо за объяснение. Вы узнаете что-то каждый день. – n0xie

-9

Вы можете вставить @service_container и сделать $this->container->get('security.context')->getToken()->getUser();.

+26

инъекционного весь контейнер является плохой идеей в большинстве случаев. Вместо этого вы должны вводить каждую услугу, которая вам нужна явно. –

+0

@elnur, скажите, что [FriendsOfSymfony] (https://github.com/FriendsOfSymfony/FOSFacebookBundle/blob/master/Twig/Extension/FacebookExtension.php#L26) :) –

+2

Расширения Twig являются одним из исключений из этого правила , –

4

Пользователь является плохим кандидатом быть сервисом.

  • Во-первых, это модель не сервис
  • Во-вторых есть служба security.context, где вы можете получить от пользователя.

В шаблоне ветки вы можете использовать app.user. См. Symfony doc global-template-variables. Если вы хотите показать что-то, основанное на пользовательских разрешениях, вы можете сделать {{is_granted ('ROLE_USER')}}.

56

Я думаю, что этот вопрос заслуживает обновленного ответа с тех пор, как 2.6.x + с новыми улучшениями компонента безопасности.

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; 

class UserDateExtension extends \Twig_Extension 
{ 
    /** 
    * @var TokenStorage 
    */ 
    protected $tokenStorage; 


    /** 
    * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage $tokenStorage 
    */ 
    public function __construct(TokenStorage $tokenStorage) 
    { 
     $this->tokenStorage = $tokenStorage; 
    } 

    public function getUser() 
    { 
     return $this->tokenStorage->getToken()->getUser(); 
    } 

    public function getFilters() 
    { 
     return array(
      'user_date' => new \Twig_Filter_Method($this, "formatUserDate"), 
     ); 
    } 

    public function formatUserDate($date, $format) 
    { 
     $user = $this->getUser(); 
     // do stuff 
    } 
} 

Services.yml

twig.date_extension: 
    class: Acme\Twig\SpecialDateExtension 
    tags: 
     - { name: twig.extension } 
    arguments: 
     - "@security.token_storage" 
1

Я рекомендовал бы связывать различные события, если вы используете событие kernel.controller, вы будете иметь маркер и не имеют никаких проблем. Маркер не доступен в kernel.request так Symfony 2.3

Я написал руководство о том, как реализовать TimeZones пользователя для Symfony 2.3+ и 2.6+ в Twig на моем блоге под названием Symfony 2.6+ User Timezones.

Это значительно превосходит использование удлинителя Twig, поскольку вы можете использовать стандартные функции форматирования даты в Twig, а также предоставлять отдельную временную дату UTC, стандартные временные интервалы даты Twig и пользовательские временные метки даты Twig.

Вот наиболее важный отрывок:

SRC/AppBundle/EventListener/TwigSubscriber.PHP

<?php 

namespace AppBundle\EventListener; 

use AppBundle\Entity\User; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpKernel\Event\FilterControllerEvent; 
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 

class TwigSubscriber implements EventSubscriberInterface 
{ 
    protected $twig; 
    protected $tokenStorage; 

    function __construct(\Twig_Environment $twig, TokenStorageInterface $tokenStorage) 
    { 
     $this->twig = $twig; 
     $this->tokenStorage = $tokenStorage; 
    } 

    public static function getSubscribedEvents() 
    { 
     return [ 
      'kernel.controller' => 'onKernelController' 
     ]; 
    } 

    public function onKernelController(FilterControllerEvent $event) 
    { 
     $token = $this->tokenStorage->getToken(); 

     if ($token !== null) { 
      $user = $token->getUser(); 

      if ($user instanceof User) { 
       $timezone = $user->getTimezone(); 
       if ($timezone !== null) { 
        $this->twig->getExtension('core')->setTimezone($timezone); 
       } 
      } 
     } 
    } 
} 

Теперь вы можете использовать веточку, как обычно, и он использует свои предпочтения пользователя, если доступно.

29

services.yml

my_service: 
    class: ... 
    arguments: 
     - "@=service('security.token_storage').getToken().getUser()" 

Service.php

protected $currentUser; 

public function __construct($user) 
{ 
    $this->currentUser = $user; 
} 

http://symfony.com/doc/current/book/service_container.html#using-the-expression-language

+2

Это лучший ответ в 2016 для Symfony 2.6 и выше – 10us

+10

Работает ли это за пределами брандмауэра безопасности? Я имею в виду, он возвращает «null» или генерирует исключение, потому что getToken() возвращает null и -> getUser() не может применяться к нулевому объекту? –

+1

Прекрасно работает для Symfony 3.2 – Londeren

2

От Symfony 2.6.

Вам нужно использовать @ security.token_storage

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 

class UserDateExtension extends \Twig_Extension 
{ 
/** 
* @var TokenStorageInterface 
*/ 
protected $tokenStorage; 


/** 
* @param $tokenStorage TokenStorage 
*/ 
public function __construct(TokenStorage $tokenStorage) 
{ 
    $this->tokenStorage = $tokenStorage; 
} 

public function getUser() 
{ 
    return $this->tokenStorage->getToken()->getUser(); 
} 

public function getFilters() 
{ 
    return array(
     'user_date' => new \Twig_Filter_Method($this, "formatUserDate"), 
    ); 
} 

public function formatUserDate($date, $format) 
{ 
    $user = $this->getUser(); 
    // do stuff 
} 

}

И Services.yml

twig.date_extension: 
    class: Acme\Twig\SpecialDateExtension 
    tags: 
     - { name: twig.extension } 
    arguments: ["@security.token_storage"] 

эталонные: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements

 Смежные вопросы

  • Нет связанных вопросов^_^