【问题标题】:Symfony - The annotation was never importedSymfony - 从未导入注释
【发布时间】:2016-11-04 07:22:57
【问题描述】:

我正在使用 Symfony 框架,并打算将自动文档引擎添加到我的项目的 RESTful api。

经过一番搜索,我找到了 apidoc 引擎 (http://apidocjs.com/)。它的工作原理非常简单:您必须为 RESTful api 的每个控制器添加一些注释,然后生成文档。

注解的例子是:

/**
 * @Route("/api/dictionary_list/{userId}/{sessionKey}", name="api/dictionary_list")
 * @api {get} /api/dictionary_list/{userId}/{sessionKey} 01. Values list (ids) for all system dictionaries
 * @apiName Dictionary list
 * @apiGroup Dictionary
 *
 * @apiParam {Integer} userId  User's ID received in authorization request
 * @apiParam {String} sessionKey  Session key received in authorization request
 *
 * @apiSuccess {Integer} parcelStatuses  The name of current dictionary
 * @apiSuccess {String} itemId  Item id which used in requests
 * @apiSuccess {String} itemName  Item name
 */

public function dictionaryListAction($userId=null, $sessionKey=null)
{
 ...
}

如您所见,apidoc 的注解与 Symfony 中路由的注解相同。

顺便说一句,在生产环境中它工作正常,但在开发环境中我得到异常,例如

[Semantical Error] The annotation "@apiName" in method AppBundle\Controller\Api\apiDictionaryController::dictionaryListAction() was never imported.

有什么办法可以解决这个问题并向 Symfony 说必须忽略 apidoc 的注释?

【问题讨论】:

标签: php symfony doctrine-orm annotations api-doc


【解决方案1】:

Symfony 使用doctrine/annotations 包来解析注解。当遇到未被列入黑名单的未知注解时,它会抛出异常。

您可以将其他注释列入黑名单,请参阅Doctrine docs - Ignoring missing exceptions

use Doctrine\Common\Annotations\AnnotationReader;

AnnotationReader::addGlobalIgnoredName('api');
AnnotationReader::addGlobalIgnoredName('apiParam');
AnnotationReader::addGlobalIgnoredName('apiGroup');
AnnotationReader::addGlobalIgnoredName('apiSuccess');

我会把它放在 app/autoload.php 中,因为它是一个全局设置。

【讨论】:

  • 谢谢你,但是当我听从你的建议时,我得到了这样的例外:PHP Fatal error: Class 'Doctrine\Common\Annotations\AnnotationReader' not found in /home/alex/Projects/parcel-search/web-app/app/autoload.php on line 7.我错过了什么?
  • 你需要把它放在 require vendor/autoload.php 之后,return 之前。
【解决方案2】:

您可以使用IgnoreAnnotation 注释告诉Docrine 注释阅读器在您的控制器中跳过此注释。为此,只需将注释添加@IgnoreAnnotation("Annotation") 到类的类文档注释即可。

在你的情况下:

/**
 * @IgnoreAnnotation("apiName")
 * @IgnoreAnnotation("apiGroup")
 * @IgnoreAnnotation("apiParam")
 * @IgnoreAnnotation("apiSuccess")
 */
class ActionController extends Controller


/**
 * @Route("/api/dictionary_list/{userId}/{sessionKey}", name="api/dictionary_list")
 * @api {get} /api/dictionary_list/{userId}/{sessionKey} 01. Values list (ids) for all system dictionaries
 * @apiName Dictionary list
 * @apiGroup Dictionary
 *
 * @apiParam {Integer} userId  User's ID received in authorization request
 * @apiParam {String} sessionKey  Session key received in authorization request
 *
 * @apiSuccess {Integer} parcelStatuses  The name of current dictionary
 * @apiSuccess {String} itemId  Item id which used in requests
 * @apiSuccess {String} itemName  Item name
 */

public function dictionaryListAction($userId=null, $sessionKey=null)
{
 ...
}

您还可以考虑为doctrine/annotations 项目打开一个PR,以包含此注释作为默认跳过为this one

希望对您有所帮助。

【讨论】:

    【解决方案3】:

    你必须导入路线:

    使用 Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

    【讨论】:

      【解决方案4】:

      在 DI 容器编译期间会读取注释,因此在 compiler pass 期间忽略 apidocs 注释可能会更好。

      例子:

      <?php
      namespace YourBundle\DependencyInjection;
      
      use Doctrine\Common\Annotations\AnnotationReader;
      use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
      use Symfony\Component\DependencyInjection\ContainerBuilder;
      
      class IgnoreApiDocsAnnotationsPass implements CompilerPassInterface {
          public function process(ContainerBuilder $container) {
              AnnotationReader::addGlobalIgnoredName('api');
              AnnotationReader::addGlobalIgnoredName('apiDefine');
              AnnotationReader::addGlobalIgnoredName('apiDeprecated');
              AnnotationReader::addGlobalIgnoredName('apiDescription');
              AnnotationReader::addGlobalIgnoredName('apiError');
              AnnotationReader::addGlobalIgnoredName('apiErrorExample');
              AnnotationReader::addGlobalIgnoredName('apiExample');
              AnnotationReader::addGlobalIgnoredName('apiGroup');
              AnnotationReader::addGlobalIgnoredName('apiHeader');
              AnnotationReader::addGlobalIgnoredName('apiHeaderExample');
              AnnotationReader::addGlobalIgnoredName('apiIgnore');
              AnnotationReader::addGlobalIgnoredName('apiName');
              AnnotationReader::addGlobalIgnoredName('apiParam');
              AnnotationReader::addGlobalIgnoredName('apiParamExample');
              AnnotationReader::addGlobalIgnoredName('apiPermission');
              AnnotationReader::addGlobalIgnoredName('apiPrivate');
              AnnotationReader::addGlobalIgnoredName('apiSampleRequest');
              AnnotationReader::addGlobalIgnoredName('apiSuccess');
              AnnotationReader::addGlobalIgnoredName('apiSuccessExample');
              AnnotationReader::addGlobalIgnoredName('apiUse');
              AnnotationReader::addGlobalIgnoredName('apiVersion');
          }
      }
      

      我从apidoc docs 获得了完整的注释列表。你需要在你的包中注册编译器传递

      <?php
      namespace YourBundle;
      
      use YourBundle\DependencyInjection\IgnoreApiDocsAnnotationsPass;
      use Symfony\Component\DependencyInjection\ContainerBuilder;
      use Symfony\Component\HttpKernel\Bundle\Bundle;
      
      class YourBundle extends Bundle {
          public function build(ContainerBuilder $container) {
              parent::build($container);
              $container->addCompilerPass(new IgnoreApiDocsAnnotationsPass());
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2020-11-10
        • 1970-01-01
        • 2019-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-26
        • 2019-03-24
        • 2015-02-16
        相关资源
        最近更新 更多