apimatic/jsonmapper 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

apimatic/jsonmapper

Composer 安装命令:

composer require apimatic/jsonmapper

包简介

Map nested JSON structures onto PHP classes

README 文档

README

https://img.shields.io/packagist/v/apimatic/jsonmapper.svg?style=flat https://img.shields.io/packagist/dm/apimatic/jsonmapper.svg?style=flat https://sonarcloud.io/api/project_badges/measure?project=apimatic_jsonmapper&metric=coverage https://sonarcloud.io/api/project_badges/measure?project=apimatic_jsonmapper&metric=sqale_rating https://sonarcloud.io/api/project_badges/measure?project=apimatic_jsonmapper&metric=vulnerabilities https://img.shields.io/packagist/l/apimatic/jsonmapper.svg?style=flat

Takes data retrieved from a JSON web service and converts them into nested object and arrays - using your own model classes.

Starting from a base object, it maps JSON data on class properties, converting them into the correct simple types or objects.

It's a bit like the native SOAP parameter mapping PHP's SoapClient gives you, but for JSON. Note that it does not rely on any schema, only your class definitions.

Type detection works by parsing @var docblock annotations of class properties, as well as type hints in setter methods. If docblock comments, or comments in general are discarded through some configuration setting like opcache.save_comments=0, or any other similar configuration, an exception is thrown, blocking any further operation.

You do not have to modify your model classes by adding JSON specific code; it works automatically by parsing already-existing docblocks.

Keywords: deserialization, hydration

Contents

Pro & contra

Benefits

  • Autocompletion in IDEs
  • It's easy to add comfort methods to data model classes
  • Your JSON API may change, but your models can stay the same - not breaking applications that use the model classes.

Drawbacks

  • Model classes need to be written by hand

    Since JsonMapper does not rely on any schema information (e.g. from json-schema), model classes cannot be generated automatically.

Usage

Basic usage

  1. Register an autoloader that can load PSR-0 compatible classes.
  2. Create a JsonMapper object instance
  3. Call the map or mapArray method, depending on your data

Map a normal object:

<?php
require 'autoload.php';
$mapper = new JsonMapper();
$contactObject = $mapper->map($jsonContact, new Contact());
?>

Map an array of objects:

<?php
require 'autoload.php';
$mapper = new JsonMapper();
$contactsArray = $mapper->mapArray(
    $jsonContacts, new ArrayObject(), 'Contact'
);
?>

Example

JSON from a address book web service:

{
    'name':'Sheldon Cooper',
    'address': {
        'street': '2311 N. Los Robles Avenue',
        'city': 'Pasadena'
    }
}

Your local Contact class:

<?php
class Contact
{
    /**
     * Full name
     * @var string
     */
    public $name;

    /**
     * @var Address
     */
    public $address;
}
?>

Your local Address class:

<?php
class Address
{
    public $street;
    public $city;

    public function getGeoCoords()
    {
        //do something with the $street and $city
    }
}
?>

Your application code:

<?php
$json = json_decode(file_get_contents('http://example.org/bigbang.json'));
$mapper = new JsonMapper();
$contact = $mapper->map($json, new Contact());

echo "Geo coordinates for " . $contact->name . ": "
    . var_export($contact->address->getGeoCoords(), true);
?>

Letting JsonMapper create the instances for you

Map a normal object (works similarly to map):

$mapper = new JsonMapper();
$contactObject = $mapper->mapClass($jsonContact, 'Contact');

Map an array of objects (works similarly to mapArray):

$mapper = new JsonMapper();
$contactsArray = $mapper->mapClassArray($jsonContacts, 'Contact');

Map a value with any combination of types e.g oneOf(string,int) or anyOf(string,Contact):

$mapper = new JsonMapper();
$contactObject = $mapper->mapFor($value, 'oneOf(string,Contact)');

Property type documentation

JsonMapper uses several sources to detect the correct type of a property:

  1. The setter method (set + ucwords($propertyname)) is inspected.

    Underscores make the next letter uppercase, which means that for a JSON property foo_bar_baz a setter method of setFooBarBaz is used.

    1. If it has a type hint in the method signature, this type used:

      public function setPerson(Contact $person) {...}
      
    2. The method's docblock is inspected for @param $type annotations:

      /**
       * @param Contact $person Main contact for this application
       */
      public function setPerson($person) {...}
      
    3. If no type could be detected, the plain JSON value is passed to the setter method.

  2. @var $type docblock annotation of class properties:

    /**
     * @var \my\application\model\Contact
     */
    public $person;
    

    Note that the property has to be public to be used directly.

    If no type could be detected, the property gets the plain JSON value.

    If a property can not be found, JsonMapper tries to find the property in a case-insensitive manner. A JSON property isempty would then be mapped to a PHP property isEmpty.

To map a JSON key to an arbitrarily named class property, you can use the @maps annotation:

/**
 * @var \my\application\model\Person
 * @maps person_object
 */
public $person;

Supported type names:

  • Simple types:
    • string
    • bool, boolean
    • int, integer
    • float
    • array
    • object
  • Class names, with and without namespaces
  • Arrays of simple types and class names:
    • int[]
    • Contact[]
  • ArrayObjects of simple types and class names:
    • ContactList[Contact]
    • NumberList[int]
  • Nullable types:
    • int|null - will be null if the value in JSON is null, otherwise it will be an integer

