2016-05-20 77 views
2

我有許多控制器操作需要會話中的某些上下文,以便它們可以執行。如果不滿足要求,重定向

/** 
* @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類,我該怎麼做呢?
還是會有另一種知道的方式?

回答

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

注:使用定製標註處理,它可能是你需要清除緩存經常能看到的變化。

+0

哇!你應該提交一個公關與這個答案作爲新的食譜:)謝謝你這個質量的答案。 –

0

您可以實現自己的註釋並將您的邏輯放入kernel.request事件偵聽器中。

註釋功能不會變成Symfony,它來源於教義。首先需要在您的包中添加新註釋類

<?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

+2

儘管此鏈接可能回答問題,但最好在此處包含答案的基本部分,並提供供參考的鏈接。如果鏈接頁面更改,僅鏈接答案可能會失效,導致您的答案無用,從而被刪除。 –

+0

我實際上是在這個鏈接試圖瞭解我如何能夠做到我正在尋找它。雖然我並沒有真正瞭解如何在示例中將'Permission'鏈接到'AnnotationDriver'。 –

+0

我修改了我的評論。 Doctrine註解驅動程序從方法/類解析註釋和映射註釋以更正描述註釋的類 –