webmozart/json

一个强大的JSON解码器/编码器,支持模式验证。

维护者

详细信息

github.com/webmozart/json

源代码

问题

安装次数:751,942

依赖者: 28

建议者: 3

安全性: 0

星标: 358

关注者: 22

分支: 30

开放问题: 11

1.2.2 2016-01-14 12:11 UTC

This package is auto-updated.

Last update: 2024-09-07 23:56:52 UTC


README

Build Status Build status Scrutinizer Code Quality Latest Stable Version Total Downloads Dependency Status

最新版本:1.2.2

一个强大的包装器,用于json_encode()/json_decode(),它跨PHP版本标准化其行为,抛出有意义的异常,并默认支持模式验证。

安装

使用Composer安装此包

$ composer require webmozart/json

编码

使用JsonEncoder将数据编码为JSON

use Webmozart\Json\JsonEncoder;

$encoder = new JsonEncoder();

// Store JSON in string
$string = $encoder->encode($data);

// Store JSON in file
$encoder->encodeFile($data, '/path/to/file.json');

默认情况下,使用存储在JSON文档$schema属性中的JSON模式来验证文件。您还可以在两种方法的最后一个可选参数中传递模式的路径

use Webmozart\Json\ValidationFailedException;

try {
    $string = $encoder->encode($data, '/path/to/schema.json');
} catch (ValidationFailedException $e) {
    // data did not match schema 
}

解码

使用JsonDecoder解码JSON字符串/文件

use Webmozart\Json\JsonDecoder;

$decoder = new JsonDecoder();

// Read JSON string
$data = $decoder->decode($string);

// Read JSON file
$data = $decoder->decodeFile('/path/to/file.json');

JsonEncoder一样,解码器接受其方法的最后一个可选参数中的JSON模式的路径

use Webmozart\Json\ValidationFailedException;

try {
    $data = $decoder->decodeFile('/path/to/file.json', '/path/to/schema.json');
} catch (ValidationFailedException $e) {
    // data did not match schema 
}

验证

有时需要将编码/解码JSON数据和对其模式进行验证的步骤分开。在这种情况下,可以在编码/解码期间省略模式参数,并使用JsonValidator手动稍后验证数据

use Webmozart\Json\JsonDecoder;
use Webmozart\Json\JsonValidator;
use Webmozart\Json\ValidationFailedException;

$decoder = new JsonDecoder();
$validator = new JsonValidator();

$data = $decoder->decodeFile('/path/to/file.json');

// process $data...

$errors = $validator->validate($data, '/path/to/schema.json');

if (count($errors) > 0) {
    // data did not match schema 
}

注意:如果使用$schema属性设置模式(参见下一节),则此方法不起作用。如果设置了该属性,则在编码和解码过程中始终使用该模式进行验证。

模式

鼓励您将JSON文档的模式存储在$schema属性中

{
    "$schema": "http://example.org/schemas/1.0/schema"
}

此包中的实用程序将从URL加载模式并将其用于验证文档。显然,这会影响性能,并且取决于服务器的可用性和互联网连接。因此,鼓励您将模式与您的包一起分发。使用LocalUriRetriever将URL映射到您的本地模式文件

$uriRetriever = new UriRetriever();
$uriRetriever->setUriRetriever(new LocalUriRetriever(
    // base directory
    __DIR__.'/../res/schemas',
    // list of schema mappings
    array(
        'http://example.org/schemas/1.0/schema' => 'schema-1.0.json',
    )
));

$validator = new JsonValidator(null, $uriRetriever);
$encoder = new JsonEncoder($validator);
$decoder = new JsonDecoder($validator);

// ...

转换

您可以实现JsonConverter来封装将对象从JSON结构转换为对象并在单个类中封装的转换

use stdClass;
use Webmozart\Json\Conversion\JsonConverter;

class ConfigFileJsonConverter implements JsonConverter
{
    const SCHEMA = 'http://example.org/schemas/1.0/schema';
    
    public function toJson($configFile, array $options = array())
    {
        $jsonData = new stdClass();
        $jsonData->{'$schema'} = self::SCHEMA;
         
        if (null !== $configFile->getApplicationName()) {
            $jsonData->application = $configFile->getApplicationName();
        }
        
        // ...
        
        return $jsonData;
    }
    
