kassko/data-mapper

一个提供大量功能的映射器,用于表示一些原始数据,如对象

v1.0.0 2021-12-03 00:39 UTC

README

Build Status Total Downloads

一个非常可调的PHP映射器,支持跨ORM和跨DBMS

  • 对象不扩展基础实体类
  • 映射嵌套对象
  • 支持所有类型源之间的关系(关系数据库、非关系数据库、缓存等)
  • 懒加载
  • 支持使用表达式语言进行动态配置
  • 各种映射配置格式
  • 当源不可用或不稳定时,可以链式调用一些后备源

安装

注意:

  • 版本包含4个数字
  • 第二个版本号用于兼容性破坏时
  • 第三个用于新功能
  • 第四个用于热修复
  • 第一个用于新API或从预发布版升级到发布版(从0到1)

建议使用0.12版本的版本。已不再维护0.13版本。

良好需求示例

composer require kassko/data-mapper:"~0.12.6"

基本用法

运行测试

确保已安装phpunit phpunit

安装:精度

如果您使用注解,请注册自动加载器

$loader = require 'vendor/autoload.php';

Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($loader);

并运行环境

(new Kassko\DataMapper\DataMapperBuilder)->run();

访问数据

数据映射器风格

$id = 1;
//Construct a person, set an id to it.
$person = new Kassko\Sample\Person($id);

echo $person->getName();//Implicitly load the name from the given id by fetching the source configured.

Doctrine风格

//Here some stuff to retrieve the entityManager.

$id = 1;
$person = $entityManager->getRepository('Kassko\Sample\Person')->find($id);

echo $person->getName();

使用数据映射器,您只需调用一个getter,访问逻辑在配置中

配置可以是对象php文件中的,也可以是单独的文件。如果在对象文件中,配置在注解中,或者一个方法返回一个php数组或yaml字符串。如果在单独的文件中,配置在php或yaml文件中。

为了简单起见,使用注解格式记录了用法。但在本文档中,您可以找到其他格式的参考指南。

填充您的对象

使用内联数据源填充您的对象

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;
use Kassko\DataMapper\ObjectExtension\LoadableTrait;

class Person
{
    use LoadableTrait;

    private $id;
    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", args="#id", lazyLoading=true)
     */
    private $name;
    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", args="#id", lazyLoading=true)
     */
    private $email;

    public function __construct($id) { $this->id = $id; }
    public function getId() { return $this->id; }
    public function getName() { $this->loadProperty('name'); return $this->name; }
    public function getEmail() { $this->loadProperty('email'); return $this->email; }
}
namespace Kassko\Sample;

class PersonDataSource
{
    public function getData($id)
    {
        return [
          'name' => 'foo',
          'email' => 'foo@bar.com'
        ];
    }  
}

使用数据源存储填充您的对象

数据源存储很有用

如果您希望在一个地方组织您的源

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;
use Kassko\DataMapper\ObjectExtension\LoadableTrait;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="nameSource", 
 *          class="Kassko\Sample\PersonDataSource", 
 *          method="getData",
 *          args="#id",
 *          lazyLoading=true
 *      ),
 *      @DM\DataSource(
 *          id="emailSource", 
 *          class="Kassko\Sample\PersonDataSource", 
 *          method="getData",
 *          args="#id",
 *          lazyLoading=true
 *      )
 * })
 */
class Person
{
    use LoadableTrait;

    private $id;
    /**
     * @DM\RefSource(id="nameSource")
     */
    private $name;
    /**
     * @DM\RefSource(id="emailSource")
     */
    private $email;

    public function __construct($id) { $this->id = $id; }
    public function getId() { return $this->id; }
    public function getName() { $this->loadProperty('name'); return $this->name; }
    public function getEmail() { $this->loadProperty('email'); return $this->email; }
}

或者如果您有一个填充多个属性的源

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;
use Kassko\DataMapper\ObjectExtension\LoadableTrait;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="personSource", 
 *          class="Kassko\Sample\PersonDataSource", 
 *          method="getData",
 *          args="#id", 
 *          lazyLoading=true,
 *          supplySeveralFields=true
 *      )
 * })
 */
class Person
{
    use LoadableTrait;

    private $id;
    /**
     * @DM\RefSource(id="personSource")
     * @DM\Field("name"="first_name")
     */
    private $firstName;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $name;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $email;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $phone;

    public function __construct($id) { $this->id = $id; }
    public function getId() { return $this->id; }
    public function getFirstName() { $this->loadProperty('firstName'); return $this->firstName; }
    public function getName() { $this->loadProperty('name'); return $this->name; }
    public function getEmail() { $this->loadProperty('email'); return $this->email; }
    public function getPhone() { $this->loadProperty('phone'); return $this->phone; }
}
namespace Kassko\Sample;

class PersonDataSource
{
    public function getData($id)
    {
        return [
            'first_name' => 'foo',
            'name' => 'bar',
            'email' => 'foo@bar',
            'phone' => '01 02 03 04 05',
        ];
    }
}

请注意,您不必公开setter。只有在您有特定的逻辑要编写时才公开它们。我建议您不要将这些setter设置为“public”,因为这些属性由数据源加载(并管理)。

与源和依赖注入一起工作

CarRepository也有一些依赖项(实体管理器),它通过类-resolver解析器实例化。提醒:您可以在这里看到更多详细信息。

运行环境和注册依赖项

(new Kassko\DataMapper\DataMapperBuilder)
    ->settings(['container' => ['instance' => ['person.data_source_id' => $personDataSourceInstance]]])
    ->run()
;

您可以发送一个实现\ArrayAccess的对象

(new Kassko\DataMapper\DataMapperBuilder)
    ->settings(['container' => ['instance' => $container]])
    ->run()
;

或者发送一个具有“get”和“has”方法的对象

(new Kassko\DataMapper\DataMapperBuilder)
    ->settings(['container' => ['instance' => $container, 'get_method_name' => 'get', 'has_method_name' => 'has']])
    ->run()
;

并且您指定以下依赖项id

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="personSource", 
 *          class="@person.data_source_id", 
 *          method="find", 
 *          args="#id",
 *          lazyLoading=true
 *      )
 * })
 */
class Person
{
}

源注解详细信息

  • id。源的一个任意id。可选但必需,如果您需要在其他注解中提及源。
  • class。返回数据的源类。如果源有依赖项(例如,PersonDataSource有依赖项$connection),其实例化可以由名为class-resolver的解析器执行。有关更多详细信息,请参阅这里
  • method。返回数据的方法的名称。
  • args。返回数据的方法的参数。您可以发送一个原始值、一个带有前缀#的字段值(例如:#id)、一个表达式等。有关更多详细信息,请参阅这里
  • supplySeveralFields。源是直接返回数据还是将它们放在一个数组的键中并返回数组。如果源只提供单个字段,它可以直接返回数据,这些数据将绑定到相应的属性。否则,源应返回一个数组,其键与要提供的属性一样多。键的名称与属性相同或映射在注解Field中完成。

Data-mapper不是一个ORM,因此它不能为您生成一些SQL语句。但它可以封装ORM(如Doctrine ORM)的使用,这样您就可以利用两者。它还可以帮助您在不同的DBMS之间建立关系。

与Doctrine源的关系示例

namespace Kassko\Sample;

