2015-05-24 2 views
4

В моем проекте у меня есть класс BaseController, который реализует несколько методов, используемых всеми моими контроллерами.Symfony2 Наследование Аннотации

Теперь я хотел добавить @QueryParam для этого базового класса. Мой класс выглядит следующим образом:

class DoctrineRESTQueryController extends FOSRestController 
{ 
    /** 
    * @QueryParam(name="start",default=0) 
    * @QueryParam(name="limit",default=null) 
    */ 
    public function getQueryResponseAction (ParamFetcher $paramFetcher) { 

    } 
} 

Теперь у меня есть фактический контроллер, который простирается от моего базового контроллера:

class DefaultController extends DoctrineRESTQueryController { 

    /** 
    * Retrieves all SI Prefixes in the database 
    * 
    * @Routing\Route("/siprefix", defaults={"method" = "get","_format" = "json"}) 
    * @Routing\Method({"GET"}) 
    * @ApiDoc(output="array<PartKeepr\SiPrefixBundle\Entity\SiPrefix>") 
    * 
    * @View() 
    * 
    * {@inheritdoc} 
    */ 
    public function getQueryResponseAction(ParamFetcher $paramFetcher) { 
     $paramFetcher->get("start"); 
    } 
} 

К сожалению, Symfony2, кажется, не наследует @QueryParam аннотаций от суперкласса, потому что вызов $ paramFetcher-> get («start») приводит к исключению «No @ QueryParam/@ RequestParam конфигурации для параметра« start »».

Есть ли способ сделать работу наследования аннотаций или любое другое решение, поэтому мне не нужно добавлять @QueryParam для каждого из моих контроллеров?

ответ

4

Там нет особенности FosRestBundle для этого, так что вы должны переопределить ее части для того, что вам нужно, более конкретно метода getParamsFromMethod в классе FOSRestBundle/Request/ParamReader (см source code here).

Это можно сделать путем наследования пучков.

Во-первых, подкласс FOSRestBundle\Request\ParamReader в одном из ваших комплектов, например. YourSite\RestBundle\Request\MyParamReader и переопределить getParamsFromMethod пути загрузки аннотаций родительского метода и слияния их с теми текущим:

namespace YourSite\RestBundle\Request\MyParamReader; 

use FOSRestBundle\Request\ParamReader; 

class MyParamReader extends ParamReader 
{ 
    public function getParamsFromMethod(\ReflectionMethod $method) 
    { 
     $parentParams = array(); 
     $params = parent::getParamsFromMethod($method); 

     // This loads the annotations of the parent method 
     $declaringClass = $method->getDeclaringClass(); 
     $parentClass = $declaringClass->getParentClass(); 

     if ($parentClass && $parentClass->hasMethod($method->getShortName())) { 
      $parentMethod = $parentClass->getMethod($method->getShortName()); 
      $parentParams = parent::getParamsFromMethod($parentMethod); 
     } 

     return array_merge($params, $parentParams); 
    } 
} 

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

Теперь вы должны сообщить FOSRestBundle, чтобы использовать ваш класс YourSite\RestBundle\Request\MyParamReader вместо FOSRestBundle\Request\ParamReader. Вам необходимо переопределить определение службы, где читатель параметров указан как зависимость. Это то, где вступает в игру перехват/наследование пучка, см. this Symfony2 article.

Определение службы находится в файле Resources/config/request.xml (см source code here), FOSRestBundle\Request\ParamReader является зависимость FOS\RestBundle\Request\ParamFetcher.

Поэтому вы должны переопределить файл Resources/config/request.xml. Для этого, после вышеупомянутой статьи, зарегистрировать пакет и объявить FOSRestBundle в качестве родителя:

namespace YourSite\RestBundle; 

use Symfony\Component\HttpKernel\Bundle\Bundle; 

class YourSiteRestBundle extends Bundle 
{ 
    public function getParent() 
    { 
      return 'FOSRestBundle'; 
    } 
} 

Создать файл YourSite\RestBundle\Resources\config\request.xml добавить YourSite\RestBundle\Request\MyParamReader как зависимость:

<?xml version="1.0" ?> 
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> 
    <parameters> 
     <parameter key="fos_rest.request.param_fetcher.class">FOS\RestBundle\Request\ParamFetcher</parameter> 
     <parameter key="your_site_rest.request.param_fetcher.reader.class">YourSite\RestBundle\Request\MyParamReader</parameter> 
    </parameters> 
    <services> 
     <service id="fos_rest.request.param_fetcher" class="%fos_rest.request.param_fetcher.class%" scope="request"> 
      <argument type="service" id="your_site.request.param_fetcher.reader"/> 
      <argument type="service" id="request"/> 
      <argument type="service" id="fos_rest.violation_formatter"/> 
      <argument type="service" id="validator" on-invalid="null"/> 
     </service> 
     <service id="your_site.request.param_fetcher.reader" class="%your_site_rest.request.param_fetcher.reader.class%"> 
      <argument type="service" id="annotation_reader"/> 
     </service> 
    </services> 
</container> 

Это проверялось, но он должен Работа.

+0

Удивительно!Один маленький багфикс: Обычай читатель должен проверить, если родительский метод на самом деле существует: если ($ ParentClass && $ parentClass-> hasMethod ($ ме-> getShortName())) {$ parentMethod = $ parentClass-> getMethod ($ ме-> getShortName()); $ parentParams = parent :: getParamsFromMethod ($ parentMethod); } return array_merge ($ params, $ parentParams); } – Felicitus

+0

Я обновил свой ответ. –

0

Отличное решение, спасибо! Возможно, кто-то ищет такую ​​же конфигурацию .yml в symfony3, должно работать следующее:

parameters: 
    fos_rest.request.param_fetcher.class: FOS\RestBundle\Request\ParamFetcher 
    your_site_rest.request.param_fetcher.reader.class: YourSiteBundle\Request\MyParamReader 

services: 
    fos_rest.request.param_fetcher: 
     class: %fos_rest.request.param_fetcher.class% 
     arguments: ['@service_container', '@your_site.request.param_fetcher.reader', '@request_stack', '@?validator'] 
     scope: request 
    your_site.request.param_fetcher.reader: 
     class: %your_site.request.param_fetcher.reader.class% 
     arguments: ['@annotation_reader'] 
Смежные вопросы