我有许多控制器操作需要会话中的某些上下文,以便可以执行它们。
/**
* @Route("/some/route", name="some_route")
*/
public function oneOfMyAction(Request $request)
{
if (!$request->getSession()->get('some_required_variable')) {
$this->redirectToRoute('some_other_route');
}
return $this->render('AppBundle::protected-content.html.twig');
}
有没有办法在注释中对这个要求进行因子分解,或者我可以在控制器中轻松使用它?
/**
* @Route("/some/route", name="some_route")
* @SomeRequiredVariable()
*/
public function oneOfMyAction(Request $request)
{
return $this->render('AppBundle::protected-content.html.twig');
}
如果我可以实施SomeRequiredVariable
课程,我该怎么做?
还是会有另一种明智的方式?
答案 0 :(得分:1)
我总是发现自定义注释的文档有点缺乏。但希望以下内容对您有所帮助。
<强>先决条件强>:
@Annotation
的课程。对于与annotion一起使用的所有参数,这将充当容器。要使其正常工作,您需要将所有属性(可用于自定义注释(此处为route, route_params, required
))定义为类属性。
<?php
// src/AppBundle/Annotation/RedirectOnMissing.php
namespace AppBundle\Annotation;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @Annotation
*/
class RedirectOnMissing
{
/**
* @var string
*/
private $route;
/**
* @var array
*/
private $route_params = [];
/**
* @var array
*/
private $required = [];
/**
* @param array $options
*/
public function __construct(array $options)
{
$options = $this->configureOptions(new OptionsResolver())->resolve($options);
$this->route = $options['route'];
$this->route_params = $options['route_params'];
$this->required = $options['required'];
}
/**
* @param OptionsResolver $resolver
*
* @return OptionsResolver
*/
private function configureOptions(OptionsResolver $resolver)
{
return $resolver
->setRequired(['route', 'required'])
->setDefaults([
'route_params' => []
])
->setAllowedTypes('route', 'string')
->setAllowedTypes('required', 'array')
->setAllowedTypes('route_params', 'array')
;
}
/**
* Get `route`
*
* @return string
*/
public function getRoute()
{
return $this->route;
}
/**
* Get `route_params`
*
* @return array
*/
public function getRouteParams()
{
return $this->route_params;
}
/**
* Get `required`
*
* @return string[]
*/
public function getRequired()
{
return $this->required;
}
}
您需要收听kernel.controller
事件,否则您将无法访问活动控制器。
<?php
// src/AppBundle/EventListener/FilterControllerListener.php
namespace AppBundle\EventListener;
use AppBundle\Annotation\RedirectOnMissing;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation as Http;
class FilterControllerListener
{
/**
* @var Reader
*/
private $reader;
/**
* @var UrlGeneratorInterface
*/
private $urlGenerator;
/**
* @var SessionInterface
*/
private $session;
/**
* @param Reader $reader
* @param UrlGeneratorInterface $urlGenerator
* @param SessionInterface $session
*/
public function __construct(Reader $reader, UrlGeneratorInterface $urlGenerator, SessionInterface $session)
{
$this->reader = $reader;
$this->urlGenerator = $urlGenerator;
$this->session = $session;
}
/**
* @param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if (!is_array($controller)) {
return;
}
/** @var $methodAnnotation RedirectOnMissing */
$methodAnnotation = $this->reader->getMethodAnnotation(
new \ReflectionMethod($controller[0], $controller[1]),
RedirectOnMissing::class
);
if (null !== $methodAnnotation) {
foreach ($methodAnnotation->getRequired() as $key) {
if (!$this->session->has($key)) {
$event->setController(function () use($methodAnnotation) {
return new Http\RedirectResponse($this->urlGenerator->generate($methodAnnotation->getRoute(), $methodAnnotation->getRouteParams()));
});
break;
}
}
}
}
}
// src/AppBundle/Resources/config/services.yml
services:
// ...
app.event_listner.controller_listener:
class: AppBundle\EventListener\FilterControllerListener
arguments:
- "@annotation_reader"
- "@router"
- "@session"
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
<?php
/**
* @Cfg\Route("/test")
*
* @RedirectOnMissing(route="home", required={"foo", "bar"})
*/
public function testAction()
{
return new Http\Response('no redirect');
}
注意:处理自定义注释时,可能需要经常清除缓存以查看更改。
答案 1 :(得分:0)
您可以实现自己的注释,并将您的逻辑放入kernel.request
事件侦听器中。
注释功能不会成为Symfony,它来自Doctrine。首先需要在您的包中添加新的注释类
<?php
namespace Acme\Bundle\TestBundle\Annotation;
/**
* @Annotation
* @Target({"METHOD"})
*/
class Custom
{
}
第二部分是用您的逻辑创建订阅者。
<?php
namespace Acme\Bundle\TestBundle\EventListener;
use Doctrine\Common\Annotations\Reader;
use Acme\Bundle\TestBundle\Annotations\Custom;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CustomEventSubscriber implements EventSubscriberInterface
{
protected $reader;
public function __construct(Reader $reader)
{
$this->reader = $reader;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER => 'onKernelController',
];
}
public function onKernelController(FilterControllerEvent $event)
{
if (!is_array($controller = $event->getController())) {
return;
}
$method = new \ReflectionMethod($controller[0], $controller[1]);
foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
if ($annotation instanceof Custom) {
// put your logic here
}
}
}
}
然后您必须将订户定义为服务。
services:
custom_subscriber:
class: Acme\Bundle\TestBundle\EventListener\CustomEventSubscriber
arguments: [@annotation_reader]
tags:
- {name: kernel.event_subscriber}
之后,您可以使用注释标记控制器的操作。
有关详细信息,请参阅here。