Доступ к контейнеру или securityContext или EntityManager из MenuBuilder через RequestVoter

Я нашел этот фрагмент кода в Gist (где-то я потерял ссылку), и мне нужно что-то подобное, поэтому я начал использовать в своем приложении, но я еще не полностью понял, и поэтому у меня возникли некоторые проблемы.

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

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

Я рендеринг меню, хотя RequestVoter (Я думаю) и это код:

namespace PlantillaBundle\Menu;

use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\Voter\VoterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;

class RequestVoter implements VoterInterface {

private $container;

private $securityContext;

public function __construct(ContainerInterface $container, SecurityContextInterface $securityContext)
{
$this->container = $container;
$this->securityContext = $securityContext;
}

public function matchItem(ItemInterface $item)
{
if ($item->getUri() === $this->container->get('request')->getRequestUri())
{
// URL's completely match
return true;
}
else if ($item->getUri() !== $this->container->get('request')->getBaseUrl() . '/' && (substr($this->container->get('request')->getRequestUri(), 0, strlen($item->getUri())) === $item->getUri()))
{
// URL isn't just "/" and the first part of the URL match
return true;
}
return null;
}

}

Весь код, связанный с securityContext был добавлен мной в попытке работать с ним из menuBuilder, Теперь это код, где я делаю меню:

namespace PlantillaBundle\Menu;

use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;

class MenuBuilder extends ContainerAware {

public function mainMenu(FactoryInterface $factory, array $options)
{
// and here is where I need to access securityContext
// and in the near future EntityManger

$user = $this->securityContext->getToken()->getUser();
$logged_in = $this->securityContext->isGranted('IS_AUTHENTICATED_FULLY');

$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'nav');

if ($logged_in)
{
$menu->addChild('Home', array('route' => 'home'))->setAttribute('icon', 'fa fa-list');
}
else
{
$menu->addChild('Some Menu');
}

return $menu;
}

}

Но это совершенно неправильно, так как я не прохожу securityContext к методу, и я не знаю, как и я получаю эту ошибку:

Исключение было сгенерировано во время рендеринга шаблона.
(«Примечание: неопределенное свойство:
PlantillaBundle \ Menu \ MenuBuilder :: $ securityContext in
/var/www/html/src/PlantillaBundle/Menu/MenuBuilder.php строка 12 «) в
/var/www/html/src/PlantillaBundle/Resources/views/menu.html.twig at
строка 2

Избиратель определяется в services.yml следующим образом:

plantilla.menu.voter.request:
class: PlantillaBundle\Menu\RequestVoter
arguments:
- @service_container
- @security.context
tags:
- { name: knp_menu.voter }

Итак, как я ввожу securityContext (Я не буду просить EntityManager, так как я полагаю, будет та же процедура) и доступ к нему из menuBuilder?

Обновление: рефакторинг кода

Итак, после предложения @Cerad я внес эти изменения:

services.yml

services:
plantilla.menu_builder:
class: PlantillaBundle\Menu\MenuBuilder
arguments: ["@knp_menu.factory", "@security.context"]

plantilla.frontend_menu_builder:
class: Knp\Menu\MenuItem # the service definition requires setting the class
factory_service: plantilla.menu_builder
factory_method: createMainMenu
arguments: ["@request_stack"]
tags:
- { name: knp_menu.menu, alias: frontend_menu }

MenuBuilder.php

namespace PlantillaBundle\Menu;

use Knp\Menu\FactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class MenuBuilder {

/**
* @var Symfony\Component\Form\FormFactory $factory
*/
private $factory;

/**
* @var Symfony\Component\Security\Core\SecurityContext $securityContext
*/
private $securityContext;

/**
* @param FactoryInterface $factory
*/
public function __construct(FactoryInterface $factory, $securityContext)
{
$this->factory = $factory;
$this->securityContext = $securityContext;
}

public function createMainMenu(RequestStack $request)
{
$user = $this->securityContext->getToken()->getUser();
$logged_in = $this->securityContext->isGranted('IS_AUTHENTICATED_FULLY');

$menu = $this->factory->createItem('root');
$menu->setChildrenAttribute('class', 'nav');

if ($logged_in)
{
$menu->addChild('Home', array('route' => 'home'))->setAttribute('icon', 'fa fa-list');
}
else
{
$menu->addChild('Some Menu');
}

return $menu;
}

}

Абд иб мой шаблон просто сделать меню {{ knp_menu_render('frontend_menu') }} но теперь я теряю часть FontAwesome и до того, как она заработает, почему?

0

Решение

Согласно вашему запросу на комментарий, вот как может выглядеть ваш построитель меню:

namespace PlantillaBundle\Menu;

use Knp\Menu\FactoryInterface;

class MenuBuilder {

protected $securityContext;

public function __construct($securityContext)
{
$this->securityContext = $securityContext;
}
public function mainMenu(FactoryInterface $factory, array $options)
{
// and here is where I need to access securityContext
// and in the near future EntityManger

$user = $this->securityContext->getToken()->getUser();
...

// services.yml
plantilla.menu.builder:
class: PlantillaBundle\Menu\MenuBuilder
arguments:
- '@security.context'

// controller
$menuBuilder = $this->container->get('plantilla.menu.builder');

Обратите внимание, что нет необходимости оповещать контейнер компоновщика, поскольку вам нужна только служба контекста безопасности. Конечно, вы также можете ввести менеджер сущностей.

================================

Что касается материала для избирателей, то сейчас вы проверяете только, вошел ли пользователь в систему. Так что в действительности нет необходимости в избирателях. Но предположим, что определенные пользователи (администраторы и т. Д.) Имели доступ к дополнительным пунктам меню. Вы можете переместить всю логику проверки безопасности избирателю. Ваш код конструктора меню может выглядеть так:

if ($this->securityContext->isGranted('view','homeMenuItem')
{
$menu->addChild('Home', array('route' ...

Другими словами, вы можете получить более точный контроллер того, кто получает какой пункт меню.

Но сначала запустите ваш MenuBuilder, а затем добавьте материал для избирателей, если это необходимо.

1

Другие решения

Ваш конструктор меню ContainerAware, так что я думаю, что в нем вы должны получить доступ к SecurityContext с помощью $this->getContainer()->get('security.context'),

И вы не предоставили ни одного варианта использования для класса избирателей, так что я предполагаю, что вы не используете matchItem метод.

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

2

По вопросам рекламы [email protected]