- Notifications
You must be signed in to change notification settings - Fork32
mark-gerarts/automapper-plus
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
An automapper for PHP inspired by.NET's automapper.Transfers data from one object to another, allowing custom mapping operations.
- Installation
- Why?
- Example usage
- In depth
- Similar libraries
- See also
- A note on PHPStan
- Roadmap
This library is available onpackagist:
$ composer require"mark-gerarts/auto-mapper-plus"If you're using Symfony, check out theAutoMapper+ bundle.
When you need to transfer data from one object to another, you'll have to writea lot of boilerplate code. For example when using view models, CommandBuscommands, working with API responses, etc.
Automapper+ helps you by automatically transferring properties from one objectto another,including private ones. By default, properties with the same namewill be transferred. This can be overridden as you like.
Suppose you have a class Employee and an associated DTO.
<?phpclass Employee{private$id;private$firstName;private$lastName;private$birthYear;publicfunction__construct($id,$firstName,$lastName,$birthYear) {$this->id =$id;$this->firstName =$firstName;$this->lastName =$lastName;$this->birthYear =$birthYear; }publicfunctiongetId() {return$this->id; }// And so on...}class EmployeeDto{// While the properties are public for this example, we can map to private// or protected properties just the same.public$firstName;public$lastName;public$age;}
The following snippet provides a quick overview on how the mapper can beconfigured and used:
<?phpuseAutoMapperPlus\Configuration\AutoMapperConfig;useAutoMapperPlus\AutoMapper;$config =newAutoMapperConfig();// Simply registering the mapping is enough to convert properties with the same// name. Custom actions can be registered for each individual property.$config ->registerMapping(Employee::class, EmployeeDto::class) ->forMember('age',function (Employee$source) {returndate('Y') -$source->getBirthYear(); }) ->reverseMap();// Register the reverse mapping as well.$mapper =newAutoMapper($config);// With this configuration we can start converting our objects.$john =newEmployee(10,"John","Doe",1980);$dto =$mapper->map($john, EmployeeDto::class);echo$dto->firstName;// => "John"echo$dto->lastName;// => "Doe"echo$dto->age;// => 37
The AutoMapper has to be provided with anAutoMapperConfig, which holds theregistered mappings. This can be done in 2 ways:
Passing it to the constructor:
<?phpuseAutoMapperPlus\Configuration\AutoMapperConfig;useAutoMapperPlus\AutoMapper;$config =newAutoMapperConfig();$config->registerMapping(Source::class, Destination::class);$mapper =newAutoMapper($config);
Using the static constructor:
<?php$mapper = AutoMapper::initialize(function (AutoMapperConfig$config) {$config->registerMapping(Source::class, Destination::class);$config->registerMapping(AnotherSource::class, Destination::class);// ...});
Once configured, using the AutoMapper is pretty straightforward:
<?php$john =newEmployee("John","Doe",1980);// Map the source object to a new instance of the destination class.$mapper->map($john, EmployeeDto::class);// Mapping to an existing object is possible as well.$mapper->mapToObject($john,newEmployeeDto());// Map a collection using mapMultiple$mapper->mapMultiple($employees, EmployeeDto::class);
Mappings are defined using theAutoMapperConfig'sregisterMapping() method.By default, every mapping has to be explicitly defined before you can use it.
A mapping is defined by providing the source class and the destination class.The most basic definition would be as follows:
<?php$config->registerMapping(Employee::class, EmployeeDto::class);
This will allow objects of theEmployee class to be mapped toEmployeeDtoinstances. Since no extra configuration is provided, the mapping will onlytransfer properties with the same name.
With theforMember() method, you can specify what should happen for the givenproperty of the destination class. When you pass a callback to this method, thereturn value will be used to set the property.
The callback receives the source object as argument.
<?php$config->registerMapping(Employee::class, EmployeeDto::class) ->forMember('fullName',function (Employee$source) {return$source->getFirstName() .'' .$source->getLastName(); });
Behind the scenes, the callback in the previous example is wrapped in aMapFrom operation. Operations represent the action that should be performedfor the given property.
The following operations are provided:
| Name | Explanation |
|---|---|
| MapFrom | Maps the property from the value returned from the provided callback. Gets passed the source object, an instance of the AutoMapper and optionally thecurrent context. |
| Ignore | Ignores the property. |
| MapTo | Maps the property to another class. Allows fornested mappings. Supports both single values and collections. |
| MapToAnyOf | Similar toMapTo, but maps the property to the first match from a list of classes. This can be used forpolymorphic properties. Supports both single values and collections. |
| FromProperty | Use this to explicitly state the source property name. |
| DefaultMappingOperation | Simply transfers the property, taking into account the provided naming conventions (if there are any). |
| SetTo | Always sets the property to the given value |
You can use them with the sameforMember() method. TheOperation class canbe used for clarity.
<?php$getName =function ($source,AutoMapperInterface$mapper) {return'John'; };$mapping->forMember('name',$getName);// The above is a shortcut for the following:$mapping->forMember('name', Operation::mapFrom($getName));// Which in turn is equivalent to:$mapping->forMember('name',newMapFrom($getName));// Other examples:// Ignore this property.$mapping->forMember('id', Operation::ignore());// Map this property to the given class.$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));// SetTo sets the property to the given value.$mapping->forMember('type', Operation::setTo('employee'));// An extended example showing you can access the mapper in `MapFrom`.$getColorPalette =function(SimpleXMLElement$XMLElement,AutoMapperInterface$mapper) {/** @var SimpleXMLElement $palette */$palette =$XMLElement->xpath('/product/specification/palette/colour');return$mapper->mapMultiple($palette, Color::class);};$mapping->forMember('palette',$getColorPalette);
MapTo requires some extra explanation. Since lists and maps are the same datastructure in PHP (arrays), we can't reliably distinct between the two.MapTotherefore accepts a second parameter,$sourceIsObjectArray, a boolean valuethat indicates whether the source value should be interpreted as a collection,or as an associative array representing an object. By default we assume acollection or a single non-array value.
<?php// This assumes address is an object, or a collection of mappable// objects if the source is an array/iterable.$mapping->forMember('address', Operation::mapTo(Address::class));// This is equivalent to:$mapping->forMember('address', Operation::mapTo(Address::class,false));// If you want to be very specific about the source being a collection, you// can use `mapCollectionTo`. This is purely syntactic sugar; it is equivalent// to the declarations above as well.$mapping->forMember('addresses', Operation::mapCollectionTo(Address::class));// On the other hand, if the source is an array that represents an object, you// can use the following:$mapping->forMember('address', Operation::mapTo(Address::class,true));// Or nicer$mapping->forMember('address', Operation::mapArrayTo(Address::class));
You can create your own operations by implementing theMappingOperationInterface. Take a look at theprovided implementationsfor some inspiration.
If you need to have the automapper available in your operation, you canimplement theMapperAwareInterface, and use theMapperAwareTrait. ThedefaultMapTo andMapFrom operations use these.
Sometimes you have properties which contain a list of different types of objectse.g. when you load all entities withsingle table inheritance. You can useMapToAnyOf to map every object to a possible different one. Keep in mindthat the mapping for the child class has to be registered as well. The sourceproperty can be both a single value or a collection.
<?php// This iterates over every property of the source property// 'polymorphicChildren'. Each value will be mapped to the first existing// mapping from the value to one of the given classes.$config->createMapping(ChildA::class, ChildADto::class);$config->createMapping(ChildB::class, ChildBDto::class);$config->createMapping(Parent::class, ParentDto::class) ->forMember('polymorphicChildren', Operation::mapToAnyOf([ChildADto::class, ChildBDto::class] ));
Nested mappings can be registered using theMapTo operation. Keep in mind that the mapping for thechild class has to be registered as well.
MapTo supports both single entities and collections.
<?php$config->registerMapping(Child::class, ChildDto::class);$config->registerMapping(Parent::class, ParentDto::class) ->forMember('child', Operation::mapTo(ChildDto::class));
You can specify how the new destination object will be constructed (this isn'trelevant if you usemapToObject). You can do this by registering afactorycallback. This callback will be passed both the source object and an instanceof the AutoMapper.
<?php$config->registerMapping(Source::class, Destination::class) ->beConstructedUsing(function (Source$source,AutoMapperInterface$mapper):Destination {returnnewDestination($source->getProperty()); });
Another option is to skip the constructor all together. This can be set usingthe options.
<?php// Either set it in the options:$config->getOptions()->skipConstructor();$mapper =newAutoMapper($config);// Or set it on the mapping directly:$config->registerMapping(Source::class, Destination::class)->skipConstructor();
Since it is a common use case to map in both directions, thereverseMap()method has been provided. This creates a new mapping in the alternate direction.
reverseMap will keep the registered naming conventions into account, if thereare any.
<?php// reverseMap() returns the new mapping, allowing to continue configuring the// new mapping.$config->registerMapping(Employee::class, EmployeeDto::class) ->reverseMap() ->forMember('id', Operation::ignore());$config->hasMappingFor(Employee::class, EmployeeDto::class);// => True$config->hasMappingFor(EmployeeDto::class, Employee::class);// => True
Note:reverseMap() simply creates a completely new mapping in the reversedirection, using the default options. However, every operation you defined withforMember that implements theReversible interface, gets defined for the newmapping as well. Currently, onlyfromProperty supports being reversed.
To make things more clear, take a look at the following example:
<?php// Source class properties: Destination class properties:// - 'some_property', - 'some_property'// - 'some_alternative_property' - 'some_other_property'// - 'the_last_property' - 'the_last_property'//$config->registerMapping(Source::class, Destination::class) ->forMember('some_property', Operation::ignore()) ->forMember('some_other_property', Operation::fromProperty('some_alternative_property')) ->reverseMap();// When mapping from Source to Destination, the following will happen:// - some_property gets ignored// - some_other_property gets mapped by using the value form some_alternative_property// - the_last_property gets mapped because the names are equal.//// Now, when we go in the reverse direction things are different:// - some_property gets mapped, because Ignore is not reversible// - some_alternative_property gets mapped because FromProperty is reversible// - the_last_property gets mapped as well
When defining different view models, it can occur that you have lots of similarproperties. For example, with a ListViewModel and a DetailViewModel. This meansthat the mapping configuration will be similar as well.
For this reason, it is possible to copy a mapping. In practice this means thatall the options will be copied, and all the explicitly defined mappingoperations.
After copying the mapping, you're free to override operations or options on thenew mapping.
<?php$detailMapping =$config->registerMapping(Employee::class, EmployeeDetailView::class)// Define operations and options ... ->forMember('age',function () {return20; });// You can copy a mapping by passing source and destination class. This will// search the config for the relevant mapping.$listMapping =$config->registerMapping(Employee::class, EmployeeListView::class) ->copyFrom(Employee::class, EmployeeDetailView::class)// Alternatively, copy a mapping by passing it directly.// ->copyFromMapping($detailMapping)//// You can now go ahead and define new operations, or override existing// ones. ->forMember('name', Operation::ignore()) ->skipConstructor();
When you're dealing with very simple mappings that don't require anyconfiguration, it can be quite cumbersome the register a mapping for each andevery mapping. For these cases it is possible to enable the automatic creationof mappings:
<?php$config->getOptions()->createUnregisteredMappings();
With this configuration the mapper will generate a very basic mapping on thefly instead of throwing an exception if the mapping is not configured.
Unless you define a specific way to fetch a value (e.g.mapFrom), the mapperhas to have a way to know which source property to map from. By default, it willtry to transfer data between properties of the same name. There are, however, afew ways to alter this behaviour.
If a source property isspecifically defined(e.g.FromProperty), this will be used in all cases.
You can specify the naming conventions followed by the source & destinationclasses. The mapper will take this into account when resolving names.
For example:
<?phpuseAutoMapperPlus\NameConverter\NamingConvention\CamelCaseNamingConvention;useAutoMapperPlus\NameConverter\NamingConvention\SnakeCaseNamingConvention;$config->registerMapping(CamelCaseSource::class, SnakeCaseDestination::class) ->withNamingConventions(newCamelCaseNamingConvention(),// The naming convention of the source class.newSnakeCaseNamingConvention()// The naming convention of the destination class. );$source =newCamelCaseSource();$source->propertyName ='camel';$result =$mapper->map($source, SnakeCaseDestination::class);echo$result->property_name;// => "camel"
The following conventions are provided (more to come):
- CamelCaseNamingConvention
- PascalCaseNamingConvention
- SnakeCaseNamingConvention
You can implement your own by using theNamingConventionInterface.
As mentioned earlier, the operationFromProperty allows you to explicitlystate what property of the source object should be used.
<?php$config->registerMapping(Source::class, Destination::class) ->forMember('id', Operation::fromProperty('identifier'));
You should read the previous snippet as follows:"For the property named 'id'on the destination object, use the value of the 'identifier' property of thesource object".
FromProperty isReversible, meaning that when you applyreverseMap(),AutoMapper will know how to map between the two properties. For more info, readthesection aboutreverseMap.
Should naming conventions and explicitly stating property names not besufficient, you can resort to aCallbackNameResolver (or implement your ownNameResolverInterface).
ThisCallbackNameResolver takes a callback as an argument, and will use thisto transform property names.
<?phpclass Uppercase{public$IMAPROPERTY;}class Lowercase{public$imaproperty;}$uppercaseResolver =newCallbackNameResolver(function ($targetProperty) {returnstrtolower($targetProperty);});$config->registerMapping(Uppercase::class; Lowercase::class) ->withNameResolver($uppercaseResolver);$uc =newUppercase();$uc->IMAPROPERTY ='value';$lc =$mapper->map($uc, Lowercase::class);echo$lc->imaproperty;// => "value"
TheOptions object is a value object containing the possible options for boththeAutoMapperConfig and theMapping instances.
TheOptions you set for theAutoMapperConfig will act as the default optionsfor everyMapping you register. These options can be overridden for everymapping.
For example:
<?php$config =newAutoMapperConfig();$config->getOptions()->setDefaultMappingOperation(Operation::ignore());$defaultMapping =$config->registerMapping(Source::class, Destination::class);$overriddenMapping =$config->registerMapping(AnotherSource::class, Destination::class) ->withDefaultOperation(newDefaultMappingOperation());$defaultMapping->getOptions()->getDefaultMappingOperation();// => Ignore$overriddenMapping->getOptions()->getDefaultMappingOperation();// => DefaultMappingOperation
The available options that can be set are:
| Name | Default value | Comments |
|---|---|---|
| Source naming convention | null | The naming convention of the source class (e.g.CamelCaseNamingConversion). Also seenaming conventions. |
| Destination naming convention | null | See above. |
| Skip constructor | true | whether or not the constructor should be skipped when instantiating a new class. Use$options->skipConstructor() and$options->dontSkipConstructor() to change. |
| Property accessor | PropertyAccessor | Use this to provide an alternative implementation of the property accessor. A property accessor combines the reading and writing of properties |
| Property reader | PropertyAccessor | Use this to provide an alternative implementation of the property reader. |
| Property writer | PropertyAccessor | Use this to provide an alternative implementation of the property writer. |
| Default mapping operation | DefaultMappingOperation | the default operation used when mapping a property. Also seemapping operations |
| Default name resolver | NameResolver | The default class to resolve property names |
| Custom Mapper | null | Grants the ability to use acustom mapper. |
| Object crates | [\stdClass::class] | Seethe dedicated section. |
| Ignore null properties | false | Sets whether or not a source property should be mapped to the destination object if the source value is null |
| Use substitution | true | Whether or not the Liskov substitution principle should be applied when resolving a mapping. |
| createUnregisteredMappings | false | Whether or not an exception should be thrown for unregistered mappings, or a mapping should be generated on the fly. |
You can set the options for theAutoMapperConfig by retrieving the object:
<?php$config =newAutoMapperConfig();$config->getOptions()->dontSkipConstructor();
Alternatively, you can set the options by providing a callback to theconstructor. The callback will be passed an instance of the defaultOptions:
<?php// This will set the options for this specific mapping.$config =newAutoMapperConfig(function (Options$options) {$options->dontSkipConstructor();$options->setDefaultMappingOperation(Operation::ignore());// ...});
A mapping also has thegetOptions method available. However, chainable helpermethods exist for more convenient overriding of the options:
<?php$config->registerMapping(Source::class, Destination::class) ->skipConstructor() ->withDefaultOperation(Operation::ignore());
Setting options via a callable has been provided for mappings as well, using thesetDefaults() method:
<?php$config->registerMapping(Source::class, Destination::class) ->setDefaults(function (Options$options) {$options->dontSkipConstructor();// ... });
As a side note it is worth mentioning that it is possible to map from and tostdClass. MappingfromstdClass happens as you would expect, copyingproperties to the new object.
<?php// Register the mapping.$config->registerMapping(\stdClass::class, Employee::class);$mapper =newAutoMapper($config);$employee =new \stdClass();$employee->firstName ='John';$employee->lastName ='Doe';$result =$mapper->map($employee, Employee::class);echo$result->firstName;// => "John"echo$result->lastName;// => "Doe"
Mappingto\stdClass requires some explanation. All properties available onthe provided source object are copied to the\stdClass as public properties.It's still possible to define operations for individual properties (for example,to ignore a property).
<?php// Operations can still be registered.$config->registerMapping(Employee::class, \stdClass::class) ->forMember('id', Operation::ignore());$mapper =newAutoMapper($config);$employee =newEmployee(5,'John','Doe',1978);$result =$mapper->map($employee, \stdClass::class);echo$result->firstName;// => "John"echo$result->lastName;// => "Doe"var_dump(isset($result->id));// => bool(false)
Naming conventions will be taken into account, so keep this in mind whendefining operations. The property name has to match the naming convention of thetarget.
<?php$config->registerMapping(CamelCaseSource::class, \stdClass::class) ->withNamingConventions(newCamelCaseNamingConvention(),newSnakeCaseNamingConvention() )// Operations have to be defined using the target property name. ->forMember('some_property',function () {return'new value'; });$mapper =newAutoMapper($config);$source =newCamelCaseSource();$source->someProperty ='original value';$source->anotherProperty ='Another value';$result =$mapper->map($employee, \stdClass::class);var_dump(isset($result->someProperty));// => bool(false)echo$result->some_property;// => "new value"echo$result->another_property;// => "Another value"
As suggested and explained inthis issue,AutoMapper+ usesobject crates to allow mapping to\stdClass. This means youcan register your own classes as well to be an object crate. This makes themapper handle it exactly as\stdClass, writing all source properties to publicproperties on the target.
Registering object crates can be done using theOptions.
<?phpclass YourObjectCrate { }$config =newAutoMapperConfig();// (Or pass a callable to the constructor)$config->getOptions()->registerObjectCrate(YourObjectCrate::class);$config->registerMapping(Employee::class, YourObjectCrate::class);$mapper =newAutoMapper($config);$employee =newEmployee(5,'John','Doe',1978);$result =$mapper->map($employee, YourObjectCrate::class);echo$result->firstName;// => "John"echo$result->lastName;// => "Doe"echoget_class($result);// => "YourObjectCrate"
It is possible to map associative arrays into objects (shout-out to @slava-v).This can be done just like you would declare a regular mapping:
<?php$config->registerMapping('array', Employee::class);// Alternatively, use the enum DataType::ARRAY// Adding operations works just as you would expect.$config->registerMapping(DataType::ARRAY, Employee::class) ->forMember('id', Operation::ignore()) ->forMember('type', Operation::setTo('employee'))// Since arrays are oftentimes snake_case'd. ->withNamingConventions(newSnakeCaseNamingConvention(),newCamelCaseNamingConvention() );// It is now possible to map an array to an employee:$employee = ['id' =>5,'first_name' =>'John','last_name' =>'Doe'];$result =$mapper->map($employee, Employee::class);echo$result->firstName;// => "John"echo$result->id;// => nullecho$result->type;// => "employee"
See theMapTo section underOperations for some more detailsabout the intricacies involving this operation in combination with arrays.
As for now, it is not possible to mapto an array. While this is relativelyeasy to implement, it would introduce a breaking change. It is part of version2.x, so check there if you need this feature.
This library attempts to make registering mappings painless, with as littleconfiguration as possible. However, cases exist where a mapping requires a lotof custom code. This code would look a lot cleaner if put in its own class.Another reason to resort to a custom mapper would beperformance.
It is therefore possible to specify a custom mapper class for a mapping. Thismapper has to implement theMapperInterface. For your convenience, aCustomMapper class has been provided that implements this interface.
<?php// You can either extend the CustomMapper, or just implement the MapperInterface// directly.class EmployeeMapperextends CustomMapper{/** * @param Employee $source * @param EmployeeDto $destination * @return EmployeeDto */publicfunctionmapToObject($source,$destination) {$destination->id =$source->getId();$destination->firstName =$source->getFirstName();$destination->lastName =$source->getLastName();$destination->age =date('Y') -$source->getBirthYear();return$destination; }}$config->registerMapping(Employee::class, EmployeeDto::class) ->useCustomMapper(newEmployeeMapper());$mapper =newAutoMapper($config);// The AutoMapper can now be used as usual, but your custom mapper class will be// called to do the actual mapping.$employee =newEmployee(10,'John','Doe',1980);$result =$mapper->map($employee, EmployeeDto::class);
Sometimes a mapping should behave differently based on the context. It istherefore possible to pass a third argument to the map methods to describethe current context. Both theMapFrom andMapTo operations can make use ofthis context to alter their behaviour.
The context argument is an array that can contain any arbitrary value. Notethat this argument isn't part of theAutoMapperInterface yet, since it wouldbreak backwards compatibility. It will be added in the next major release.
<?php// This example shows how for example the current locale can be passed to alter// the mapping behaviour.$config->registerMapping(Employee::class, EmployeeDto::class) ->forMember('honorific',function ($source,AutoMapperInterface$mapper,array$context):string {$translationKey ="honorific.{$source->getGender()}";return$this->translator->trans($translationKey,$context['locale']); } );// Usage:$mapper->map($employee, EmployeeDto::class, ['locale' =>$request->getLocale()]);
When using themapToObject method, the context will contain the destinationobject by default. It is accessible using$context[AutoMapper::DESTINATION_CONTEXT].This is useful in scenarios where you need data from the destination objectto populate the object you're mapping.
When implementing a custom constructor, the context will contain the destinationclass by default. It is accessible using$context[AutoMapper::DESTINATION_CLASS_CONTEXT].
When mapping an object graph, the context will also contain arrays for propertyname paths, ancestor source objects and ancestor destination objects. Those arraysare accessible using$context[AutoMapper::PROPERTY_STACK_CONTEXT],$context[AutoMapper::SOURCE_STACK_CONTEXT] and$context[AutoMapper::DESTINATION_STACK_CONTEXT].They can be used to implement custom mapping function based on the hierarchy level and current positioninside the object graph being mapped.
- Passing
NULLas an argument for the source object tomapreturnsNULL.
When picking a library, it's important to see what options are available. Nolibrary is perfect, and they all have their pro's and con's.
A few other object mappers exist for PHP. They're listed here with a shortdescription, and are definitely worth checking out!
- Jane automapper:
- Similar API
- Compiles mappings, resulting in near-native performance
- Nylle/PHP-AutoMapper:
- Only maps public properties
- Requires some conventions to be met
- Does some interesting stuff with types
- Papper:
- Convention based
- High performance
- Lacks in documentation
- BCCAutoMapperBundle:
- Only available as a Symfony bundle (<3.0)
- Very similar to this project
- Does some cool stuff with graph mapping
Performance benchmarks (credit goes toidr0id):
Runtime: PHP 7.2.9-1
Host: Linux 4.18.0-2-amd64 #1 SMP Debian 4.18.10-2 (2018-11-02) x86_64
Collection size: 100000
| package | duration (MS) | MEM (B) |
|---|---|---|
| native php | 32 | 123736064 |
| mark-gerarts/auto-mapper-plus (custom mapper) | 92 | 123736064 |
| jane-php/automapper (optimized) | 100 | 123736064 |
| jane-php/automapper | 136 | 123736064 |
| idr0id/papper | 310 | 123736064 |
| trismegiste/alkahest | 424 | 113250304 |
| mark-gerarts/auto-mapper-plus | 623 | 123736064 |
| nylle/php-automapper | 642 | 123736064 |
| bcc/auto-mapper-bundle | 2874 | 123736064 |
Up-to-date benchmarks can be foundhere.
Note that using a custom mapper is very fast. So when performance really startsto matter in your application, you can easilyimplement a custom mapperwhere needed, without needing to change the code that uses the mapper.
Because of an issue describedhere,PHPStan reports the following error if you use the$context parameter:
Method AutoMapperPlus\MapperInterface::map() invoked with 3 parameters, 2 required.If you see this error, you should enable theAutoMapper+ extension.Please note that this is a temporary solution. The issue will be fixed in the2.0 release.
- Provide a more detailed tutorial
- Create a sample app demonstrating the automapper
- Allow mapping from
stdClass, - or perhaps even an associative array (could have)
- Allow mapping to
stdClass - Provide options to copy a mapping
- Allow setting of prefix for name resolver (seeautomapper)
- Create operation to copy value from property
- Allow passing of contructor function
- Allow configuring of options in AutoMapperConfig -> error when trying with a registered mapping
- Consider: passing of options to a single mapping operation
- MapTo: allow mapping of collection
- Clean up the property checking in the Mapping::forMember() method.
- Refactor tests
- Allow setting a maximum depth, see #14
- Provide a NameResolver that accepts an array mapping, as an alternative to multiple
FromPropertys - Make use of a decorated Symfony's
PropertyAccessor(see#16) - Allow adding of middleware to the mapper
- Allow mappingto array
Version 2 is in the works, check there for new features as well
About
An AutoMapper for PHP
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Contributors9
Uh oh!
There was an error while loading.Please reload this page.