    public function fromJson($jsonData, array $options = array())
    {
        $configFile = new ConfigFile();
        
        if (isset($jsonData->application)) {
            $configFile->setApplicationName($jsonData->application);
        }
        
        // ...
        
        return $configFile;
    }
}

现在加载和转储ConfigFile对象非常简单

$converter = new ConfigFileJsonConverter();

// Load config.json as ConfigFile object
$jsonData = $decoder->decodeFile('/path/to/config.json');
$configFile = $converter->fromJson($jsonData);

// Save ConfigFile object as config.json
$jsonData = $converter->toJson($configFile);
$encoder->encodeFile($jsonData, '/path/to/config.json');

您可以通过将转换器包装在ValidatingConverter中来自动化ConfigFile的模式验证

use Webmozart\Json\Validation\ValidatingConverter;

$converter = new ValidatingConverter(new ConfigFileJsonConverter());

您还可以通过将模式传递给ValidatingConverter来针对显式模式进行验证

use Webmozart\Json\Validation\ValidatingConverter;

$converter = new ValidatingConverter(
    new ConfigFileJsonConverter(),
    __DIR__.'/../res/schema/config-schema.json'
);

版本控制和迁移

当您持续开发应用程序时,您将进入需要更改您的JSON模式的情况。将JSON文件更新以匹配更改后的模式可能是具有挑战性和耗时的。此包支持版本控制机制来自动化此迁移。

想象一下config.json文件有三个不同的版本:1.0、2.0和3.0。在这些版本之间,键的名称发生了变化

config.json(版本1.0)

{
    "$schema": "http://example.org/schemas/1.0/schema",
    "application": "Hello world!"
}

config.json(版本2.0)

{
    "$schema": "http://example.org/schemas/2.0/schema",
    "application.name": "Hello world!"
}

config.json(版本3.0)

{
    "$schema": "http://example.org/schemas/3.0/schema",
    "application": {
        "name": "Hello world!"
    }
}

您可以通过实现与最新版本(例如3.0)兼容的转换器来支持这些版本中的任何文件

  1. 兼容最新版本(例如3.0)的转换器

  2. 将旧版本迁移到新版本(例如从1.0到2.0和从2.0到3.0)的迁移。

让我们看一下3.0版本的ConfigFileJsonConverter的一个例子。

use stdClass;
use Webmozart\Json\Conversion\JsonConverter;

class ConfigFileJsonConverter implements JsonConverter
{
    const SCHEMA = 'http://example.org/schemas/3.0/schema';
    
    public function toJson($configFile, array $options = array())
    {
        $jsonData = new stdClass();
        $jsonData->{'$schema'} = self::SCHEMA;
         
        if (null !== $configFile->getApplicationName()) {
            $jsonData->application = new stdClass();
            $jsonData->application->name = $configFile->getApplicationName();
        }
        
        // ...
        
        return $jsonData;
    }
    
    public function fromJson($jsonData, array $options = array())
    {
        $configFile = new ConfigFile();
        
        if (isset($jsonData->application->name)) {
            $configFile->setApplicationName($jsonData->application->name);
        }
        
        // ...
        
        return $configFile;
    }
}

此转换器可以按照上一节所述使用。然而,它只能与3.0版本的config.json文件一起使用。

我们可以通过实现JsonMigration接口来添加对旧文件的支持。该接口包含四个方法

  • getSourceVersion():返回迁移的源版本
  • getTargetVersion():返回迁移的目标版本
  • up(stdClass $jsonData):从源版本迁移到目标版本
  • down(stdClass $jsonData):从目标版本迁移回源版本
use Webmozart\Json\Migration\JsonMigration;

class ConfigFileJson20To30Migration implements JsonMigration
{
    const SOURCE_SCHEMA = 'http://example.org/schemas/2.0/schema';
    
    const TARGET_SCHEMA = 'http://example.org/schemas/3.0/schema';
    
    public function getSourceVersion()
    {
        return '2.0';
    }
    
    public function getTargetVersion()
    {
        return '3.0';
    }
    
    public function up(stdClass $jsonData)
    {
        $jsonData->{'$schema'} = self::TARGET_SCHEMA;
        
        if (isset($jsonData->{'application.name'})) {
            $jsonData->application = new stdClass();
            $jsonData->application->name = $jsonData->{'application.name'};
            
            unset($jsonData->{'application.name'});
        )
    }
    
