2015-05-24 122 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 configuration for parameter'start'”。

是否有任何方法使注解继承工作,或任何其他解决方案,所以我不必将@QueryParam添加到我的每个控制器?

回答

4

有一个在FosRestBundle对此没有的功能,所以你必须重写您所需要的它的部分,更具体的FOSRestBundle/Request/ParamReader类中的方法getParamsFromMethod(见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\ParamReaderFOS\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-> hasMethod($方法 - > getShortName())){$ = parentMethod $ parentClass-> getMethod ($方法 - > getShortName()); $ parentParams = parent :: getParamsFromMethod($ parentMethod); } return array_merge($ params,$ parentParams); } – Felicitus

+0

我更新了我的答案。 –

0

伟大的解决方案,谢谢!也许有人在symfony3中寻找相同的.yml配置,下面应该可以工作:

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']