use Kassko\DataMapper\ObjectExtension\LoadableTrait;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="personSource", 
 *          class="Kassko\Sample\PersonDataSource", 
 *          method="getData", 
 *          args="#id", 
 *          lazyLoading=true,
 *          supplySeveralFields=true
 *      ),
 *      @DM\DataSource(
 *          id="carSource", 
 *          class="Kassko\Sample\CarRepository", 
 *          method="find", 
 *          args="expr(source('personSource')['car_id'])",
 *          lazyLoading=true
 *      )
 * })
 */
class Person
{
    private $id;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $firstName;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $name;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $email;
    /**
     * @DM\RefSource(id="personSource")
     */
    private $phone;
    /**
     * @DM\RefSource(id="carSource")
     */
    private $car;

    public function __construct($id) { $this->id = $id; }
    public function getId() { return $this->id; }
    public function getFirstName() { return $this->firstName; }
    public function getName() { return $this->name; }
    public function getEmail() { return $this->email; }
    public function getPhone() { return $this->phone; }
    public function getCar() { return $this->car; }
}
namespace Kassko\Sample;

class PersonDataSource
{
    public function getData($id)
    {
        return [
            'first_name' => 'foo',
            'name' => 'bar',
            'email' => 'foo@bar',
            'phone' => '01 02 03 04 05',
        ];
    }
}
namespace Kassko\Sample;

use Doctrine\ORM\EntityRepository;

/**
 * CarRepository is a Doctrine source that feed the property $car.
 */
class CarRepository extends EntityRepository
{
}

功能:详细信息

=======================================================================================================

基本用法

给定一个对象

namespace Kassko\Sample;

class Watch
{
        private $brand;
        private $color;

        public function getBrand() { return $this->brand; }
        public function setBrand($brand) { $this->brand = $brand; }
        public function getColor() { return $this->color; }
        public function setColor($color) { $this->color = $color; }
}

使用ResultBuilder

结果构建器允许您从包含多个记录的结果中填充整个集合。它还允许您获取单个结果,即使结果包含多个记录。

$data = [
        0 => [
                'brand' => 'some brand',
                'color' => 'blue',
        ],
        1 => [
                'brand' => 'some other brand',
                'color' => 'green',
        ],
];

$dataMapper = (new Kassko\DataMapper\DataMapperBuilder)->instance();

$dataMapper->resultBuilder('Kassko\Sample\Watch', $data)->all();//The result will be an array with two objects.
$dataMapper->resultBuilder('Kassko\Sample\Watch', $data)->first();//The result will be a watch object representing the first record.

上面的代码将显示

array(2) {
    ["brand"]=>
    string(10) "some brand"
    ["color"]=>
    string(4) "blue"
}

相反,您可以提取对象或对象集合的值

$dataMapper = (new Kassko\DataMapper\DataMapperBuilder)->instance();

$dataMapper->resultBuilder('Kassko\Sample\Watch')->raw($object);
$dataMapper->resultBuilder('Kassko\Sample\Watch')->raw($collection);

在上文中,我们使用了默认的加湿器。但您通常需要自定义加湿,因为列名与属性名不同,以及许多其他原因。

要自定义加湿,您应该提供映射配置。有多种格式可供选择,但在本文档中我们选择使用注解格式(有关所有映射配置格式的详细信息,请参阅 此处)。

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Watch
{
        private $brand;

        /**
         * @DM\Fields(name="COLOR")
         */
        private $color;

        public function getBrand() { return $this->brand; }
        public function setBrand($brand) { $this->brand = $brand; }
        public function getColor() { return $this->color; }
        public function setColor($color) { $this->color = $color; }
}
$loader = require 'vendor/autoload.php';

Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

$dataMapper = (new Kassko\DataMapper\DataMapperBuilder)->instance();
$dataMapper->resultBuilder('Kassko\Sample\Watch', $data)->all();

使用结果构建器

您可以在下面找到所有使用ResultBuilder获取结果的方法

        /*
        Return an array of objects.
        So return an array with only one object, if only one fullfill the request.
        */
        $resultBuilder->all();
        /*
        Return the object found.

        If more than one result are found, throw an exception
        Kassko\DataMapper\Result\Exception\NonUniqueResultException.

        If no result found, throw an exception
        Kassko\DataMapper\Result\Exception\NoResultException.
        */
        $resultBuilder->single();
        /*
        Return the object found or null.
        */
        $resultBuilder->one();

        /*
        Return the object found or a default result (like false).
        */
        $resultBuilder->one(false);

        /*
        If more than one result are found, throw an exception
        Kassko\DataMapper\Result\Exception\NonUniqueResultException.
        */
        /*
        Return the first object found or null.
        */
        $resultBuilder->first();

        /*
        Return the first object found or a default result (like value false).
        */
        $resultBuilder->first(false);

        /*
        If no result found, throw an exception
        Kassko\DataMapper\Result\Exception\NoResultException.
        */
        /*
        Return an array indexed by a property value.

        If the index does not exists (allIndexedByUnknown()), throw an exception Kassko\DataMapper\Result\Exception\NotFoundIndexException.

        If the same index is found twice, throw an exception
        Kassko\DataMapper\Result\Exception\DuplicatedIndexException.

        Examples:

        allIndexedByBrand() will index by brand value:
        [
                'BrandA' => $theWatchInstanceWithBrandA,
                'BrandB' => $theWatchInstanceWithBrandB,
        ]

        allIndexedByColor() will index by color value:
        [
                'Blue' => $theWatchInstanceWithColorBlue,
                'Red' => $theWatchInstanceWithColorRed,
        ]

        allIndexedByUnknown() will throw a Kassko\DataMapper\Result\Exception\NotFoundIndexException.
        */
        $resultBuilder->allIndexedByBrand();//Indexed by brand value
        //or
        $resultBuilder->allIndexedByColor();//Indexed by color value
        /*
        Return an iterator.

        Result will not be hydrated immediately but only when you will iterate the results (with "foreach" for example).
        */
        $result = $resultBuilder->iterable();
        foreach ($result as $object) {//$object is hydrated

                if ($object->getColor() === 'blue') {
                        break;

                        //We found the good object then we stop the loop and others objects in results will not be hydrated.
                }
        }
        /*
        Return an iterator indexed by a property value.

        If the index does not exists, throw an exception Kassko\DataMapper\Result\Exception\NotFoundIndexException.

        If the same index is found twice, throw an exception Kassko\DataMapper\Result\Exception\DuplicatedIndexException.
        */
        $resultBuilder->iterableIndexedByBrand();
        //or
        $resultBuilder->iterableIndexedByColor();

强制字段类型

本节将稍后编写。

在填充或提取之前应用转换器

转换器

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;
use Kassko\DataMapper\Hydrator\HydrationContextInterface;
use Kassko\DataMapper\Hydrator\Value;
use \DateTime;

class Watch
{
        private static $brandCodeToLabelMap = [1 => 'Brand A', 2 => 'Brand B'];
        private static $brandLabelToCodeMap = ['Brand A' => 1, 'Brand B' => 2];

        /**
         * @DM\Field(readConverter="readBrand", writeConverter="writeBrand")
         */
        private $brand;

        /**
         * @DM\Field(readConverter="hydrateBool", writeConverter="extractBool")
         */
        private $waterProof;

        /**
         * @DM\Field(readConverter="hydrateBoolFromSymbol", writeConverter="extractBoolToSymbol")
         */
        private $stopWatch;

