php-openapi/yii2-openapi

从OpenAPI 3规范生成完整的REST API应用程序。

2.0-beta2 2023-01-05 13:21 UTC

README

Yii2的REST API应用程序生成器,支持openapi 3.0 YAML -> Yii2。

基于Gii,Yii框架代码生成器

Latest Stable Version Latest Alpha Version Total Downloads License yii2-openapi

TLDR;这是什么?

一个基于OpenAPI和Yii框架的PHP API应用程序的代码生成器。

输入:OpenAPI 3.0 YAML或JSON(通过cebe/php-openapi

输出:带有控制器、模型和数据库模式的Yii框架应用程序

功能

当前可用功能

  • 生成路径映射、控制器和动作以供API端点使用。CRUD端点是可用的,其他端点是生成的抽象函数,需要实现
  • 根据OpenAPI模式生成模型和验证
  • 从OpenAPI模式生成数据库模式
  • 生成模式更改的数据库迁移
  • 通过Faker提供模拟数据以供开发使用

要求

  • PHP 7.1或更高版本(与PHP 8兼容良好)

安装

composer require php-openapi/yii2-openapi:^2.0@beta

使用

您可以将此软件包用于现有应用程序,或使用yii2-app-api应用程序模板启动新项目。有关模板的使用说明,请参阅模板存储库的README。

在现有Yii应用程序配置中(适用于控制台和Web)

<?php
$config = [
    // ... this is your application config ...
];

if (YII_ENV_DEV) {
    // enable Gii module
    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => \yii\gii\Module::class,
        'generators' => [
            // add ApiGenerator to Gii module
            'api' => \cebe\yii2openapi\generator\ApiGenerator::class,

            // --------- OR ---------
            // to disable generation of migrations files or with default config change
            'api' => [
              'class' => \cebe\yii2openapi\generator\ApiGenerator::class,
              'generateMigrations' => false, # this config can also be applied in CLI command
            ],
        ],
    ];
}

return $config;

要使用Web生成器,请打开index.php?r=gii并选择REST API Generator

在控制台中,您可以使用./yii gii/api --openApiPath=@app/openapi.yaml运行生成器。其中@app/openapi.yaml应该是您的OpenAPI规范文件的绝对路径。这可以是JSON,也可以是YAML(有关支持的格式,请参阅php-openapi/php-openapi)。

运行./yii gii/api --help查看所有选项。例如:禁用迁移文件的生成./yii gii/api --generateMigrations=0

有关示例OpenAPI规范,请参阅Petstore示例

OpenAPI扩展

此库理解以下OpenAPI规范的扩展

x-faker

您可以为属性指定用于生成假数据的自定义PHP代码

    Post:
      properties:
        id:
          type: integer
        tags:
          type: array
          items:
            type: string
          example: ['one', 'two']
          x-faker: "$faker->randomElements(['one', 'two', 'three', 'four'])"

要避免为特定的模型属性生成faker代码,请使用值false

    Post:
      properties:
        age:
          type: integer
          x-faker: false

allOf一起使用

    Invoice:
      type: object
      required:
        - id
      properties:
        id:
          type: integer

    Order:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
        invoice:
          allOf:
            - $ref: '#/components/schemas/Invoice'
            - x-faker: false

x-table

指定定义存储在数据库中的模型的Schema的表名。您可以根据\yii\base\Model生成非数据库模型,而不生成迁移,通过设置x-table: false

x-pk

显式指定与“id”不同的表的主键名称

    Post:
      x-table: posts
      x-pk: uid
      properties:
        uid:
           type: integer
        title:
           type: string

x-db-type

显式指定列的数据库类型。(必须只包含真实的DB类型! (jsonjsonbuuidvarchar等.))。如果将x-db-type设置为false,则属性将作为虚拟属性处理;它将作为公共属性添加到模型中,但将跳过迁移的生成。

x-db-type的示例值:

  • false(布尔值假)
  • 作为字符串,其值可以是以下内容:
    • text
    • text[]
    • INTEGER PRIMARY KEY AUTO_INCREMENT
    • decimal(12,4)
    • json
    • varchar
    • VARCHAR
    • SMALLINT UNSIGNED ZEROFILL
    • MEDIUMINT(10) UNSIGNED ZEROFILL COMMENT "comment"(注意这里的双引号)

不允许使用以下值

  • int null default null after low_price(null 和 default 将分别由 nullabledefault 键处理)
  • MEDIUMINT(10) UNSIGNED ZEROFILL NULL DEFAULT '7' COMMENT 'comment' AFTER seti,ADD INDEX t (w)

如果同时提供了 enumx-db-type,则在数据库列模式(迁移)中,只考虑 x-db-type,忽略 enum