ArrayObjects and extending classes are treated as arrays.

Variables without a type or with type mixed will get the JSON value set directly without any conversion.

See phpdoc's type documentation for more information.

Simple type mapping

When an object shall be created but the JSON contains a simple type only (e.g. string, float, boolean), this value is passed to the classes' constructor. Example:

PHP code:

/**
 * @var DateTime
 */
public $date;

JSON:

{"date":"2014-05-15"}

This will result in new DateTime('2014-05-15') being called.

Custom property initialization

You can use the @factory annotation to specify a custom method that will be called to get the value to be assigned to the property.

/**
 * @factory MyUtilityClass::createDate
 */
public $date;

Here, createDate method in the MyUtilityClass is called with the raw value for date property and the value returned by the factory method is then assigned to the date property.

The factory method should return true when tested with is_callable, otherwise an exception will be thrown.

The factory annotation can be used with other annotations such as @var; however, only the value created by the factory method will be used while other typehints and initialization methods for the property will be ignored.

Logging

JsonMapper's setLogger() method supports all PSR-3 compatible logger instances.

Events that get logged:

  • JSON data contain a key, but the class does not have a property or setter method for it.
  • Neither setter nor property can be set from outside because they are protected or private

Handling invalid or missing data

During development, APIs often change. To get notified about such changes, JsonMapper may throw exceptions in case of either missing or yet unknown data.

Unknown properties

When JsonMapper sees properties in the JSON data that are not defined in the PHP class, you can let it throw an exception by setting $bExceptionOnUndefinedProperty:

$jm = new JsonMapper();
$jm->bExceptionOnUndefinedProperty = true;
$jm->map(...);

To process unknown properties yourself, you can set a method on the class as a collection method:

$jm = new JsonMapper();
$mapper->sAdditionalPropertiesCollectionMethod = 'addAdditionalProperty';
$jm->map(...);

Here, the addAdditionalProperty() method will be called with a name and a value argument.

Missing properties

Properties in your PHP classes can be marked as "required" by putting @required in their docblock:

/**
 * @var string
 * @required
 */
public $someDatum;

When the JSON data do not contain this property, JsonMapper will throw an exception when $bExceptionOnMissingData is activated:

$jm = new JsonMapper();
$jm->bExceptionOnMissingData = true;
$jm->map(...);

Passing arrays to map()

You may wish to pass array data into map() that you got by calling

json_decode($jsonString, true)

By default, JsonMapper will throw an exception because map() requires an object as first parameter. You can circumvent that by setting $bEnforceMapType to false:

$jm = new JsonMapper();
$jm->bEnforceMapType = false;
$jm->map(...);

Handling polymorphic responses

JsonMapper allows you to map a JSON object to a derived class based on a discriminator field. The discriminator field's value is used to decide which class this JSON object should be mapped to.

Your local Person class:

<?php
/**
 * @discriminator type
 * @discriminatorType person
 */
class Person
{
    public $name;
    public $age;
    public $type;
}

Your local Employee class:

<?php
/**
 * @discriminator type
 * @discriminatorType employee
 */
class Employee extends Person
{
    public $employeeId;
}

Your application code:

$mapper = new JsonMapper();
$mapper->arChildClasses['Person'] = ['Employee'];
$mapper->arChildClasses['Employee'] = [];
$person = $mapper->mapClass($json, 'Person');

Now, if the value of the type key in JSON is "person" then an instance of a Person class is returned. However, if the type is "employee" then an instance of Employee class is returned.

Classes need to be registered in arChildClasses before being used with discriminator.

Note that there can only be one discriminator field in an object hierarchy.

Polymorphic responses also work if the polymorphic class is embedded as a field or in an array.

To map an array of classes, use the mapArrayClass which will create the right type of objects by examining the discriminatorType value.

Installation

Supported PHP Versions

  • PHP 5.6
  • PHP 7.0
  • PHP 7.1
  • PHP 7.2
  • PHP 7.4
  • PHP 8.0
  • PHP 8.1
  • PHP 8.2

Install the Package

From Packagist:

$ composer require apimatic/jsonmapper

Related software

About JsonMapper

License

JsonMapper is licensed under the OSL 3.0.

Coding style

JsonMapper follows the PEAR Coding Standards.

Author

Christian Weiske, Netresearch GmbH & Co KG

apimatic/jsonmapper 适用场景与选型建议

apimatic/jsonmapper 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9.07M 次下载、GitHub Stars 达 24, 最近一次更新时间为 2016 年 04 月 14 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 apimatic/jsonmapper 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 apimatic/jsonmapper 我们能提供哪些服务?
定制开发 / 二次开发

基于 apimatic/jsonmapper 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 9.07M
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 26
  • 点击次数: 25
  • 依赖项目数: 65
  • 推荐数: 0

GitHub 信息

  • Stars: 24
  • Watchers: 4
  • Forks: 187
  • 开发语言: PHP

其他信息

  • 授权协议: OSL-3.0
  • 更新时间: 2016-04-14