        /**
         * @DM\Field(type="date", readDateConverter="Y-m-d H:i:s", writeDateConverter="Y-m-d H:i:s")
         */
        private $createdDate;

        public function getBrand() { return $this->brand; }
        public function setBrand($brand) { $this->brand = $brand; }
        public function isWaterProof() { return $this->waterProof; }
        public function setWaterProof($waterProof) { $this->waterProof = $waterProof; }
        public function hasStopWatch() { return $this->stopWatch; }
        public function setStopWatch($stopWatch) { $this->stopWatch = $stopWatch; }
        public function getCreatedDate() { return $this->createdDate; }
        public function setCreatedDate(DateTime $createdDate) { $this->createdDate = $createdDate; }

        public static function readBrand(Value $value, HydrationContextInterface $context)
        {
                if (isset(self::$brandCodeToLabelMap[$value->value])) {
                        $value->value = self::$brandCodeToLabelMap[$value->value];
                }
        }

        public static function writeBrand(Value $value, HydrationContextInterface $context)
        {
                if (isset(self::$brandLabelToCodeMap[$value->value])) {
                        $value->value = self::$brandLabelToCodeMap[$value->value];
                }
        }

        public static function hydrateBool(Value $value, HydrationContextInterface $context)
        {
                $value->value = $value->value == '1';
        }

        public static function extractBool(Value $value, HydrationContextInterface $context)
        {
                $value->value = $value->value ? '1' : '0';
        }

        public static function hydrateBoolFromSymbol(Value $value, HydrationContextInterface $context)
        {
                $value->value = $value->value == 'X';
        }

        public static function extractBoolToSymbol(Value $value, HydrationContextInterface $context)
        {
                $value->value = $value->value ? 'X' : ' ';
        }
}

readDateConverter包含将转换为Date对象的字符串格式。内部,DataMapper使用Php函数DateTime::createFromFormat()从原始字符串创建Date对象。

writeDateConverter包含您希望序列化Date对象的字符串格式。内部,DataMapper使用Php函数DateTime::createFromFormat()将Date对象序列化为字符串。

给定以下代码

$data = [
        'brand' => '1',
        'waterProof' => '1',
        'stopWatch' => 'X',
        'created_date' => '2014-09-14 12:36:52',
];

$dataMapper = (new Kassko\DataMapper\DataMapperBuilder)->instance();
$object = new Kassko\Sample\Watch;
$dataMapper->hydrator('Kassko\Sample\Watch')->hydrate($data, $object);
var_dump($object);

您的输出将是

object(Watch)#283 (8) {
        ["brand":"Watch":private]=> string(10) "Brand A"
        ["waterProof":"Watch":private]=> bool(true)
        ["stopWatch":"Watch":private]=> bool(true)
        ["createdDate":"Watch":private]=>
                object(DateTime)#320 (3) { ["date"]=> string(19) "2014-09-14 12:36:52" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/Berlin" }
}

如果created_date的格式不正确,将抛出异常。例如,在上面的read date converter中给出的格式是'Y-m-d H:i:s',因此create_date如'2014 09 14 12h36m52s'是不正确的。

日期转换器

本节将稍后编写。

在填充或提取过程前后添加回调

本节将稍后编写。

自定义getter和setter

DataMapper自动识别字段的getter(或isser或haser)和setter。

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Watch
{
        /**
         * @DM\Field
         */
        private $brand;

        /**
         * @DM\Field
         */
        private $waterProof;

        /**
         * @DM\Field
         */
        private $stopWatch;

        public function getBrand() { return $this->brand; }
        public function setBrand($brand) { $this->brand = $brand; }
        public function isWaterProof() { return $this->waterProof; }
        public function setWaterProof($waterProof) { $this->waterProof = $waterProof; }
        public function hasStopWatch() { return $this->stopWatch; }
        public function setStopWatch($stopWatch) { $this->stopWatch = $stopWatch; }
}

DataMapper将按顺序查找相应的getter,首先查看

  • 一个getter
  • 一个isser
  • 一个haser

您还可以指定相应的getter/setter

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Watch
{
        /**
         * @DM\Field(prefix="is")
         */
        private $waterProof;

        /**
         * @DM\Getter(prefix="has")
         */
        private $alarm;

        /**
         * @DM\Getter(prefix="are")
         */
        private $handsYellow;

        /**
         * @DM\Field(name="hasStopWatch")
         */
        private $stopWatch;

        /**
         * @DM\Getter(name="canColorChange")
         * @DM\Setter(name="colorCanChange")
         */
        private $variableColor;

        public function isWaterProof() { return $this->waterProof; }
        public function setWaterProof($waterProof) { $this->waterProof = $waterProof; }
        public function hasAlarm() { return $this->alarm; }
        public function setAlarm($stopWatch) { $this->alarm = $alarm; }
        public function areHandsYellow() { return $this->handsYellow; }
        public function setHandsyellow($handsYellow) { $this->handsYellow = $handsYellow; }
        public function hasStopWatch() { return $this->stopWatch; }
        public function setStopWatch($stopWatch) { $this->stopWatch = $stopWatch; }
        public function canColorChange() { return $this->variableColor; }
        public function colorCanChange($colorCanChange) { $this->variableColor = $colorCanChange; }
}

填充嵌套对象

本节将稍后编写。

配置PHP对象填充器而不是使用映射配置

本节将稍后编写。

与复杂对象(如服务)一起工作以创建

本节将稍后编写。

与其他映射配置格式一起工作

本节将稍后编写。

外部映射配置格式

本节将稍后编写。

内部映射配置格式

本节将稍后编写。

提高持久性无感知

本节将稍后编写。

在运行时选择映射配置

您可以使用相同的模型和多种映射配置,但您必须使用外部映射配置之一,而不是使用对象中嵌入的映射。因此,'yaml_file'或'php_file'是正确的映射格式,但'annotations'、'inner_php'或'inner_yaml'是错误的格式。

namespace Kassko\Sample;

class Color
{
        private $red;
        private $green;
        private $blue;

        public function getRed() { return $this->red; }
        public function setRed($red) { $this->red = $red; }
        public function getGreen() { return $this->green; }
        public function setGreen($green) { $this->green = $green; }
        public function getBlue() { return $this->blue; }
        public function setBlue($blue) { $this->blue = $blue; }
}

具有yaml映射的英文数据源

# color_en.yml

fields:
        red: ~
        green: ~
        blue: ~

具有yaml映射的法语数据源

# color_fr.yml

fields:
        red:
                name: rouge
        green:
                name: vert
        blue:
                name: bleu

假设我们有一个西班牙语数据源,其映射格式为php。

//color_es.php

return [
        'fields' => [
                'red' => 'rojo',
                'green' => 'verde',
                'blue' => 'azul',
        ],
];
use DataMapper\Configuration\RuntimeConfiguration;

$data = [
        'red' => '255',
        'green' => '0',
        'blue' => '127',
];

$resultBuilder = $dataMapper->resultBuilder('Kassko\Sample\Color', $data);
$resultBuilder->setRuntimeConfiguration(
        (new RuntimeConfiguration)
        ->addClassMetadataDir('Color', 'some_resource_dir')//Optional, if not specified Configuration::defaultClassMetadataResourceDir is used.
        ->addMappingResourceInfo('Color', 'color_en.yml', 'inner_yaml')
);

