Я нашел этот фрагмент кода в 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 и до того, как она заработает, почему?
Согласно вашему запросу на комментарий, вот как может выглядеть ваш построитель меню:
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, а затем добавьте материал для избирателей, если это необходимо.
Ваш конструктор меню ContainerAware
, так что я думаю, что в нем вы должны получить доступ к SecurityContext
с помощью $this->getContainer()->get('security.context')
,
И вы не предоставили ни одного варианта использования для класса избирателей, так что я предполагаю, что вы не используете matchItem
метод.
Вы должны определенно попытаться реструктурировать свои услуги так, чтобы зависимости были очевидны.