Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'$this' as $sourcePropertyName means complete source object #60

Merged
33 changes: 23 additions & 10 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ To set a default value for a property, you can use the `default` keyword:
```yaml
# config/packages/neusta_converter.yaml
neusta_converter:
converter:
person.converter:
properties:
target: YourNamespace\Person
phoneNumber:
source: phone
default: '0123456789'
converter:
person.converter:
properties:
target: YourNamespace\Person
phoneNumber:
source: phone
default: '0123456789'
```

The converter will set the value of `phoneNumber` (property of the target object) to `0123456789` if
Expand Down Expand Up @@ -221,7 +221,7 @@ Conversion done.
## Special Populators

After working a while with the converter pattern, you will notice that many scenarios in the population are very similar.
If the source property can be copied directly to the target property, but only the names of the properties change,
If the source property can be copied directly to the target property, but only the names of the properties change,
the same populator could be reused over and over again.

### Converting Populator
Expand Down Expand Up @@ -258,7 +258,7 @@ class Person
}
```

If you have a situation as above and your `User` will have an `Address` which should be populated into `Person`,
If you have a situation as above and your `User` will have an `Address` which should be populated into `Person`,
then you have to write a Populator which

* gets the `Address` from `User`,
Expand Down Expand Up @@ -293,9 +293,20 @@ person.address.populator:
Be aware - that both properties have the same name should not lead you think they have the same type.
There is really an object conversion behind done by `address.converter`.

If you specify the `sourcePropertyName` as an empty string, the full `source` object is used for the population.

Especially in connection with the `ConvertingPopulator` this is sometimes necessary.

#### Special case

In very rare situations it could happen that you want to use the complete source object for population of a special
attribute/property of your target object. In these case you can not define a source property name for the accessor but
you can use `'$this'` and the `ConvertingPopulator` (internally the `PropertyMappingPopulator` will use the object
`$source` itself as value.)

### ArrayConvertingPopulator

If you think that there is no 1:1 relation between `User` and `Address` (or corresponding Person and PersonAddress)
If you think that there is no 1:1 relation between `User` and `Address` (or corresponding Person and PersonAddress)
but a 1:n relation then the `ConvertingPopulator` cannot be used.

In these cases we have implemented an extended version of it called `ArrayConvertingPopulator`.
Expand Down Expand Up @@ -341,6 +352,7 @@ class Person
```

Now you have to declare the following populator:

```yaml
# config/packages/neusta_converter.yaml
neusta_converter:
Expand All @@ -361,6 +373,7 @@ person.addresses.populator:
$sourcePropertyName: 'addresses'
$targetPropertyName: 'addresses'
```

There is no new converter but a different populator implementation for this.

## Context
Expand Down
4 changes: 3 additions & 1 deletion src/Populator/PropertyMappingPopulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public function __construct(
public function populate(object $target, object $source, ?object $ctx = null): void
{
try {
$value = $this->accessor->getValue($source, $this->sourceProperty) ?? $this->defaultValue;
$value = '$this' !== $this->sourceProperty
? $this->accessor->getValue($source, $this->sourceProperty) ?? $this->defaultValue
: $source;

if (!$this->skipNull || (null !== $value)) {
$this->accessor->setValue($target, $this->targetProperty, ($this->mapper)($value, $ctx));
Expand Down
19 changes: 18 additions & 1 deletion tests/Populator/PropertyMappingPopulatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
use Neusta\ConverterBundle\Tests\Fixtures\Model\Source\Address;
use Neusta\ConverterBundle\Tests\Fixtures\Model\Source\User;
use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\Person;
use Neusta\ConverterBundle\Tests\Fixtures\Model\Target\PersonAddress;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;

class PropertyMappingPopulatorTest extends TestCase
{
use ProphecyTrait;

public function test_populate(): void
public function test_populate_a_certain_source_property(): void
{
$populator = new PropertyMappingPopulator(
targetProperty: 'age',
Expand Down Expand Up @@ -92,4 +93,20 @@ public function test_populate_skip_null_with_sub_fields_and_null_safety(): void

self::assertSame('Old City', $target->getPlaceOfResidence());
}

public function test_populate_whole_source_object(): void
{
$populator = new PropertyMappingPopulator('address', '$this');
$address = (new PersonAddress())
->setStreet('Street')
->setStreetNo('1')
->setCity('Capitol City')
->setPostalCode('12345');

$person = new Person();

$populator->populate($person, $address);

self::assertSame($address, $person->getAddress());
}
}