$resultBuilder->single();
use DataMapper\Configuration\RuntimeConfiguration;

$data = [
        'rouge' => '255',
        'vert' => '0',
        'bleu' => '127',
];

$resultBuilder = $dataMapper->resultBuilder('Kassko\Sample\Color', $data);
$resultBuilder->setRuntimeConfiguration(
        (new RuntimeConfiguration)
        ->addClassMetadataDir('Color', 'some_resource_dir')
        ->addMappingResourceInfo('Color', 'color_fr.yml', 'inner_yaml')
);

$resultBuilder->single();
use DataMapper\Configuration\RuntimeConfiguration;

$data = [
        'rojo' => '255',
        'verde' => '0',
        'azul' => '127',
];

$resultBuilder = $dataMapper->resultBuilder('Kassko\Sample\Color', $data);
$resultBuilder->setRuntimeConfiguration(
        (new RuntimeConfiguration)
        ->addClassMetadataDir('Color', 'some_resource_dir')
        ->addMappingResourceInfo('Color', 'color_es.php', 'inner_php')
);

$resultBuilder->single();

将映射配置绑定到一个属性,特别是

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Customer
{
        /**
         * @DM\Field
         * @DM\Id
         */
        private $id;

        /**
         * @DM\Field(class="Kassko\Sample\Address")
         * @DM\Config(mappingResourceType="yaml", mappingResourceName="billing_address.yml")
         */
        private $billingAddress;//$billingAddress is a value object.

        /**
         * @DM\Field(class="Kassko\Sample\Address")
         * @DM\Config(mappingResourceType="yaml", mappingResourceName="shipping_address.yml")
         */
        private $shippingAddress;//$shippingAddress is a value object too.
}
namespace Kassko\Sample;

class Address
{
        private $street;
        private $town;
        private $postalCode;
        private $country;
}
# billing_address.yml

fields:
        street:
                name: billing_street
        town:
                name: billing_town
        postalCode:
                name: billing_postal_code
        country:
                name: billing_country
# shipping_address.yml

fields:
        street:
                name: shipping_street
        town:
                name: shipping_town
        postalCode:
                name: shipping_postal_code
        country:
                name: shipping_country
$data = [
        'id' => 1,
        'billing_street' => '12 smarties street',
        'billing_town' => 'Nuts',
        'billing_postal_code' => '654321'
        'billing_country' => 'England',
        'shipping_street' => '23 smarties street',
        'shipping_town' => 'Mars',
        'shipping_postal_code' => '987654'
        'shipping_country' => 'England',
];

$dataMapper->resultBuilder('Kassko\Sample\Customer', $data)->single();

请注意,您可以拥有包含值对象的值对象,依此类推。每个值对象都可以使用它自己的映射配置格式。

将源绑定到一个属性或一组属性/从多源、多ORM填充对象

数据源

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Information
{
    /**
     * @DM\DataSource(class="Kassko\Sample\ShopDataSource", method="getBestShop")
     * @DM\Field(class='Kassko\Sample\Shop')
     */
    private $bestShop;

    /**
     * @DM\DataSource(class="Kassko\Sample\ShopDataSource", method="getNbShops")
     */
    private $nbShops;

    public function getBestShop() { return $this->bestShop; }
    public function setBestShop(Shop $shop) { $this->bestShop = $bestShop; }
}
namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Shop
{
    /**
     * @DM\Field
     */
    private $name;

    /**
     * @DM\Field
     */
    private $address;
}
namespace Kassko\Sample;

class ShopDataSource
{
    public function getBestShop()
    {
        return [
            'name' => 'The best',
            'address' => 'Street of the bests',
        ];
    }

    public function getNbShops()
    {
        return 25;
    }
}

方法参数

本节将稍后编写。

懒加载

以下,我们仅在需要时加载属性"bestShop"和"keyboard"。

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;
use Kassko\DataMapper\ObjectExtension\LazyLoadableTrait;

class Information
{
    use LazyLoadableTrait;

        /**
         * @DM\DataSource(class="Kassko\Sample\ShopDataSource", method="getBestShop", lazyLoading=true)
         * @DM\Field(class='Kassko\Sample\Shop')
         */
        private $bestShop;

        /**
         * @DM\DataSource(class="Kassko\Sample\ShopDataSource", method="getNbShops", lazyLoading=true)
         */
        private $nbShops;

        public function getBestShop()
        {
                $this->loadProperty('bestShop');//<= Load the best shop from the property name if not loaded.
                return $this->bestShop;
        }

        public function getNbShop()
        {
                $this->loadProperty('nbShops');//<= Load the best shop from the property name if not loaded.
                return $this->nbShops;
        }
}
namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Shop
{
        /**
         * @DM\Field
         */
        private $name;

        /**
         * @DM\Field
         */
        private $address;
}
namespace Kassko\Sample;

class ShopDataSource
{
    public function getBestShop()
    {
        return [
            'name' => 'The best',
            'address' => 'Street of the bests',
        ];
    }

    public function getNbShops()
    {
        return 25;
    }
}

源存储

给定以下代码

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Person
{
    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", lazyLoading=true, supplySeveralFields=true)
     */
    private $name;

    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", lazyLoading=true, supplySeveralFields=true)
     */
    private $address;

    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", lazyLoading=true, supplySeveralFields=true)
     */
    private $phone;

    /**
     * @DM\DataSource(class="Kassko\Sample\PersonDataSource", method="getData", lazyLoading=true, supplySeveralFields=true)
     */
    private $email;
}
namespace Kassko\Sample;

class PersonDataSource
{
    public function getData()
    {
        return [
            'name' => 'Foo',
            'address' => 'Blue road',
            'phone' => '01 02 03 04 05',
            'email' => 'foo@bar.baz',
        ];
    }
}

我们可以去除重复项

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="some_source", class="Kassko\Sample\PersonDataSource", method="getData", lazyLoading=true
 *      )
 * })
 */
class Person
{
    /**
     * @DM\RefSource(id="some_source")
     */
    private $name;

    /**
     * @DM\RefSource(id="some_source")
     */
    private $address;

    /**
     * @DM\RefSource(id="some_source")
     */
    private $phone;

    /**
     * @DM\RefSource(id="some_source")
     */
    private $email;
}

回退源

在此,sourceB在sourceA不稳定时替换sourceA

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="sourceA", class="Kassko\Sample\ShopDataSource", method="getData", lazyLoading=true,
 *          fallbackSourceId="sourceB", onFail="checkException", exceptionClass="Kassko\Sample\NotStableSourceException"
 *      )
 * })
 */
class Person
{
}

或者

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="sourceA", class="Kassko\Sample\ShopDataSource", method="getData", lazyLoading=true,
 *          fallbackSourceId="sourceB", onFail="checkReturnValue", badReturnValue="null"
 *      )
 * })
 */
class Person
{
}

错误的返回值可能是: "null""false""emptyString""emptyArray"

处理器

namespace Kassko\Sample;

use Kassko\DataMapper\Annotation as DM;

class Key
{
    use LazyLoadableTrait;

    private $note;
    private $octave = 3;

