Skip to content

Commit

Permalink
Merge branch 'feature/fluent-from-property'
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-gerarts committed Apr 14, 2018
2 parents 665deac + 803f87a commit f4768bd
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 2 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,15 @@ $mapping->forMember('id', Operation::ignore());
$mapping->forMember('employee', Operation::mapTo(EmployeeDto::class));
// Explicitly state what the property name is of the source object.
$mapping->forMember('name', Operation::fromProperty('unconventially_named_property'));
// The `FromProperty` operation can be chained with `MapTo`, allowing a
// differently named property to be mapped to a class.
$mapping->forMember(
'address',
Operation::fromProperty('adres')->mapTo(Address::class)
);
```

Example of using the MapFromWithMapper:
Example of using `MapFromWithMapper`:

```php
<?php
Expand Down
82 changes: 81 additions & 1 deletion src/MappingOperation/Implementations/FromProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

namespace AutoMapperPlus\MappingOperation\Implementations;

use AutoMapperPlus\AutoMapperInterface;
use AutoMapperPlus\Configuration\Options;
use AutoMapperPlus\MappingOperation\AlternativePropertyProvider;
use AutoMapperPlus\MappingOperation\DefaultMappingOperation;
use AutoMapperPlus\MappingOperation\MapperAwareOperation;
use AutoMapperPlus\MappingOperation\MappingOperationInterface;
use AutoMapperPlus\MappingOperation\Reversible;
use AutoMapperPlus\NameResolver\CallbackNameResolver;

/**
* Class FromProperty
Expand All @@ -15,8 +18,16 @@
*/
class FromProperty extends DefaultMappingOperation implements
AlternativePropertyProvider,
Reversible
Reversible,
// We need to be mapper aware to be able to pass the mapper to a chained
// operation.
MapperAwareOperation
{
/**
* @var MappingOperationInterface|null
*/
private $nextOperation;

/**
* @var string
*/
Expand Down Expand Up @@ -48,6 +59,22 @@ public function getAlternativePropertyName(): string
return $this->propertyName;
}

/**
* @inheritdoc
*/
public function mapProperty(string $propertyName, $source, $destination): void {
if ($this->nextOperation === null) {
parent::mapProperty($propertyName, $source, $destination);
return;
}

$this->mapPropertyWithNextOperation(
$propertyName,
$source,
$destination
);
}

/**
* @inheritdoc
*/
Expand All @@ -71,4 +98,57 @@ public function getReverseTargetPropertyName
{
return $this->propertyName;
}

/**
* Chain a MapTo operation, making the MapTo use this operation's property
* name instead.
*
* Note: because MapTo is not reversible, the MapTo part gets lost when
* reversing the mapping.
*
* @todo: extend to other operations, or maybe a __call?
*
* @param string $class
* @return FromProperty
*/
public function mapTo(string $class): FromProperty
{
$this->nextOperation = new MapTo($class);
return $this;
}

/**
* @param string $propertyName
* @param $source
* @param $destination
*/
protected function mapPropertyWithNextOperation(
string $propertyName,
$source,
$destination
): void
{
// We have to make the overridden property available to the next
// operation. To do this, we create a "one-time use" name resolver
// to pass to the operation.
$options = clone $this->options;
$options->setNameResolver(new CallbackNameResolver(function () {
return $this->propertyName;
}));
$this->nextOperation->setOptions($options);

// The chained operation will now use the property name assigned to
// FromProperty, so we can go ahead and call it.
$this->nextOperation->mapProperty($propertyName, $source, $destination);
}

/**
* @inheritdoc
*/
public function setMapper(AutoMapperInterface $mapper): void
{
if ($this->nextOperation instanceof MapperAwareOperation) {
$this->nextOperation->setMapper($mapper);
}
}
}
30 changes: 30 additions & 0 deletions test/AutoMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
use AutoMapperPlus\NameConverter\NamingConvention\SnakeCaseNamingConvention;
use AutoMapperPlus\NameResolver\CallbackNameResolver;
use AutoMapperPlus\Test\Models\Inheritance\SourceChild;
use AutoMapperPlus\Test\Models\Nested\Address;
use AutoMapperPlus\Test\Models\Nested\AddressDto;
use AutoMapperPlus\Test\Models\Nested\Person;
use AutoMapperPlus\Test\Models\Nested\PersonDto;
use AutoMapperPlus\Test\Models\SimpleProperties\NoProperties;
use PHPUnit\Framework\TestCase;
use AutoMapperPlus\Test\Models\Employee\Employee;
Expand Down Expand Up @@ -505,4 +509,30 @@ public function testInstanceWithMappingCallback_InstanceIsCorrect()
// Assert
$this->assertEquals($expectedResult, $result->propertyName->name);
}

/**
* @todo: move this to fromPropertyTest.
*/
public function testFromPropertyCanBeChained()
{
$config = new AutoMapperConfig();
$config->registerMapping(Address::class, AddressDto::class)
->forMember('streetAndNumber', function (Address $source) {
return $source->street . ' ' . $source->number;
});
$config->registerMapping(Person::class, PersonDto::class)
->forMember('address', Operation::fromProperty('adres')->mapTo(AddressDto::class))
;
$mapper = new AutoMapper($config);

$address = new Address;
$address->street = "Main Street";
$address->number = 12;
$person = new Person;
$person->adres = $address;

$result = $mapper->map($person, PersonDto::class);

$this->assertEquals("Main Street 12", $result->address->streetAndNumber);
}
}
9 changes: 9 additions & 0 deletions test/Models/Nested/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace AutoMapperPlus\Test\Models\Nested;

class Address
{
public $street;
public $number;
}
8 changes: 8 additions & 0 deletions test/Models/Nested/AddressDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace AutoMapperPlus\Test\Models\Nested;

class AddressDto
{
public $streetAndNumber;
}
8 changes: 8 additions & 0 deletions test/Models/Nested/Person.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace AutoMapperPlus\Test\Models\Nested;

class Person
{
public $adres;
}
9 changes: 9 additions & 0 deletions test/Models/Nested/PersonDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace AutoMapperPlus\Test\Models\Nested;


class PersonDto
{
public $address;
}

0 comments on commit f4768bd

Please sign in to comment.