Lzh on GitHub

警告:找不到所需的 @OA\Info()

随着在版本 4 中增加对 PHP 属性 的支持,必须进行一些架构更改。

其中一项更改是,在源文件中放置注解现在受到与属性相同的限制。这些限制由 PHP 反射 API 决定,特别是它提供对属性和 doc 注释的访问位置。

这意味着独立的注解不再受支持,并被忽略,因为 swagger-php 无法再 “看到” 它们。

支持的位置:

  • 类 (class)
  • 接口 (interface)
  • 特性 (trait)
  • 方法 (method)
  • 属性 (property)
  • 类/接口常量 (class/interface const)

最常见的情况是,会出现一个关于找不到所需 @OA\Info 的警告。虽然大多数注解都与特定的代码相关,但 info 注解(以及其他几个)有点像全局的。

避免此问题的最简单解决方案是向 docblock 添加一个“虚拟”类,并将所有“全局”注解(例如 TagServerSecurityScheme 等)放在一个单独的 docblock 中添加到该类上。

<?php

use OpenApi\Attributes as OA;

#[OA\Tag(name: 'user', description: 'User related operations')]
#[OA\Info(
    version: '1.0',
    title: 'Example API',
    description: 'Example info',
    contact: new OA\Contact(name: 'Swagger API Team'),
)]
#[OA\Server(
    url: 'https://example.localhost',
    description: 'API server',
)]
class OpenApiSpec
{
}

从版本 4.8 开始,doctrine/annotations 库是可选的,这可能会导致出现相同的消息。

如果是这种情况,doctrine annotations 必须单独安装:

composer require doctrine/annotations

注解缺失

使用反射的另一个副作用是 swagger-php 不再能 “看到” 多个连续的 docblock,因为 PHP 反射 API 只提供对最靠近给定结构化元素的 docblock 的访问。

class Controller
{
    /**
     * @OA\Delete(
     *      path="/api/v0.0.2/notifications/{id}",
     *      operationId="deleteNotificationById",
     *      summary="Delete notification by ID",
     *      @OA\Parameter(name="id", in="path", @OA\Schema(type="integer")),
     *      @OA\Response(response=200, description="OK"),
     *      @OA\Response(response=400, description="Bad Request")
     * )
     */
    /**
     * Delete notification by ID.
     *
     * @param Request $request
     * @param AppNotification $notification
     *
     * @return Response
     * @throws Exception
     */
    public function destroy(Request $request, AppNotification $notification) {
        //
    }
}

在这种情况下,最简单的解决方案是合并两个 docblock。这样做还有一个额外的好处,可以避免摘要的重复。

在这个改进版本中,swagger-php 会自动使用 docblock 摘要,就像上面显式地做的那样。

class Controller
{
    /**
     * @OA\Delete(
     *      path="/api/v0.0.2/notifications/{id}",
     *      operationId="deleteNotificationById",
     *      summary="Delete notification by ID",
     *      @OA\Parameter(name="id", in="path", @OA\Schema(type="integer")),
     *      @OA\Response(response=200, description="OK"),
     *      @OA\Response(response=400, description="Bad Request")
     * )
     */
    /**
     * Delete notification by ID.
     *
     * @param Request $request
     * @param AppNotification $notification
     *
     * @return Response
     * @throws Exception
     */
    public function destroy(Request $request, AppNotification $notification) {
        //
    }
}

生成的规范结果:

openapi: 3.0.0
paths:
  '/api/v0.0.2/notifications/{id}':
    delete:
      summary: 'XDelete notification by ID.'
      operationId: deleteNotificationById
      parameters:
        -
          name: id
          in: path
          schema:
            type: integer
      responses:
        '200':
          description: OK
        '400':
          description: 'Bad Request'

跳过未知的 \SomeClass

这条消息意味着 swagger-php 试图使用反射来检查 \SomeClass,但 PHP 找不到/加载该类。实际上,这意味着 class_exists("\SomeClass") 返回 false

使用 -b --bootstrap 选项

这种情况可能由多种原因导致。如果你是从全局安装中运行 openapi 命令行工具,通常应用程序的类加载器(composer)并未激活。如果你的应用根目录是 myapp,你可以尝试:

openapi -b myapp/vendor/autoload.php myapp/src

-b 选项允许执行一些额外的 PHP 代码来加载所需的内容,以便向 PHP 注册你的应用的类加载器。

这类错误的常见情况之一是尝试在独立的单个文件中使用注解。通常,这意味着它不会使用命名空间或遵循任何其他自动加载标准。
在这种情况下,-b 选项也可以用来自动加载实际文件。
请注意,你仍然需要将该文件(或其文件夹)作为目标提供。
openapi -b src/test.php src/test.php

命名空间不匹配

导致此错误的另一个原因可能是你的类实际上使用了错误的命名空间(或者根本没有命名空间!)。

根据你的框架,这在你的应用上下文中可能仍然有效,但单独的 composer 自动加载器可能无法加载你的类(假设你正在使用 composer)。

openapi 命令行工具没有输出

根据你的 PHP 配置,运行 openapi 命令行工具可能完全没有任何输出。

原因是 openapi 目前使用 error_log 函数进行所有输出。

因此,如果 error_log 被配置为写入文件,那么命令看起来就像是坏了一样。