x-indexes

指定表索引

    Post:
      x-table: posts
      x-indexes:
          - 'visible,publish_date'
          - 'unique:title' #for unique attributes also unique validation check will be added
          - 'gist:metadata' #for postgres will generate index using GIST index type
      properties:
        id:
           type: integer
           x-db-type: INTEGER PRIMARY KEY AUTO_INCREMENT
        title:
           type: string
        visible:
            type: boolean
        publish_date:
            type: string
            format: date
        metadata:
           type: object
           x-db-type: JSON
           default: '{}' 

x-db-default-expression

能够通过数据库表达式提供默认值

created_at:
  readOnly: true
  type: string
  format: datetime
  x-db-type: datetime
  nullable: false
  x-db-default-expression: current_timestamp()

注意:如果同时存在 defaultx-db-default-expression,则考虑 default

created_at:
  readOnly: true
  type: string
  format: datetime
  x-db-type: datetime
  nullable: false
  x-db-default-expression: current_timestamp() # this will be ignored
  default: "2011-11-11" # this will be considered

另请参阅:https://dev.mysqlserver.cn/doc/refman/8.0/en/data-type-defaults.html

x-fk-on-delete

允许在迁移中设置数据库表中行 ON DELETE 事件的 foreign key 约束。例如

  components:
    schemas:
      User:
        type: object
        description: x on-x (update|delete) foreign key constraint
        properties:
          id:
            type: integer
          name:
            type: string
      Post:
        type: object
        description: x on-x (update|delete) foreign key constraint
        properties:
          id:
            type: integer
          title:
            type: string
          user:
            allOf:
              - $ref: '#/components/schemas/User'
              - x-fk-on-update: CASCADE
          user_2:
            allOf:
              - $ref: '#/components/schemas/User'
              - x-fk-on-update: CASCADE
              - x-fk-on-delete: SET NULL
          user_3:
            allOf:
              - $ref: '#/components/schemas/User'
              - x-fk-on-delete: SET NULL
          user_4:
            $ref: '#/components/schemas/User' # without any constraints

x-fk-on-update

允许在迁移中设置数据库表中行 ON UPDATE 事件的 foreign key 约束。例如,请参阅上述 x-fk-on-delete 部分。

x-fk-column-name

在关系列的情况下提供自定义数据库表列名。这不会反映在模型关系、faker 等。

  components:
    schemas:
      Webhook:
        type: object
        description: example for x-fk-column-name
        properties:
          id:
            type: integer
          name:
            type: string
          user:
            $ref: '../openapi.yaml#/components/schemas/User' # this will automatically create `user_id` column
          redelivery_of:
            allOf:
              - $ref: '../openapi.yaml#/components/schemas/Delivery'
              # this will automatically create `redelivery_of_id` column, but to avoid that use below extension
              - x-fk-column-name: redelivery_of # this will create `redelivery_of` column instead of `redelivery_of_id`

多对多关系定义

定义多对多关系有两种方式

简单多对多(无连接模型)

  • 多对多关系的属性名称应与复数化的小写相关模式名称相等

  • 引用模式应包含对当前模式的镜像引用

  • 连接表的迁移可以自动生成 - 表名应为 [复数化,小写 schema_name1]2[复数化,小写 schema_name2],按字母顺序;例如,对于模式 Post 和 Tag - 表应为 posts2tags,对于模式 Post 和 Attachement - 表应为 attachments2posts

Post:
  properties:
  ...
    tags:
      type: array
      items:
        $ref: '#/components/schemas/Tag'

Tag:
  properties:
  ...
    posts:
      type: array
      items:
        $ref: '#/components/schemas/Post'

多对多(有连接模型)

这种方式允许在两个模型之间创建多个多对多关系

  • 定义具有所有必要属性的连接模式。只有一个重要要求 - 连接模式名称必须以前缀 'junction_' 开始(此前缀仅用于内部使用,在表和模型生成之前将被删除)
# Model TeamMembers with table team_members will be generated with columns team_id, user_id and role
junction_TeamMembers:
   team:
      $ref: '#/components/schemas/Team'
   user:
      $ref: '#/components/schemas/User'
   role:
     type: string
  • 两个多对多相关模式都必须具有引用 "junction_*" 模式的属性。这些属性将用作关系名称
Team:
  properties:
  ...
     team_members:
       type: array
       items:
         $ref: '#/components/schemas/junction_TeamMembers'

User:
  properties:
  ...
    memberships: #You absolutely free with naming for relationship attributes
      type: array
      items:
        $ref: '#/components/schemas/junction_TeamMembers'

NOT NULL 约束的处理

