wol-soft/php-json-schema-model-generator

从JSON-Schema文件创建(不可变)PHP模型类,包括所有验证规则作为PHP代码

0.25.0 2024-09-19 15:33 UTC

README

Latest Version Minimum PHP Version Maintainability Build Status Coverage Status MIT License Documentation Status

php-json-schema-model-generator

从JSON-Schema文件生成PHP模型类,包括验证并提供生成类的流畅自动完成功能。

目录

动机

简单示例:从PHP应用程序中,您定义并记录API,使用swagger注释和JSON-Schema模型。现在您想在控制器操作中使用模型而不是手动访问请求数据(例如,数组)。此外,您的模式已经为模型定义了验证规则。为什么要在您手动编写的代码中重复这些规则?相反,您可以为该库生成的模型设置中间件,并使用请求数据填充模型。现在您有一个经过验证的模型,可以在控制器操作中使用它。当处理嵌套对象时,还有完整的自动完成功能。太棒了!

要求

  • 至少需要PHP 8.0
  • 需要PHP扩展ext-json和ext-mbstring

安装

安装php-json-schema-model-generator的推荐方法是使用Composer

$ composer require --dev wol-soft/php-json-schema-model-generator
$ composer require wol-soft/php-json-schema-model-generator-production

为了避免将php-json-schema-model-generator的所有依赖项添加到您的生产依赖项中,建议将其作为dev-dependency添加,并包含wol-soft/php-json-schema-model-generator-production库。生产库提供所有类以运行生成的代码。生成类应作为开发环境中的一个步骤或在应用程序构建步骤中完成(这是推荐的流程)。

基本用法

有关更多详细信息,请参阅文档

生成模型的基础对象是ModelGenerator。创建生成器后,您可以使用该对象生成模型类而无需任何其他配置

(new ModelGenerator())
    ->generateModels(new RecursiveDirectoryProvider(__DIR__ . '/schema'), __DIR__ . '/result');

generateModels方法的第一个参数必须是一个实现了SchemaProviderInterface接口的类。提供者获取JSON模式文件并为生成器提供它们。以下提供者可用:

第二个参数必须指向一个现有且为空的目录(您可以使用generateModelDirectory辅助方法创建您的目标目录)。生成器完成后,此目录将包含生成的PHP类。

作为可选参数,您可以设置一个GeneratorConfiguration对象(请参阅文档中所有可用的选项)来配置您的生成器,或使用generateModelDirectory方法生成模型目录(如果不存在,将生成目录;如果已存在,将删除所有包含的文件和文件夹,以进行干净的生成过程)

$generator = new ModelGenerator(
    (new GeneratorConfiguration())
        ->setNamespacePrefix('MyApp\Model')
        ->setImmutable(false)
);

$generator
    ->generateModelDirectory(__DIR__ . '/result');
    ->generateModels(new RecursiveDirectoryProvider(__DIR__ . '/schema'), __DIR__ . '/result');

生成器将递归检查给定的源目录,并将所有找到的*.json文件转换为模型。源目录内的所有JSON-Schema文件都必须提供对象的模式。

示例

目录 ./tests/manual 包含一些简单的示例,展示了用法。通过执行 composer update 安装库的依赖项后,您可以执行 php ./tests/manual/test.php 生成示例,并使用一些 JSON-Schema 文件进行探索,以了解库的功能。

让我们来看一个简单的示例。我们创建了一个包含姓名和可选年龄的简单人员模型。我们的结果 JSON-Schema

{
  "$id": "Person",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer",
      "minimum": 0
    }
  },
  "required": [
    "name"
  ]
}

使用此 JSON-Schema 生成一个类后,我们的名为 Person 的类将提供以下接口

// the constructor takes an array with data which is validated and applied to the model
public function __construct(array $modelData);

// the method getRawModelDataInput always delivers the raw input which was provided on instantiation
public function getRawModelDataInput(): array;

// getters to fetch the validated properties. Age is nullable as it's not required
public function getName(): string;
public function getAge(): ?int;

// setters to change the values of the model after instantiation (only generated if immutability is disabled)
public function setName(string $name): Person;
public function setAge(?int $age): Person;

现在让我们看看生成的模型的行为

// Throws an exception as the required name isn't provided.
// Exception: 'Missing required value for name'
$person = new Person([]);

// Throws an exception as the name provides an invalid value.
// Exception: 'Invalid type for name. Requires string, got int'
$person = new Person(['name' => 12]);

// Throws an exception as the age contains an invalid value due to the minimum definition.
// Exception: 'Value for age must not be smaller than 0'
$person = new Person(['name' => 'Albert', 'age' => -1]);

// A valid example as the age isn't required
$person = new Person(['name' => 'Albert']);
$person->getName(); // returns 'Albert'
$person->getAge(); // returns NULL
$person->getRawModelDataInput(); // returns ['name' => 'Albert']

// If setters are generated the setters also perform validations.
// Exception: 'Value for age must not be smaller than 0'
$person->setAge(-10);

更复杂的异常消息,例如来自 allOf 组合的,可能如下所示

Invalid value for Animal declined by composition constraint.
  Requires to match 3 composition elements but matched 1 elements.
  - Composition element #1: Failed
    * Value for age must not be smaller than 0
  - Composition element #2: Valid
  - Composition element #3: Failed
    * Value for legs must not be smaller than 2
    * Value for legs must be a multiple of 2

这是怎么工作的?

类生成过程基本上分为三到四个步骤

  • 扫描给定的源目录以找到所有应处理的 *.json 文件。
  • 遍历所有应生成的模式。这是类生成的关键步骤。现在每个模式都被解析,并为生成的模型填充一个包含属性的模式模型类。JSON-Schema 中定义的所有验证规则都被转换为纯 PHP 代码。在模型完成后,将生成一个 RenderJob 并添加到 RenderQueue。如果 JSON-Schema 包含嵌套对象或引用多个 RenderJob,则可能为给定的模式文件添加多个 RenderJob。
  • 如果为生成过程定义了后处理器,则将应用后处理器。
  • 解析所有模式文件后没有错误,将处理 RenderQueue。将执行之前添加的所有 RenderJob,并将 PHP 类保存到指定的目标目录。

测试

通过 PHPUnit 测试库。

通过执行 ./vendor/bin/phpunit (Linux) 或 vendor\bin\phpunit.bat (Windows) 来执行测试,安装库的依赖项后。测试名称已针对使用 --testdox 输出进行优化。大多数测试是原子集成测试,它们将设置一个 JSON-Schema 文件并从模式生成一个类,然后测试生成的类的行为。

在执行过程中,测试将在 tmp 中创建一个名为 PHPModelGeneratorTest 的目录,其中将写入 JSON-Schema 文件和 PHP 类。

如果从 JSON-Schema 创建 PHP 类的测试失败,则 JSON-Schema 和生成的类(类)将被输出到 ./failed-classes 目录

文档

该库的文档通过 Sphinx 生成。

要生成文档,请安装 Sphinx,进入 docs 目录,然后执行 make html (Linux) 或 make.bat html (Windows)。生成的文档将可在 ./docs/build 目录中找到。

托管在 Read the Docs 上的文档在每次推送时都会更新。