gfg / dto-context
负责根据创建的上下文创建对象,以处理数据完整性
1.0.11
2016-08-26 17:23 UTC
Requires (Dev)
- pdepend/pdepend: @stable
- phploc/phploc: @stable
- phpmd/phpmd: @stable
- phpunit/php-invoker: @stable
- phpunit/phpunit: @stable
- sebastian/phpcpd: @stable
- squizlabs/php_codesniffer: @stable
- sstalle/php7cc: @stable
README
简介
在处理实体的数据表示时,我们经常会发现需要检查和验证一组参数,这些参数取决于将要执行的操作。这些参数会根据要执行的操作而变化。通常,这会导致大量代码,以确保该特定操作的所有信息实际上都存在。
概念
DTO Context(数据传输对象)的主要思想是有一个实体的单一数据表示,在这种情况下称为 DataWrapper,其中包含实体可以拥有的所有内容,以及一个称为 Context 的对象,该对象表示实体将能够执行的动作上下文。例如:一个名为 Person 的实体,具有一些属性,如姓名、年龄、身高和体重,以及执行创建、更新姓名、增加年龄、更改国籍等操作的几个动作。对于这些动作中的任何一个,实体本身都是相同的,但是在更新姓名的情况下,不需要确保体重或身高已被填写。更新姓名的动作上下文知道这一点,知道执行该操作所需的全部内容,以及为该操作进行操作所需的所有内容。
除了封装特定动作的数据之外,每个上下文还会自动添加一些元数据,这可能非常有用,例如上下文名称和上下文唯一哈希,该哈希在数据导出时生成。
结构
Context //The context object where the rules and parameters are stored
├─ Base.php //Contains all the basic methods for a Context to be implemented
└─ ContextInterface.php //Every context must implement this interface
DataWrapper //The data representation of the system entities
├─ Base.php //Contains all the basic actions that are needed for a datawrapper to work properly
├─ BaseCollection.php //A container for a collection of datawrappers
└─ DataWrapperInterface.php //Every datawrapper should implement this interface
Factory //Responsible for creating the contexts properly
├─ Base.php //All the basic actions to perform context creation
├─ FactoryInterface.php //All context factories should implement this interface
├─ Hydrator.php //Class responsible to rebuild a context based on the exported version of it
└─ HydratorInterface.php //All Hydrators must implement this interface
Manager.php //A manager to intermediate the requests to control contexts, this allows flexibility, adding custom factories and hydrators to attend specific needs
使用示例
该库本身提供支持,以扩展并实现特定场景的上下文逻辑。假设上述提到的Person上下文示例。要使用DTO-Context实现它,请遵循以下步骤
- 创建上下文工厂;
- 创建数据包装器;
- 创建上下文。
建议的结构
建议的结构应用作可组合的库。
src\MyDTO
└─ Context
├─ Factory.php
└─ Person
├─ CreatePerson.php
├─ UpdateName.php
└─ ...
DataWrapper
└─ Person.php
1. ContextFactory
<?php namespace MyDTO\Context; use \GFG\DTOContext\Factory\Base; class Factory extends Base { /** * we map the contexts that the we'll be using, * this can be very useful to identify in one place all the related * actions of an entity */ const PERSON_CREATE = 'person.create'; const PERSON_UPDATE_NAME = 'person.update.name'; const PERSON_UPDATE_HEIGHT = 'person.update.height'; const PERSON_UPDATE_WEIGHT = 'person.update.weight'; const PERSON_INCREASE_AGE = 'person.update.age'; // ... /** * Points to which class this context will use */ private $mappingList = [ self::PERSON_CREATE = 'MyDTO\Context\Person\CreatePerson', self::PERSON_UPDATE_NAME = 'MyDto\Context\Person\UpdateName', self::PERSON_UPDATE_HEIGHT = 'MyDto\Context\Person\UpdateHeight', self::PERSON_UPDATE_WEIGHT = 'MyDto\Context\Person\UpdateWeight', self::PERSON_INCREASE_AGE = 'MyDto\Context\Person\IncreaseAge', // ... ]; public getMappingList() { return self::$mappingList; } }
2. DataWrapper
<?php namespace MyDTO\DataWrapper; use \GFG\DTOContext\DataWrapper\Base; /** * @SuppressWarnings(PHPMD.UnusedPrivateField) * @method string getName() * @method integer getHeight() * @method integer getWeight() * @method integer getAge() * @method string getNacionality() * @method \MyDTO\DataWrapper\Person setName(string $name) * @method \MyDTO\DataWrapper\Person setHeight(integer $height) * @method \MyDTO\DataWrapper\Person setWeight(integer $weight) * @method \MyDTO\DataWrapper\Person setAge(integer $age) * @method \MyDTO\DataWrapper\Person setNacionality(string $nationality) */ class Person extends Base { private $name; private $height; private $weight; private $age; private $nationality; }
3. Contexts
创建Person上下文
<?php namespace MyDTO\Context; use \GFG\DTOContext\Context\ContextInterface; class CreatePerson extends ContextInterface { /** * In this method, we'll use only the data that is needed for * this action */ public function exportContextData() { $dataWrapper = $this->getDataWrapper(); return $this->prepareExport([ 'name' => $dataWrapper->getName(), 'height' => $dataWrapper->getHeight(), 'weight' => $dataWrapper->getWeight(), 'age' => $dataWrapper->getAge(), 'nationality' => $dataWrapper->getNacionality() ]); } }
更新姓名
<?php namespace MyDTO\Context; use \GFG\DTOContext\Context\ContextInterface; class UpdateName extends ContextInterface { public function exportContextData() { $dataWrapper = $this->getDataWrapper(); return $this->prepareExport([ 'name' => $dataWrapper->getName() ]); } }
实现
<?php use \GFG\DTOContext\Context\Manager; use \MyDTO\Context\Factory; use \MyDto\DataWrapper\Person; $manager = (new Manager()) ->setFactory(new Factory); $context = $manager->build( Factory::PERSON_CREATE, new Person([ 'name' => 'John Armless', 'height' => 180, 'weight' => 90, 'age' => 20, 'nationality' => 'Brazilian' ]) ); // also, you can add some extra information to be sent with the metadata // any set method will be used to store information, later captured by the // corresponding get method $context->setAccessCode('access code');
上下文的组成
如前所述,有一些元数据可以增加使用DTO-Context封装数据的优势。
<?php $exportedData = $context->exportContextData(); /* $exportedData = Array( 'name' => 'mydto.context.person.createperson' //this name is generated based on the namespace of the context 'info' => ['AccessCode' => 'access code'] //extra information 'hash' => 'ff17fea5e96ea2401372805b763fb182' //this hash is an unique hash generated for each instance, specially useful for tracking purposes 'data_wrapper' => 'MyDTO\DataWrapper\Person' //which datawrapper this context is using 'data' => Array( 'name' => 'John Armless', 'height' => 180, 'weight' => 90, 'age' => 20, 'nationality' => 'Brazilian' ) //all the data that was exported ); */ ?>
有了这个导出数据的数组,可以重建完全相同的上下文,这在许多方面都非常有用,例如在服务器之间记录请求,因为重建时的哈希将保持不变。
<?php use \GFG\DTO-Context\Factory\Hydrator; $rebuiltContext = $manager->rebuild($exportedData, new Hydrator);