diff --git a/src/Mapper.php b/src/Mapper.php index 773910b..d396034 100644 --- a/src/Mapper.php +++ b/src/Mapper.php @@ -54,6 +54,11 @@ abstract class Mapper implements MapperInterface { */ private $validation; + /** + * @var array + */ + private $skipAttributes; + /** * @return string */ @@ -159,6 +164,23 @@ public function setValidation($validation) { return $this; } + /** + * @param array $attributes + * @return $this + */ + public function setSkipAttributes(array $attributes = []) { + $this->skipAttributes = $attributes; + + return $this; + } + + /** + * @return array + */ + public function getSkipAttributes() { + return $this->skipAttributes; + } + /** * @param string|object $outputClassOrObject * @param integer $adapter @@ -166,7 +188,8 @@ public function setValidation($validation) { public function __construct($outputClassOrObject, $adapter = self::MEMORY_ANNOTATION_ADAPTER) { $this->setOutputClassOrObject($outputClassOrObject) ->setAnnotationAdapterType($adapter) - ->setValidation(true); + ->setValidation(true) + ->setSkipAttributes(); } /** diff --git a/src/Mapper/Structure.php b/src/Mapper/Structure.php index 095a53d..7bc1c41 100644 --- a/src/Mapper/Structure.php +++ b/src/Mapper/Structure.php @@ -12,7 +12,7 @@ \Phalcon\Annotations\Adapter\Xcache, \PhMap\Mapper, - \PhMap\Transforms, + \PhMap\Transform, \PhMap\Exception\UnknownAnnotationAdapter, \PhMap\Exception\FieldValidator\UnknownField as UnknownFieldException, \PhMap\Exception\FieldValidator\MustBeSimple as MustBeSimpleException, @@ -203,19 +203,21 @@ public function map() { $transform = $this->getTransforms() ? $this->getTransforms()->findByInputFieldName($attribute) : null; $transformedAttribute = $transform ? $transform->getOutputFieldName() : $attribute; + if ($this->needToSkip($transformedAttribute)) { + continue; + } + $setter = $this->createSetter($transformedAttribute); if ($this->hasAttribute($transformedAttribute)) { /** @var Annotations $methodAnnotations */ $methodAnnotations = $methodsAnnotations[$setter]; - $childTransforms = $transform ? $transform->getTransforms() : null; - $valueToMap = $this->buildValueToMap( $transformedAttribute, $value, $methodAnnotations, - $childTransforms + $transform ); if (!is_null($valueToMap)) { @@ -231,11 +233,51 @@ public function map() { return $this->getOutputObject(); } + /** + * @return array + */ + protected function getCurrentSkipAttributes() { + static $currentSkipAttributes = []; + + if (empty($currentSkipAttributes)) { + foreach ($this->getSkipAttributes() as $attribute) { + $attributes = explode('.', $attribute); + if (count($attributes) === 1) { + $currentSkipAttributes[] = array_pop($attributes); + } + } + } + + return $currentSkipAttributes; + } + + protected function getSkipAttributesByParent($parentAttribute) { + $skipAttributes = []; + + foreach ($this->getSkipAttributes() as $skipAttribute) { + $parentAttributeWithDelimiter = $parentAttribute . '.'; + + if (strpos($skipAttribute, $parentAttributeWithDelimiter) === 0) { + $skipAttributes[] = str_replace($parentAttributeWithDelimiter, '', $skipAttribute); + } + } + + return $skipAttributes; + } + + /** + * @param $attribute + * @return boolean + */ + protected function needToSkip($attribute) { + return in_array($attribute, $this->getSkipAttributes()); + } + /** * @param string $attribute * @param mixed $value * @param Annotations $methodAnnotations - * @param Transforms|null $transforms + * @param Transform|null $transform * @return mixed * @throws MustBeSimpleException * @throws MustBeSequenceException @@ -245,7 +287,7 @@ protected function buildValueToMap( $attribute, $value, Annotations $methodAnnotations, - Transforms $transforms = null + Transform $transform = null ) { $valueToMap = $value; @@ -255,6 +297,10 @@ protected function buildValueToMap( $mapperAnnotationClass = $mapperAnnotation->getArgument('class'); $mapperAnnotationIsArray = $mapperAnnotation->getArgument('isArray'); + $transforms = $transform ? $transform->getTransforms() : null; + + $skipAttributes = $this->getSkipAttributesByParent($attribute); + if ($this->isObject($value)) { if ($mapperAnnotationIsArray) { if ($this->getValidation()) { @@ -266,20 +312,28 @@ protected function buildValueToMap( /** @var object|array $value */ /** @var Mapper $mapper */ $mapper = new static($value, $mapperAnnotationClass); - $valueToMap = $mapper->setTransforms($transforms) + $valueToMap = $mapper + ->setTransforms($transforms) ->setValidation($this->getValidation()) + ->setSkipAttributes($skipAttributes) ->map(); } } else { if ($mapperAnnotationIsArray) { $validation = $this->getValidation(); - $valueToMap = array_map(function($value) use ($mapperAnnotationClass, $transforms, $validation) { + $valueToMap = array_map(function($value) use ( + $mapperAnnotationClass, + $transforms, + $validation, + $skipAttributes + ) { /** @var object|array $value */ /** @var Mapper $mapper */ $mapper = new static($value, $mapperAnnotationClass); return $mapper ->setTransforms($transforms) ->setValidation($validation) + ->setSkipAttributes($skipAttributes) ->map(); }, $value); } elseif ($this->getValidation()) { diff --git a/src/MapperInterface.php b/src/MapperInterface.php index 171821d..218bd1f 100644 --- a/src/MapperInterface.php +++ b/src/MapperInterface.php @@ -67,6 +67,17 @@ public function enableValidation(); */ public function getValidation(); + /** + * @param array $attributes + * @return $this + */ + public function setSkipAttributes(array $attributes = []); + + /** + * @return array + */ + public function getSkipAttributes(); + /** * @return object */ diff --git a/src/Wrapper.php b/src/Wrapper.php index b00641b..bae3704 100644 --- a/src/Wrapper.php +++ b/src/Wrapper.php @@ -135,6 +135,25 @@ public function enableValidation() { return $this; } + /** + * @param array $attributes + * @return $this + */ + public function setSkipAttributes(array $attributes = []) { + $this->getMapper() + ->setSkipAttributes($attributes); + + return $this; + } + + /** + * @return array + */ + public function getSkipAttributes() { + return $this->getMapper() + ->getSkipAttributes(); + } + /** * @return object */ diff --git a/tests/AssociativeMapperTest.php b/tests/AssociativeMapperTest.php index c17e629..9a3a577 100644 --- a/tests/AssociativeMapperTest.php +++ b/tests/AssociativeMapperTest.php @@ -115,6 +115,31 @@ public function testTransforms() { $this->assertEquals($objectMapped, self::getTree()); } + /** + * @return void + */ + public function testSkipAttributes() { + $inputStructure = self::getTreeDecodedToArray(); + + $skipAttributes = [ + 'name', + 'branch.length' + ]; + + $objectMapped = (new Associative($inputStructure, new Tree(), Mapper::FILES_ANNOTATION_ADAPTER)) + ->setSkipAttributes($skipAttributes) + ->map(); + $this->assertEquals( + $objectMapped, + self::getTree() + ->setName(null) + ->setBranch( + self::getBranch() + ->setLength(null) + ) + ); + } + /** * @throws \PhMap\Exception\FieldValidator\MustBeSimple * @return void diff --git a/tests/JsonMapperTest.php b/tests/JsonMapperTest.php index 0e50960..ce9a439 100644 --- a/tests/JsonMapperTest.php +++ b/tests/JsonMapperTest.php @@ -112,6 +112,31 @@ public function testTransforms() { $this->assertEquals($objectMapped, self::getTree()); } + /** + * @return void + */ + public function testSkipAttributes() { + $inputStructure = self::getTreeJson(); + + $skipAttributes = [ + 'name', + 'branch.length' + ]; + + $objectMapped = (new Json($inputStructure, new Tree(), Mapper::FILES_ANNOTATION_ADAPTER)) + ->setSkipAttributes($skipAttributes) + ->map(); + $this->assertEquals( + $objectMapped, + self::getTree() + ->setName(null) + ->setBranch( + self::getBranch() + ->setLength(null) + ) + ); + } + /** * @throws \PhMap\Exception\FieldValidator\MustBeSimple * @return void diff --git a/tests/ObjectMapperTest.php b/tests/ObjectMapperTest.php index 5cf6e3b..6afa689 100644 --- a/tests/ObjectMapperTest.php +++ b/tests/ObjectMapperTest.php @@ -125,6 +125,31 @@ public function testTransforms() { $this->assertEquals($objectMapped, self::getTree()); } + /** + * @return void + */ + public function testSkipAttributes() { + $inputStructure = self::getTree(); + + $skipAttributes = [ + 'name', + 'branch.length' + ]; + + $objectMapped = (new Object($inputStructure, new Tree(), Mapper::FILES_ANNOTATION_ADAPTER)) + ->setSkipAttributes($skipAttributes) + ->map(); + $this->assertEquals( + $objectMapped, + self::getTree() + ->setName(null) + ->setBranch( + self::getBranch() + ->setLength(null) + ) + ); + } + /** * @throws \PhMap\Exception\FieldValidator\MustBeSimple * @return void