    /**
     * @DM\DataSource(
     * id="ida", 
     * class="Kassko\Samples\KeyLLManager", 
     * method="getData", supplySeveralFields=true,
     * preprocessors = @DM\Methods({
     *  @DM\Method(method="somePreprocessor"),
     *  @DM\Method(class="Kassko\Sample\KeyProcessor", method="preprocess", args="##this")
     * })
     * processors = @DM\Methods({
     *  @DM\Method(method="someProcessor"),
     *  @DM\Method(class="Kassko\Sample\KeyProcessor", method="process", args="##this")
     * })
     *)
     */
    public $color;

    public function getColor() 
    {
        $this->loadProperty('color');
        return $this->color;
    }

    public function somePrepocessor()
    {
        //Some stuff
    }

    public function someProcessor())
    {
        //Some stuff
    }
}
namespace Kassko\Sample;

class KeyPreprocessor
{
    public function preprocess(Key $key)
    {
        $this->logger->info(sprintf('Before key hydration %s', $key->getId()));
    }

    public function process($keyColor)
    {
        $this->logger->info(sprintf('After key hydration %s', $key->getId()));
    }
}

或者

class Key
{
    use LazyLoadableTrait;

    private $note;
    private $octave = 3;

    /**
     * @DM\DataSource(
     * id="ida", 
     * class="Kassko\Samples\KeyLLManager", 
     * method="getData", supplySeveralFields=true,
     * preprocessor = @DM\Method(method="somePreprocessor"),  
     * processor = @DM\Method(method="someProcessor")
     *)
     */
    public $color;

    public function getColor() 
    {
        $this->loadProperty('color');
        return $this->color;
    }

    public function somePrepocessor()
    {
        //Some stuff
    }

    public function someProcessor())
    {
        //Some stuff
    }
}

依赖

depends 包含其他数据源的来源。当您需要确保某个属性已在一个区域中可用时,这很有用。

本节将稍后完成。

处理关系

本节将稍后编写。

如何在客户端代码中实现DataMapper/ResultBuilder无感知

本节将稍后编写。

使用表达式语言

本节将稍后编写。

表达式语言的基本用法

本节将稍后编写。

添加一个功能提供者

本节将稍后编写。

对象监听器

本节将稍后编写。

添加一个自定义映射配置格式

本节将稍后编写。

继承映射配置

本节将稍后编写。

组件配置参考

[
    'mapping' =>
    [
        //Default is "annotations" or other type (1).
        'default_resource_type' => 'annotations',

        //Optional key.
        'default_resource_dir' => 'some_dir',

        //Optional key. Has only sense if you use inner_php or inner_yaml format.
        //It's the method whereby you provide the mapping.
        'default_provider_method' => 'some_method_name',

        //Optional section.
        'groups' =>
        [
            'some_group' =>
            [
                //Default is "annotations" or other type (1).
                'resource_type' => annotations,

                //The resource dir of the given bundle.
                'resource_dir' => 'some_dir',

                //Default value is null.
                'provider_method' => null,
            ],
        ],

        //Optional section
        'objects':
        [
            [
                //Required (the full qualified object class name).
                'class' => 'some_fqcn',

                //Optional key. Allows to inherit settings from a group if there are not specified.
                'group' => 'some_group',

                //Optional key.
                'resource_type' => 'yaml_file',

                //Optional key.
                //The resource directory with the resource name.
                //If not defined, data-mapper fallback to resource_name and prepend to it a resource_dir (this object resource_dir or a group resource_dir or the default_resource_dir).
                //So if resource_path is not defined, keys resource_name and a resource_dir should be defined.
                'resource_path' => 'some_path',

                //Optional key. Only the resource name (so without the directory).
                'resource_name' => 'some_ressource.yml',

                //Optional key. Override default_provider_method.
                'provider_method' => 'some_method_name',
            ],
        ],
    ],

    //Optional section.
    'cache' =>
    [
        //Optional section. The cache for mapping metadata.
        'metadata_cache' =>
        [
            //A cache instance which implements Kassko\Cache\CacheInterface. Default is Kassko\Cache\ArrayCache.
            //If you use a third-party cache provider, maybe you need to wrap it into an adapter to enforce compatibility with Kassko\Cache\CacheInterface.
            'instance' => $someCacheInstance,

            //Default value is 0.
            //0 means the data will never been deleted from the cache.
            //Obviously, 'life_time' has no sense with an "ArrayCache" implementation.
            'life_time' => 0,

            //Default value is false. Indicates if the cache is shared or not.
            //If you don't specify it, you're not wrong. It optimises the
            'is_shared' => false,
        ],

        //Optional section. The cache for query results.
        //This section has the same keys as 'metadata_cache' section.
        'result_cache': => [],
    ],

    //Optional key. A logger instance which implements Psr\Logger\LoggerInterface.
    'logger' => $logger,

    //Optional key. Needed to retrieve repositories specified in 'repository_class' mapping attributes and which creation is assigned to a creator (a factory, a container, a callable).
    'class_resolver' => $someClassResolver,

    //Optional key. Needed to retrieve object listener specified in 'object_listener' mapping attributes and which creation is assigned to a creator (a factory, a container, a callable).
    'object_listener_resolver' => $someObjectListenerResolver,
]

(1) 可用的类型有:annotations、yaml_file、php_file、inner_php、inner_yaml。如果您添加了自定义映射加载器,可能会有其他类型。

映射配置参考

config配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Config(
     *      class="\ValueObjectClass",
     *      mappingResourceName="valueObjectResourceName",
     *      mappingResourcePath="valueObjectResourcePath",
     *      mappingResourceType="valueObjectResourceType"
     * )
     */
    protected $firstField;

Yaml格式

fields: [firstField]
config:
    firstField:
        class: "\\\ValueObjectClass"
        mappingResourceName: valueObjectResourceName
        mappingResourcePath: valueObjectResourcePath
        mappingResourceType: valueObjectResourceType

Php格式

[
    'fields' => ['firstField'],
    'config' => [
        'firstField'    => [
            'class' => '\ValueObjectClass',
            'mappingResourceName' => 'valueObjectResourceName',
            'mappingResourcePath' => 'valueObjectResourcePath',
            'mappingResourceType' => 'valueObjectResourceType'
        ]
    ]
];

CustomHydrator配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * Class SomeClass
 * 
 * @DM\CustomHydrator(
 *      class="SomeClassHydrator",
 *      hydrateMethod="hydrateMethod",
 *      extractMethod="extractMethod"
 * )
 */
class SomeClass
{
}

Yaml格式

object:
  customHydrator:
    class: SomeClassHydrator
    hydrateMethod: hydrateMethod
    extractMethod: extractMethod

Php格式

[
    'object'    => [
        'customHydrator'    => [
            'class' => 'SomeClassHydrator',
            'hydrateMethod' => 'hydrateMethod',
            'extractMethod' => 'extractMethod'
        ]
    ]
];

方法原型

class SomeClassHydrator
{
    /**
     * Hydrate a SomeClass object from raw data $data.
     *
     * @param array The raw data
     * @return SomeClass
     */
    public function hydrateMethod(array $data)
    {
    }

    /**
     * Extract data from a SomeClass instance $object.
     *
     * @param SomeClass The object
     * @return array
     */
    public function extractMethod(SomeClass $object)
    {
    }
}