数据库迁移中的 NOT NULL 由 OpenAPI 模式的 nullablerequired 属性确定。例如,属性 = 'my_property'。

  • 如果您没有通过 "required" 或 "nullable" 定义属性,则它默认为 NULL
  ExampleSchema:
    properties:
      my_property:
        type: string
  • 如果您在 "required" 中定义了属性,则它为 NOT NULL
  ExampleSchema:
    required:
     - my_property
    properties:
      my_property:
        type: string
  • 如果您通过 "nullable" 定义了属性,则它覆盖 "required",例如,在这种情况下允许 NULL
  ExampleSchema:
    required:
      - my_property
    properties:
      my_property:
        type: string
        nullable: true
  • 如果您通过 "nullable" 定义了属性,则它覆盖 "required",例如,在这种情况下为 NOT NULL
  test_table:
    required:
    properties:
      my_property:
        type: string
        nullable: false

enum 的处理

它在所有 3 个数据库中工作:MySQL、MariaDb 和 PgSQL。

 test_table:
   properties:
     my_property:
       enum:
         - one
         - two
         - three

注意:枚举值的变化不是很简单。对于 Mysql 和 Mariadb,将生成迁移,但在许多情况下需要对其进行自定义修改。对于 Pgsql,枚举值更改的迁移将不会生成。应手动处理。

如果提供了 x-db-type,则将忽略数据库列模式(迁移)。

numeric 的处理

precision-default = 10 scale-default = 2

  • 您可以将属性定义为 "numeric(precision,scale)"
 test_table:
   properties:
     my_property:
       x-db-type: decimal(12,4)

数据库结果 = decimal(12,4)

  • 您可以定义类似 "numeric(precision)" 的属性,默认缩放默认值为 2
 test_table:
   properties:
     my_property:
       x-db-type: decimal(12)

数据库结果 = decimal(12,2)

  • 您可以定义类似 "numeric" 的属性,精度默认值为 10,缩放默认值为 2
 test_table:
   properties:
     my_property:
       x-db-type: decimal

数据库结果 = decimal(10,2)

处理数据库列数据类型 timestamp

如果字段定义为

created_at:
    type: string
    format: date-time # or datetime
    example: '2020-03-14T21:42:17Z'
    readOnly: true

则选定的数据库类型将是 timestamp。这是设计意图。如果需要 datetime 数据类型,请使用 x-db-type 作为

created_at:
    type: string
    format: date-time # or datetime
    example: '2020-03-14T21:42:17Z'
    x-db-type: datetime
    readOnly: true

假设

在从 OpenAPI 描述生成代码时,有许多可能的方法来实现合适的结果。因此,目前应用了一些假设和限制,以确保其正常工作。以下是一个(可能不完整)的列表

  • 当前的实现最适合遵循 JSON:API 指南的 OpenAPI 描述。
    • 当前未从 OpenAPI 架构中提取请求和响应格式/模式,并且如果它不遵循 JSON:API,则可能需要手动调整。
  • 具有名称 id 的列/字段/属性被视为该库的主键,并且由数据库/Yii 自动处理;因此,请从验证 rules() 中删除它。
    • 其他字段当前可以使用 x-pk OpenAPI 扩展(见下文)作为主键使用,但可能在所有情况下都不正确工作,如果发现任何问题,请报告错误。

其他注意事项

向现有表添加列

在 API 模型中添加新字段时,将生成新迁移以将这些字段添加到表中。对于已经投入生产的项目,应考虑调整生成的迁移以添加现有数据记录的默认值。

这种情况很重要,例如添加具有 NOT NULL 约束的新列,它不提供默认值。此类迁移将在表不为空时失败

$this->addColumn('{{%company}}', 'name', $this->string(128)->notNull());

在 PostgreSQL 数据库上失败

向表 {{%company}} 添加列名称 string(128) NOT NULL ...异常:SQLSTATE[23502]:空值违反:7 错误:列 "name" 包含空值

解决方案是创建列,允许 NULL,设置默认值,然后稍后添加空值约束。

$this->addColumn('{{%company}}', 'name', $this->string(128)->null());
$this->update('{{%company}}', ['name' => 'No name']);
$this->alterColumn('{{%company}}', 'name', $this->string(128)->notNull());

屏幕截图

Gii 生成器表单

Gii Generator Form

生成的文件

Gii Generated Files

开发

要贡献或尝试,请参阅本地设置此项目的步骤 CONTRIBUTING.md

支持

需要帮助您的 API 项目吗?

提供专业支持、咨询以及软件开发服务。

https://www.cebe.cc/en/contact

本库的开发由 cebe.:cloud: "您的专业部署平台" 赞助。