From 68ab4536dc1685e89106e69650e265bd14bd6828 Mon Sep 17 00:00:00 2001 From: denismacak Date: Sat, 4 Sep 2021 21:37:14 +0200 Subject: [PATCH 1/5] Added syntactic sugar for extending already registered mapping --- src/Configuration/AutoMapperConfig.php | 16 +++++++++ .../AutoMapperConfigInterface.php | 13 +++++++ test/AutoMapperTest.php | 34 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/Configuration/AutoMapperConfig.php b/src/Configuration/AutoMapperConfig.php index 0badcac..e0258bc 100644 --- a/src/Configuration/AutoMapperConfig.php +++ b/src/Configuration/AutoMapperConfig.php @@ -202,6 +202,22 @@ public function registerMapping( return $mapping; } + /** + * @inheritdoc + */ + public function extendMapping( + string $sourceClassName, + string $destinationClassName + ): MappingInterface { + if (!$this->hasMappingFor($sourceClassName, $destinationClassName)) { + throw new \RuntimeException("Undefined mapping for class $sourceClassName"); + } + + $mapping = $this->getMappingFor($sourceClassName, $destinationClassName); + + return $this->registerMapping($sourceClassName, $destinationClassName)->copyFromMapping($mapping); + } + /** * @inheritdoc */ diff --git a/src/Configuration/AutoMapperConfigInterface.php b/src/Configuration/AutoMapperConfigInterface.php index 7eb6d07..a0186cc 100644 --- a/src/Configuration/AutoMapperConfigInterface.php +++ b/src/Configuration/AutoMapperConfigInterface.php @@ -47,6 +47,19 @@ public function registerMapping( string $destinationClassName ): MappingInterface; + /** + * Extends already registered mapping. Whether it's unregistered type + * of mapping or manually registered mapping. + * + * @param string $sourceClassName + * @param string $destinationClassName + * @return MappingInterface + */ + public function extendMapping( + string $sourceClassName, + string $destinationClassName + ): MappingInterface; + /** * @return Options */ diff --git a/test/AutoMapperTest.php b/test/AutoMapperTest.php index 8cc3f61..cd6b5a8 100644 --- a/test/AutoMapperTest.php +++ b/test/AutoMapperTest.php @@ -150,6 +150,40 @@ public function testItCanMapWithACallback() $this->assertEquals('NewName', $destination->name); } + public function testItCanExtendMapping() + { + $this->config->registerMapping(Source::class, Destination::class); + $mapper = new AutoMapper($this->config); + $source = new Source(); + $source->name = 'John'; + $destination = $mapper->map($source, Destination::class); + + $this->assertEquals('John', $destination->name); + + $this->config->extendMapping(Source::class, Destination::class) + ->forMember('name', function (Source $source) { + return $source->name . ' ' . 'Doe'; + }); + $destination = $mapper->map($source, Destination::class); + + $this->assertEquals('John Doe', $destination->name); + } + + public function testItThrowsRuntimeErrorOnExtendMappingWhenDoesntHaveMapping() + { + $this->expectException(\RuntimeException::class); + + $this->config->getOptions()->dontCreateUnregisteredMappings(); + $mapper = new AutoMapper($this->config); + $this->config->extendMapping(Source::class, Destination::class) + ->forMember('name', function (Source $source) { + return $source->name . ' ' . 'Doe'; + }); + $source = new Source(); + $source->name = 'John'; + $mapper->map($source, Destination::class); + } + public function testTheConfigurationCanBeRetrieved() { $config = new AutoMapperConfig(); From 6e3e7b46f476f6933a98c2297ee47853da812953 Mon Sep 17 00:00:00 2001 From: denismacak Date: Sat, 4 Sep 2021 22:02:50 +0200 Subject: [PATCH 2/5] Updated readme --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 09cbf83..c61ec69 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Transfers data from one object to another, allowing custom mapping operations. * [ReverseMap](#reversemap) * [Copying a mapping](#copying-a-mapping) * [Automatic creation of mappings](#automatic-creation-of-mappings) + * [Extending already registered mappings](#extending-already-registered-mappings) * [Resolving property names](#resolving-property-names) * [Naming conventions](#naming-conventions) * [Explicitly state source property](#explicitly-state-source-property) @@ -442,6 +443,24 @@ $config->getOptions()->createUnregisteredMappings(); With this configuration the mapper will generate a very basic mapping on the fly instead of throwing an exception if the mapping is not configured. +### Extending already registered mappings +There are some cases when you want to use unregistered mappings but you want to setup +mapping just for one or few properties of the mapped class without need to define mapping for +each property. In this case you can simply extend mapping and define just those properties +that you need to have mapped differently: + +```php +extendMapping(Employee::class, EmployeeListView::class) + ->forMember('name', function (Employee $employee) { + return strtoupper($employee->name); + }); +``` + +With this configuration the mapper will generate a very basic mapping on the +fly instead of throwing an exception if the mapping is not configured. + ### Resolving property names Unless you define a specific way to fetch a value (e.g. `mapFrom`), the mapper has to have a way to know which source property to map from. By default, it will From 8d675cd5fdef578ec10154ce019f2cfbc8de923f Mon Sep 17 00:00:00 2001 From: denismacak Date: Sat, 4 Sep 2021 22:04:21 +0200 Subject: [PATCH 3/5] Updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c61ec69..e616df0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Transfers data from one object to another, allowing custom mapping operations. * [ReverseMap](#reversemap) * [Copying a mapping](#copying-a-mapping) * [Automatic creation of mappings](#automatic-creation-of-mappings) - * [Extending already registered mappings](#extending-already-registered-mappings) + * [Extending mappings](#extending-mappings) * [Resolving property names](#resolving-property-names) * [Naming conventions](#naming-conventions) * [Explicitly state source property](#explicitly-state-source-property) @@ -443,7 +443,7 @@ $config->getOptions()->createUnregisteredMappings(); With this configuration the mapper will generate a very basic mapping on the fly instead of throwing an exception if the mapping is not configured. -### Extending already registered mappings +### Extending mappings There are some cases when you want to use unregistered mappings but you want to setup mapping just for one or few properties of the mapped class without need to define mapping for each property. In this case you can simply extend mapping and define just those properties From eff092e20ba64a97f30a670c773db7c3fe3eb3db Mon Sep 17 00:00:00 2001 From: denismacak Date: Sat, 4 Sep 2021 22:05:00 +0200 Subject: [PATCH 4/5] Removed leftover --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e616df0..93da93b 100644 --- a/README.md +++ b/README.md @@ -452,7 +452,7 @@ that you need to have mapped differently: ```php extendMapping(Employee::class, EmployeeListView::class) +$config->extendMapping(Employee::class, EmployeeListView::class) ->forMember('name', function (Employee $employee) { return strtoupper($employee->name); }); From 5ba5be325cc42a03dd4509ced145099dc6422868 Mon Sep 17 00:00:00 2001 From: denismacak Date: Sat, 4 Sep 2021 22:26:40 +0200 Subject: [PATCH 5/5] Removed leftover --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 93da93b..04c2b04 100644 --- a/README.md +++ b/README.md @@ -458,9 +458,6 @@ $config->extendMapping(Employee::class, EmployeeListView::class) }); ``` -With this configuration the mapper will generate a very basic mapping on the -fly instead of throwing an exception if the mapping is not configured. - ### Resolving property names Unless you define a specific way to fetch a value (e.g. `mapFrom`), the mapper has to have a way to know which source property to map from. By default, it will