DataSource配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\DataSource(
     *      id="firstFieldId",
     *      lazyLoading=true,
     *      supplySeveralFields=true,
     *      depends={"depend#1","depend#2"},
     *      onFail="checkException",
     *      exceptionClass="\RuntimeException",
     *      badReturnValue="emptyString",
     *      fallbackSourceId="firstFieldFallbackSourceId",
     *      preprocessor=@DM\Method(method="fooPreprocessor"),
     *      processors = @DM\Methods({
     *          @DM\Method(method="barProcessor"),
     *          @DM\Method(method="bazProcessor")
     *      })
     *      class="\stdClass",
     *      method="someMethod",
     *      args={"argument#1", "argument#2"}
     * )
     */
     protected $firstField;
}

Yaml格式

fields:
    firstField:
        name: originalFieldName
        dataSource:
            id: firstFieldId
            lazyLoading: true
            supplySeveralFields: true
            depends: [depend#1, depend#2]
            onFail: checkException
            exceptionClass: "\\\RuntimeException"
            badReturnValue: emptyString
            fallbackSourceId: firstFieldFallbackSourceId
            preprocessor:
                class: "##this"
                method: fooPreprocessor
                args: []
            processor: ~
            preprocessors: []
            processors: 
                - {method: barProcessor}
                - {method: bazProcessor}
            class: "\\\stdClass"
            method: someMethod
            args: [argument#1, argument#2]

Php格式

[
    'fields' => [
        'firstField' => [
            'name'       => 'originalFieldName',
            'dataSource' => [
                'id'                  => 'firstFieldId',
                'lazyLoading'         => true,
                'supplySeveralFields' => true,
                'depends'             => ['depend#1', 'depend#2'],
                'onFail'              => 'checkException',
                'exceptionClass'      => '\RuntimeException',
                'badReturnValue'      => 'emptyString',
                'fallbackSourceId'    => 'firstFieldFallbackSourceId',
                'preprocessor'        => [
                    'class'  => '##this',
                    'method' => 'fooPreprocessor',
                    'args'   => []
                ],
                'processor'           => [],
                'preprocessors'       => [],
                'processors'          => [
                    ['method' => 'barProcessor'],
                    ['method' => 'bazProcessor'],
                ],
                'class'               => '\stdClass',
                'method'              => 'someMethod',
                'args'                => ['argument#1', 'argument#2']
            ]
        ]
    ]
];

有关“方法配置”的使用方法,请参阅其专用文档 "方法配置"

DataSourcesStore配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="personSource",
 *          class="Kassko\Sample\PersonDataSource",
 *          method="getData",
 *          args="#id",
 *          lazyLoading=true,
 *          supplySeveralFields=true,
 *          onFail="checkException",
 *          exceptionClass="\RuntimeException",
 *          badReturnValue="emptyString",
 *          fallbackSourceId="testFallbackSourceId",
 *          depends="#dependsFirst",
 *          preprocessor = @DM\Method(method="somePreprocessor"),
 *          processor = @DM\Method(method="someProcessor")
 *      )
 * })
 */
class SomeClass
{
}

Yaml格式

object:
    dataSourcesStore:
        - id: personSource
        class: "Kassko\\\Sample\\\PersonDataSource"
        method: getData
        args: [#id]
        lazyLoading: true
        supplySeveralFields: true
        onFail: checkException
        exceptionClass: \RuntimeException
        badReturnValue: emptyString
        fallbackSourceId: testFallbackSourceId
        depends: [#dependsFirst]
        preprocessor:
            class: ""
            method: somePreprocessor
            args: []
        processor:
            class: ""
            method: someProcessor
            args: []

Php格式

[
    'object'    => [
        'dataSourcesStore'    => [
            [
                'id'=> 'personSource',
                'class'=> 'Kassko\Sample\PersonDataSource',
                'method'=> 'getData',
                'args' => ['#id'],
                'lazyLoading' => true,
                'supplySeveralFields' => true,
                'onFail'    => 'checkException',
                'exceptionClass' => '\RuntimeException',
                'badReturnValue' => 'emptyString',
                'fallbackSourceId' => 'testFallbackSourceId',
                'depends' => ['#dependsFirst'],
                'preprocessor' => [
                    'class' => '',
                    'method' => 'somePreprocessor',
                    'args' => []
                ],
                'processor' => [
                    'class' => '',
                    'method' => 'someProcessor',
                    'args' => []
                ]
            ]
        ]
    ]
];

有关“方法配置”的使用方法,请参阅其专用文档 "方法配置"

ExcludeImplicitSource配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\RefImplicitSource(id="RefImplicitSourceId")
 */
class SomeClass
{
    protected $fieldToBindAutoToImplicitSource;

    protected $anotherFieldToBindAutoToImplicitSource;

    /**
     *@DM\ExcludeImplicitSource
     */
    protected $fieldNotToBindAutoToImplicitSource;
}

Yaml格式

object:
    RefImplicitSource: RefImplicitSourceId
fields:
    fieldToBindAutoToImplicitSource:
        name: fieldToBindAutoToImplicitSource
    anotherFieldToBindAutoToImplicitSource:
        name: anotherFieldToBindAutoToImplicitSource
    fieldNotToBindAutoToImplicitSource:
        name: fieldNotToBindAutoToImplicitSource
fieldsNotToBindToImplicitSource: [fieldNotToBindAutoToImplicitSource]

Php格式

[
    'object' => [
        'RefImplicitSource' => 'RefImplicitSourceId'
    ],
    'fields' => [
        'fieldToBindAutoToImplicitSource' => [
            'name'      => 'fieldToBindAutoToImplicitSource',
        ],
        'anotherFieldToBindAutoToImplicitSource' => [
            'name'      => 'anotherFieldToBindAutoToImplicitSource',
        ],
        'fieldNotToBindAutoToImplicitSource' => [
            'name'      => 'fieldNotToBindAutoToImplicitSource',
        ]
    ],
    'fieldsNotToBindToImplicitSource' => [
        'fieldNotToBindAutoToImplicitSource'
    ]
];

Field配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Field(
     *      name="FirstField",
     *      type="string",
     *      class="stdClass",
     *      readConverter="readConvertFirstField",
     *      writeConverter="writeConvertFirstField",
     *      fieldMappingExtensionClass="ExtensionClass"
     * )
     */
    protected $fieldOne;

    /**
     * @DM\Field(
     *      name="SecondField",
     *      type="integer",
     *      class="\DateTime",
     *      readDateConverter="readDateConvertSecondField",
     *      writeDateConverter="writeDateConvertSecondField",
     *      fieldMappingExtensionClass="ExtensionClass",
     *      defaultValue="12"
     * )
     */
    protected $fieldTwo;

    /**
     * @DM\Field(
     *      name="DateField",
     *      type="date"
     * )
     */
    protected $dateField;
}

Yaml格式

fields:
    fieldOne:
        name: FirstField
        type: string
        class: stdClass
        readConverter: readConvertFirstField
        writeConverter: writeConvertFirstField
        fieldMappingExtensionClass: ExtensionClass
    fieldTwo:
        name: SecondField
        type: integer
        class: "\\\DateTime"
        readDateConverter: readDateConvertSecondField
        writeDateConverter: writeDateConvertSecondField
        fieldMappingExtensionClass: ExtensionClass
        defaultValue: 12
    dateField:
        name: DateField
        type: date

Php格式

[
    'fields' => [
        'fieldOne'  => [
            'name'                       => 'FirstField',
            'type'                       => 'string',
            'class'                      => 'stdClass',
            'readConverter'              => 'readConvertFirstField',
            'writeConverter'             => 'writeConvertFirstField',
            'fieldMappingExtensionClass' => 'ExtensionClass',
        ],
        'fieldTwo'  => [
            'name'                       => 'SecondField',
            'type'                       => 'integer',
            'class'                      => '\DateTime',
            'readDateConverter'          => 'readDateConvertSecondField',
            'writeDateConverter'         => 'writeDateConvertSecondField',
            'fieldMappingExtensionClass' => 'ExtensionClass',
            'defaultValue'               => 12
        ],
        'dateField' => [
            'name'                       => 'DateField',
            'type'                       => 'date'
        ]
    ]
];

Getter配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Getter(
     *      name="getterName"
     * )
     */
    protected $firstField;

    /**
     * @DM\Getter(
     *      prefix="is"
     * )
     */
    protected $secondField;
}