    public function down(stdClass $jsonData)
    {
        $jsonData->{'$schema'} = self::SOURCE_SCHEMA;
        
        if (isset($jsonData->application->name)) {
            $jsonData->{'application.name'} = $jsonData->application->name;
            
            unset($jsonData->application);
        )
    }
}

有了这样的迁移列表,我们可以创建一个装饰我们的ConfigFileJsonConverterMigratingConverter

use Webmozart\Json\Migration\MigratingConverter;
use Webmozart\Json\Migration\MigrationManager;

// Written for version 3.0
$converter = new ConfigFileJsonConverter();

// Support for older versions. The order of migrations does not matter.
$migrationManager = new MigrationManager(array(
    new ConfigFileJson10To20Migration(),
    new ConfigFileJson20To30Migration(),
));

// Decorate the converter
$converter = new MigratingConverter($converter, $migrationManager);

生成的转换器能够加载和转储任何版本的1.0、2.0和3.0的JSON文件。

// Loads a file in version 1.0, 2.0 or 3.0
$jsonData = $decoder->decodeFile('/path/to/config.json');
$configFile = $converter->fromJson($jsonData);

// Writes the file in the latest version by default (3.0)
$jsonData = $converter->toJson($configFile);
$encoder->encodeFile($jsonData, '/path/to/config.json');

// Writes the file in a specific version
$jsonData = $converter->toJson($configFile, array(
    'targetVersion' => '2.0',
));
$encoder->encodeFile($jsonData, '/path/to/config.json');

不同版本的验证

如果您想添加模式验证,请将您的编码器包装到ValidatingConverter中。您可以将内部和外部转换器都包装起来,以确保运行迁移前后的JSON都符合相应的模式。

// Written for version 3.0
$converter = new ConfigFileJsonConverter();

// Decorate to validate against the schema at version 3.0
$converter = new ValidatingConverter($converter);

// Decorate to support different versions
$converter = new MigratingConverter($converter, $migrationManager);

// Decorate to validate against the old schema
$converter = new ValidatingConverter($converter);

如果您将版本存储在version字段中(见下文),并且想根据该版本使用自定义模式,则可以传递用于解析模式路径的schema路径或闭包

// Written for version 3.0
$converter = new ConfigFileJsonConverter();

// Decorate to validate against the schema at version 3.0
$converter = new ValidatingConverter($converter, __DIR__.'/../res/schema/config-schema-3.0.json');

// Decorate to support different versions
$converter = new MigratingConverter($converter, $migrationManager);

// Decorate to validate against the old schema
$converter = new ValidatingConverter($converter, function ($jsonData) {
    return __DIR__.'/../res/schema/config-schema-'.$jsonData->version.'.json'
});

使用自定义模式版本化

默认情况下,模式的版本存储在模式名称中

{
    "$schema": "http://example.com/schemas/1.0/my-schema"
}

版本必须用斜杠括起来。将版本附加到模式上,例如,是不行的

{
    "$schema": "http://example.com/schemas/my-schema-1.0"
}

但是,您可以通过创建一个具有自定义正则表达式的SchemaUriVersioner来自定义模式URI的格式

use Webmozart\Json\Versioning\SchemaUriVersioner;

$versioner = new SchemaUriVersioner('~(?<=-)\d+\.\d+(?=$)~');

$migrationManager = new MigrationManager(array(
    // migrations...
), $versioner);

// ...

正则表达式必须仅匹配版本。请确保将版本前后字符包裹在前瞻和后顾断言中((?<=...)(?=...))。

在字段中存储版本

除了在模式URI中存储版本,您还可以在单独的字段中存储它。例如,字段"version"

{
    "version": "1.0"
}

此用例由VersionFieldVersioner类支持

use Webmozart\Json\Versioning\VersionFieldVersioner;

$versioner = new VersionFieldVersioner();

$migrationManager = new MigrationManager(array(
    // migrations...
), $versioner);

// ...

VersionFieldVersioner的构造函数可选地接受一个用于存储版本的自定义字段名称。默认字段名称是"version"。

作者

贡献

对这个包的贡献总是受欢迎的!

支持

如果您遇到问题,请给[email protected]发邮件或在Twitter上呼喊@webmozart

许可

本包的所有内容均根据MIT许可证授权。