-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
514 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# `#[MapTo]` and `#[MapFrom]` attributes | ||
|
||
The `#[MapTo]` and `#[MapFrom]` attributes allow you to define the mapping between a property of the source and the target object. | ||
|
||
Respectively, the `#[MapTo]` attribute is used on a property of the `source` object, and the `#[MapFrom]` attribute | ||
is used on a property of the `target` object. | ||
|
||
They both allow the same arguments, but since you can map to or from a generic data structure, they may be needed | ||
depending on the context. | ||
|
||
## Usage | ||
|
||
They can be used on : | ||
|
||
* a public or private property (also in promoted properties) | ||
|
||
```php | ||
class Entity | ||
{ | ||
#[MapTo(name: 'name')] | ||
public string $title; | ||
} | ||
``` | ||
|
||
* a public or private method | ||
|
||
``` | ||
class EntityDto | ||
{ | ||
private string $name; | ||
#[MapFrom(name: 'title')] | ||
public function setName($name): void | ||
{ | ||
$this->name = $name; | ||
} | ||
} | ||
``` | ||
|
||
* a class (to add virtual properties) | ||
|
||
``` | ||
#[MapTo(name: 'virtualProperty')] | ||
class Entity {} | ||
``` | ||
|
||
## Specifying the target or source | ||
|
||
The `#[MapTo]` and `#[MapFrom]` attributes allow you to specify on which target or source this attribute should be applied. | ||
You can use this attribute multiple times on the same property to handle behavior for different targets or sources. | ||
|
||
```php | ||
class Entity | ||
{ | ||
#[MapTo(target: EntityDto::class, name: 'name')] | ||
#[MapTo(target: 'array', name: 'title')] | ||
public string $title; | ||
} | ||
``` | ||
|
||
|
||
|
||
```php | ||
class EntityDto | ||
{ | ||
#[MapFrom(source: Entity::class, name: 'title')] | ||
#[MapFrom(source: 'array', name: 'name')] | ||
public string $name; | ||
} | ||
``` | ||
|
||
> [!WARNING] | ||
> If multiple `#[MapTo]` and/or `#[MapFrom]` attributes target the same property an exception will be thrown. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Conditional Mapping | ||
|
||
Ignoring a property is a good way to exclude it from the mapping process, but sometimes you may want to map a property conditionally. | ||
This can be done using the `#[MapTo]` or `#[MapFrom]` attributes with the `if` argument. | ||
|
||
The argument may accept several types of values: | ||
|
||
### Expression language | ||
|
||
You can use the Symfony Expression Language to define the condition. | ||
In this context the `source` object is available as `source` and the `context` array is available as `context`. | ||
|
||
```php | ||
class Source | ||
{ | ||
public bool $propertyIsValid = true; | ||
|
||
#[MapTo(if: 'source.propertyIsValid and (context["custom_key"] ?? false) == true')] | ||
public $property; | ||
} | ||
``` | ||
|
||
If you use the Bundle version of the AutoMapper, there is also [additional functions available](../bundle/expression-language.md). | ||
|
||
> [!NOTE] | ||
> In standalone mode we do not provide any functions to the expression language. | ||
> However we are interested in adding some functions to the expression language in the future. If you have some use | ||
> cases that you would like to see covered, please open an issue on the GitHub repository. | ||
### PHP function | ||
|
||
You can use a php function to define the condition. This function must return a boolean value. | ||
|
||
```php | ||
class Source | ||
{ | ||
#[MapTo(if: 'boolval')] | ||
public string $property = ''; | ||
} | ||
``` | ||
|
||
> [!WARNING] | ||
> If the PHP function need more arguments than the `source` object and the `context` array, it will throw an exception. | ||
### Static callback | ||
|
||
You can use a static callback to define the condition. | ||
|
||
```php | ||
class Source | ||
{ | ||
public bool $propertyIsValid = true; | ||
|
||
#[MapTo(if: [self::class, 'isPropertyValid'])] | ||
public $property; | ||
|
||
public static function isPropertyValid(Source $source, array $context): bool | ||
{ | ||
return $source->propertyIsValid && ($context['custom_key'] ?? false) === true; | ||
} | ||
} | ||
``` | ||
|
||
The static callback can accept the `source` object and the `context` array as arguments. | ||
|
||
### Dynamic callback | ||
|
||
You can also reference a method of the object declaring the attribute to define the condition. | ||
|
||
```php | ||
class Source | ||
{ | ||
public bool $propertyIsValid = true; | ||
|
||
#[MapTo(if: 'isPropertyValid')] | ||
public $property; | ||
|
||
public function isPropertyValid(): bool | ||
{ | ||
return $this->propertyIsValid; | ||
} | ||
} | ||
``` | ||
|
||
The dynamic callback can accept the `source` object and the `context` array as arguments. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Groups | ||
|
||
In addition to use the Symfony Serializer `#[Groups]` attribute, you can also use the `#[MapTo]` and `#[MapFrom]` | ||
attributes to define groups of properties that should be mapped. | ||
|
||
```php | ||
class Source | ||
{ | ||
#[MapTo(target: 'array', groups: ['group1', 'group2'])] | ||
public $groupedProperty; | ||
} | ||
``` | ||
|
||
When doing so the property will be mapped only if the context contains at least one group defined in the `groups` argument. | ||
|
||
### Cumulative groups | ||
|
||
When using both groups from the Symfony Serializer `#[Groups]` attribute and the `groups` argument from the `#[MapTo]` | ||
or `#[MapFrom]` attributes, the latter groups will override the former groups. | ||
|
||
```php | ||
use Symfony\Component\Serializer\Attribute\Groups; | ||
|
||
class Source | ||
{ | ||
#[Groups(['group1', 'group2'])] | ||
#[MapTo(target: 'array', groups: ['group3'])] | ||
public $groupedProperty; | ||
} | ||
``` | ||
|
||
In this case the property will be mapped only if the context contains the `group3` group. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Ignoring properties | ||
|
||
Sometimes you may want to ignore a property during the mapping process. This can be done using the `#[MapTo]` or `#[MapFrom]` attributes | ||
with the `ignore` argument set to `true`. | ||
|
||
```php | ||
class Source | ||
{ | ||
#[MapTo(target: SourceDTO::class, ignore: true)] | ||
#[MapTo(target: 'array', ignore: false)] | ||
public $ignoredProperty; | ||
} | ||
``` | ||
|
||
Setting `ignore` to `false` may be useful when used in conjunction with the `#[Ignore]` attribute from the Symfony Serializer. | ||
|
||
```php | ||
use Symfony\Component\Serializer\Attribute\Ignore; | ||
|
||
class Source | ||
{ | ||
#[Ignore] | ||
#[MapTo(target: SourceDTO::class, ignore: false)] | ||
public $ignoredProperty; | ||
} | ||
``` | ||
|
||
In this case the property will be mapped to the `SourceDTO` class, but will be ignored when using the Symfony Serializer. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Inheritance Mapping | ||
|
||
A `source` or `target` class may inherit from another class. | ||
|
||
When creating the mapping, AutoMapper can determine the correct mapping by using the inheritance information from | ||
the Symfony Serializer `#[DiscriminatorMap]` attribute. | ||
|
||
```php | ||
#[DiscriminatorMap(typeProperty: 'type', mapping: [ | ||
'cat' => Cat::class, | ||
'dog' => Dog::class, | ||
'fish' => Fish::class, | ||
])] | ||
abstract class Pet | ||
{ | ||
/** @var string */ | ||
public $type; | ||
|
||
/** @var string */ | ||
public $name; | ||
|
||
/** @var PetOwner */ | ||
public $owner; | ||
} | ||
``` | ||
|
||
When mapping a `Pet` object, AutoMapper will automatically determine the correct class to instantiate based on the `type` property. | ||
|
||
[Learn more about the Symfony Serializer inheritance mapping](https://symfony.com/doc/current/components/serializer.html#serializing-interfaces-and-abstract-classes) | ||
|
||
> [!NOTE] | ||
> If you don't use the Symfony Serializer we do not provide, yet, any way to determine the correct class to instantiate. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,87 @@ | ||
### Normalizer Bridge 🌁 | ||
# Symfony Serializer Attributes | ||
|
||
A Normalizer Bridge is available, aiming to be 100% feature compatible with the ObjectNormalizer of the | ||
``symfony/serializer`` component. The goal of this bridge **is not to replace the ObjectNormalizer** but rather | ||
providing a very fast alternative. | ||
Symfony Serializer is a powerful component that can serialize and deserialize objects to and from various formats. | ||
It can use several attributes to customize the serialization process. | ||
|
||
When this component is available, AutoMapper can use these attributes to customize the mapping process. | ||
|
||
### `#[Groups]` | ||
|
||
The Symfony Serializer `#[Groups]` attribute can be used to define groups of properties that should be mapped. | ||
|
||
```php | ||
use Symfony\Component\Serializer\Attribute\Groups; | ||
|
||
class Source | ||
{ | ||
#[Groups(['group1', 'group2'])] | ||
public $groupedProperty; | ||
} | ||
``` | ||
|
||
>! [!WARNING] | ||
> When both `target` and `source` objects have groups, the property will be mapped only if the context contains at least | ||
> one group from the `target` object and one group from the `source` object. | ||
[More information on the Groups attribute](https://symfony.com/doc/current/components/serializer.html#attributes-groups) | ||
|
||
### `#[Ignore]` | ||
|
||
The Symfony Serializer `#[Ignore]` attribute can be used to ignore a property during the mapping process. | ||
|
||
```php | ||
use Symfony\Component\Serializer\Attribute\Ignore; | ||
|
||
class Source | ||
{ | ||
#[Ignore] | ||
public $ignoredProperty; | ||
} | ||
``` | ||
|
||
[More information on the Ignore attribute](https://symfony.com/doc/current/components/serializer.html#ignoring-attributes) | ||
|
||
### `#[MaxDepth]` | ||
|
||
The Symfony Serializer `#[MaxDepth]` attribute can be used to limit the depth of the serialization process. | ||
|
||
```php | ||
use Symfony\Component\Serializer\Attribute\MaxDepth; | ||
|
||
class Source | ||
{ | ||
#[MaxDepth(1)] | ||
public $nestedProperty; | ||
} | ||
``` | ||
|
||
[More information on the MaxDepth attribute](https://symfony.com/doc/current/components/serializer.html#handling-serialization-depth) | ||
|
||
### Name converters | ||
|
||
AutoMapper can use the Symfony Serializer name converters to convert the property names, when mapping to | ||
or from an array. | ||
|
||
```php | ||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; | ||
|
||
$autoMapper = AutoMapper::create(nameConverter: new CamelCaseToSnakeCaseNameConverter()); | ||
``` | ||
|
||
[More information on the Name converters](https://symfony.com/doc/current/components/serializer.html#converting-property-names-when-serializing-and-deserializing) | ||
|
||
### Normalizer Bridge | ||
|
||
Additionally, this library provide a normalizer which implements the `Symfony\Component\Serializer\Normalizer\NormalizerInterface` | ||
interface. | ||
|
||
It's goal is to be as close as possible to the `ObjectNormalizer` of the `symfony/serializer` component, but with a focus on | ||
performance. | ||
|
||
```php | ||
use AutoMapper\Normalizer\AutoMapperNormalizer; | ||
use Symfony\Component\Serializer\Serializer; | ||
|
||
$autoMapper = AutoMapper::create(); | ||
$serializer = new Serializer([new AutoMapperNormalizer($autoMapper)]); | ||
``` |
Oops, something went wrong.