Yaml格式

fields:
    firstField:
        name: firstField
        getter: 
            name: getterName
    secondField:
        name: secondField
        getter:
            prefix: is

Php格式

[
    'fields'    => [
        'firstField'    => [
            'name'      => 'firstField',
            'getter'    => ['name' => 'getterName'],
        ],
        'secondField'    => [
            'name'      => 'secondField',
            'getter'    => ['prefix' => 'is'],
        ],
    ]
];

Id配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Id
     */
    protected $firstField;
}

Yaml格式

id: firstField
fields: ["firstField"]

Php格式

[
    'id'        => 'firstField',
    'fields'    => ['firstField']
];

IdCompositePart配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\IdCompositePart
     */
    protected $firstField;

    /**
     * @DM\IdCompositePart
     */
    protected $secondField;
}

Yaml格式

idComposite:    [firstField, secondField]
fields:         [firstField, secondField]

Php格式

[
    'idComposite'   => ['firstField', 'secondField'],
    'fields'    => ['firstField', 'secondField']
];

Listeners配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Listeners(
 *  preHydrate = @DM\Methods({
 *      @DM\Method(class="SomeClass", method="preHydrateMethodName")   
 * }),
 *  postHydrate = @DM\Methods({
 *      @DM\Method(class="SomeClass", method="postHydrateMethodName"),
 *      @DM\Method(class="SomeClassB", method="postHydrateMethodName") 
 * }),
 *  preExtract = @DM\Methods({
 *      @DM\Method(class="SomeClass", method="preExtractMethodName", args="foo")   
 * }),
 *  postExtract = @DM\Methods({
 *      @DM\Method(class="SomeClass", method="postExtractMethodName", args={"foo", "#bar"})   
 * })
 * )
 */
class SomeClass
{
}

Yaml格式

listeners:
    preHydrate: 
        - {class: SomeClass, method: preHydrateMethodName}
    postHydrate: 
        - {class: SomeClass, method: postHydrateMethodName}
        - {class: SomeClassB, method: postHydrateMethodName}
    preExtract: 
        - {class: SomeClass, method: preExtractMethodName, args: foo}
    postExtract: 
        - {class: SomeClass, method: postExtractMethodName, args: ['foo', '#bar']}

Php格式

[
    'listeners' => [
        'preHydrate' => ['class' => 'SomeClass', 'method' => 'preHydrateMethodName'],                
        'postHydrate' => 
        [
            ['class' => 'SomeClass', 'method' => 'postHydrateMethodName'],
            ['class' => 'SomeClassB', 'method' => 'postHydrateMethodName'],
        ], 
        'preExtract' => ['class' => 'SomeClass', 'method' => 'preExtractMethodName', 'args' => 'foo'],
        'postExtract' => ['class' => 'SomeClass', 'method' => 'postExtractMethodName', 'args' => ['foo', '#bar']],
    ]
];

Method配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Method(method="someMethod")
 * @DM\Method(class="SomeClass", method="someMethod", args="abc")
 * @DM\Method(class="@some_object_created_from_factory_or_container", method="someMethod", args= {"##this", "abc"}
 */

Yaml格式

some_key:
    'method': someMethod

some_key:
    class: SomeClass
    method: someMethod
    args: abc

some_key:
    class: @some_object_created_from_factory_or_container
    method: someMethod
    args: ['##this', 'abc']

Php格式

[
    'method' => 'someMethod',
]

[
    'class' => 'SomeClass',
    'method' => 'someMethod',
    'args' => 'abc'
]

[
    'class' => '@some_object_created_from_factory_or_container',
    'method' => 'someMethod',
    'args' => ['##this', 'abc']
]

Object配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(
 *      fieldExclusionPolicy="exclude_all",
 *      providerClass="testProviderClass",
 *      readDateConverter="testReadDateConverter",
 *      writeDateConverter="testWriteDateConverter",
 *      propertyAccessStrategy=true,
 *      fieldMappingExtensionClass="testFieldMappingExtensionClass",
 *      classMappingExtensionClass="testClassMappingExtensionClass"
 * )
 */
class SomeClass
{

}

Yaml格式

fieldExclusionPolicy: exclude_all
object:
    providerClass: testProviderClass
    readDateConverter: testReadDateConverter
    writeDateConverter: testWriteDateConverter
    propertyAccessStrategy: true
    fieldMappingExtensionClass: testFieldMappingExtensionClass
    classMappingExtensionClass: testClassMappingExtensionClass

Php格式

[
    'fieldExclusionPolicy'  => 'exclude_all',
    'object'    => [
        'providerClass'         => 'testProviderClass',
        'readDateConverter'     => 'testReadDateConverter',
        'writeDateConverter'    => 'testWriteDateConverter',
        'propertyAccessStrategy'=> true,
        'fieldMappingExtensionClass' => 'testFieldMappingExtensionClass',
        'classMappingExtensionClass' => 'testClassMappingExtensionClass'
    ]
];

ObjectListeners配置 - 已弃用 - 请参阅监听器配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/** 
 * @DM\ObjectListeners(
 *      classList={"SomeListenerAClass", "SomeListenerBClass"}
 * )
 */
class SomeClass
{
}

Yaml格式

objectListeners: [SomeListenerAClass, SomeListenerBClass]

Php格式

[
    'objectListeners'   => ['SomeListenerAClass', 'SomeListenerBClass']
];

PostExtract配置 - 已弃用 - 请参阅监听器配置

已弃用。请使用 监听器配置 代替。

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(classMappingExtensionClass="mappingExtensionClass")
 *
 * @DM\PostExtract(method="postExtractMethodName")
 */
class SomeClass
{
}

Yaml格式

object:
    classMappingExtensionClass: mappingExtensionClass

interceptors:
    postExtract: postExtractMethodName

Php格式

[
    'object' => ['classMappingExtensionClass' => 'mappingExtensionClass'],
    'interceptors'  => [
        'postExtract'    => 'postExtractMethodName'
    ]
];

PostHydrate配置 - 已弃用 - 请参阅监听器配置

已弃用。请使用 监听器配置 代替。

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(classMappingExtensionClass="mappingExtensionClass")
 *
 * @DM\PostHydrate(method="postHydrateMethodName")
 */
class SomeClass
{
}

Yaml格式

object:
    classMappingExtensionClass: mappingExtensionClass

interceptors:
    postHydrate: postHydrateMethodName

Php格式

[
    'object' => ['classMappingExtensionClass' => 'mappingExtensionClass'],
    'interceptors'  => [
        'postHydrate'    => 'postHydrateMethodName'
    ]
];

PreExtract配置 - 已弃用 - 请参阅监听器配置

已弃用。请使用 监听器配置 代替。

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(classMappingExtensionClass="mappingExtensionClass")
 *
 * @DM\PreExtract(
 *      method="preExtractMethodName"
 * )
 */
class SomeClass
{
}

Yaml格式

object:
    classMappingExtensionClass: mappingExtensionClass

interceptors:
    preExtract: preExtractMethodName

Php格式

[
    'object' => ['classMappingExtensionClass' => 'mappingExtensionClass'],
    'interceptors'  => [
        'preExtract'    => 'preExtractMethodName'
    ]
];

PreHydrate配置 - 已弃用 - 请参阅监听器配置

已弃用。请使用 监听器配置 代替。

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(classMappingExtensionClass="mappingExtensionClass")
 *
 * @DM\PreHydrate(method="preHydrateMethodName")
 */
class SomeClass
{
}

Yaml格式

object:
    classMappingExtensionClass: mappingExtensionClass

interceptors:
    preHydrate: preHydrateMethodName

Php格式

[
    'object' => ['classMappingExtensionClass' => 'mappingExtensionClass'],
    'interceptors'  => [
        'preHydrate'    => 'preHydrateMethodName'
    ]
];

Provider配置 - 已弃用 - 请参阅数据源配置

已弃用。请使用 数据源配置 代替。配置与数据源相同。

ProvidersStore配置 - 已弃用 - 请参阅数据源存储配置

已弃用。请使用 DataSourcesStore 配置 代替。配置与 DataSourceStore 相同。

RefImplicitSource配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\RefImplicitSource(id="RefImplicitSourceId")
 */
class SomeClass
{

}

Yaml格式

object:
    RefImplicitSource: RefImplicitSourceId
fields:
    mockField:
        name: mockFieldName

Php格式

[
    'object' => [
        'RefImplicitSource' => 'RefImplicitSourceId'
    ],
    'fields' => [
        'mockField' => [
            'name'      => 'mockFieldName',
        ]
    ]
];

RefSource配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\DataSourcesStore({
 *      @DM\DataSource(
 *          id="someDataSource",
 *          class="Kassko\Sample\PersonDataSource",
 *          method="getData"
 *      )
 * })
 */
class SomeClass
{
    /**
     * @DM\RefSource(id="someDataSource")
     */
    private $fieldOne;
}

Yaml格式

object:
    dataSourcesStore:
        - id: personSource
        class: "Kassko\\\Sample\\\PersonDataSource"
        method: getData
fields:
    fieldOne:
        name: fieldOne
        refSource: someDataSource

Php格式

[
    'object'    => [
        'dataSourcesStore'    => [
            [
                'id'=> 'personSource',
                'class'=> 'Kassko\Sample\PersonDataSource',
                'method'=> 'getData',
            ]
        ]
    ],
    'fields'    => [
        'fieldOne' => [
            'name'  => 'fieldOne',
            'refSource' => 'someDataSource',
        ]
    ],
];
### Setter config

Annotation format:
```php
use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Setter(
     *      prefix="setterPrefix",
     *      name="setterName"
     * )
     */
    protected $firstField;
}

Yaml格式

fields:
    firstField:
        name: firstField
        setter: 
            name: setterName

Php格式

[
    'fields'    => [
        'firstField'    => [
            'name'      => 'firstField',
            'setter'    => ['name' => 'setterName'],
        ]
    ]
];

ToExclude配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * Optional because it's the default settings for fieldExclusionPolicy.
 * @DM\Object(fieldExclusionPolicy="include_all")
 */
class SomeClass
{
    /**
     * @DM\ToExclude
     */
    protected $excludedField;

    /**
     * @DM\Field
     */
    protected $anotherField;
}

Yaml格式

# Optional because it's the default settings for fieldExclusionPolicy.
# object:
#    fieldExclusionPolicy: include_all
excludedFields: [excludedField]
fields:
  excludedField:
    name: excludedField
  anotherField:
    name: anotherField

Php格式

[
    /*
    //Optional because it's the default settings for fieldExclusionPolicy.
    'object' => [
        'fieldExclusionPolicy' => 'include_all'
    ],
    */
    'excludedFields' => [
        'excludedField'
    ],
    'fields'  => [
        'excludedField' => [
            'name'     => 'excludedField'
        ],
        'anotherField'         => [
            'name'     => 'anotherField'
        ]
    ]
];

ToInclude配置

注解格式

use Kassko\DataMapper\Annotation as DM;

/**
 * @DM\Object(fieldExclusionPolicy="exclude_all")
 */
class SomeClass
{
    /**
     * @DM\Include
     */
    protected $includedField;

    /**
     * @DM\Field
     */
    protected $field;
}

Yaml格式

fieldExclusionPolicy: exclude_all
fieldsToInclude: [includedField]
fields:
    includedField:
        name: includedField
    anotherField:
        name: anotherField

Php格式

[
    'fieldExclusionPolicy' => 'exclude_all'
    'fieldsToInclude' => [
        'includedField'
    ],
    'fields'  => [
        'includedField' => [
            'name'     => 'includedField'
        ],
        'anotherField' => [
            'name'     => 'anotherField'
        ],
    ]
];

Transient配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Transient
     */
    protected $firstField;

    /**
     * @var string
     */
    protected $secondField;
}

Yaml格式

transient: [firstField]
fields: [firstField]

Php格式

[
    'transient' => ['firstField'],
    'fields'    => [
        'firstField'    => [
            'name'      => 'firstFieldName'
        ]
    ]
];

ValueObject 配置 - 已弃用 - 请参阅 Config 配置

已弃用。请使用 Config 配置 代替。

注解格式:注解 @Kassko\DataMapper\Annotation\ValueObject 变更为 @Kassko\DataMapper\Annotation\Config

Yaml 和 Php 格式:现在有一个字段键 'fields.some_field.config'。请使用它而不是全局键 'valueObjects'

注解格式

use Kassko\DataMapper\Annotation as DM;

class ValueObject
{
    /**
     * @DM\Config(
     *      class="\ValueObjectClass",
     *      mappingResourceName="valueObjectResourceName",
     *      mappingResourcePath="valueObjectResourcePath",
     *      mappingResourceType="valueObjectResourceType"
     * )
     */
    protected $firstField;
}

Yaml格式

fields:
  firstField:
    name: firstField
valueObjects:
    firstField:
        class: "\\\ValueObjectClass"
        mappingResourceName: valueObjectResourceName
        mappingResourcePath: valueObjectResourcePath
        mappingResourceType: valueObjectResourceType

Php格式

[
    'fields' => [
        'firstField' => [
            'name'         => 'firstField',
        ]
    ],
    'valueObjects' => [
        'firstField'    => [
            'class' => '\ValueObjectClass',
            'mappingResourceName' => 'valueObjectResourceName',
            'mappingResourcePath' => 'valueObjectResourcePath',
            'mappingResourceType' => 'valueObjectResourceType'
        ]
    ]
];

Version配置

注解格式

use Kassko\DataMapper\Annotation as DM;

class SomeClass
{
    /**
     * @DM\Version
     */
    protected $firstField;
}

Yaml格式

version: firstField
fields: [firstField]

Php格式

[
    'version'   => 'firstField',
    'fields'    => ['firstField']
];

========================================