Download the PHP package symfonycasts/micro-mapper without Composer
On this page you can find all versions of the php package symfonycasts/micro-mapper. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download symfonycasts/micro-mapper
More information about symfonycasts/micro-mapper
Files in symfonycasts/micro-mapper
Package micro-mapper
Short Description A tiny, underwhelming data mapper to map one object to another!
License MIT
Informations about the package micro-mapper
MicroMapper: The Tiny, Underwhelming Data Mapper for Symfony!
Need to map one object (e.g. a Doctrine entity) to another object (e.g. a DTO) and love writing the mapping code manually? Then this library is for you!
Define a "mapper" class:
Then... map!
MicroMapper is similar to other data mappers, like jolicode/automapper, except... less impressive! Jane's Automapper is awesome and handles a lot of heavy lifting. With MicroMapper, you do the heavy lifting. Let's review with a table!
| Feature | MicroMapper | Jane's Automapper |
|---|---|---|
| Some of the mapping is automatic | ❌ | ✅ |
| Extensible | ✅ | ✅ |
| Handles nested objects | ✅ | ✅ |
| Small & Dead-simple | ✅ | (not SO simple) |
Support us & Symfony
Is this package useful! We're thrilled 😍!
A lot of time & effort from the Symfonycasts team & the Symfony community goes into creating and maintaining these packages. You can support us + Symfony (and learn a bucket-load) by grabbing a subscription to SymfonyCasts!
Installation
If you're using Symfony, you're done! If not, see Stand-alone Library Setup.
Usage
Suppose you have a Dragon entity, and you want to map it to a
DragonApi object (perhaps to use with API Platform, like we do
in our Api Platform EP3 Tutorial).
Step 1: Create the Mapper Class
To do this, create a "mapper" class that defines how to map:
The mapper class has three parts:
#[AsMapper]attribute: defines the "from" and "to" classes (needed for Symfony usage only).load()method: creates/loads the "to" object - e.g. load it from the database or create it and populate just the identifier.populate()method: populates the "to" object with data from the "from" object.
Step 2: Use the MicroMapper Service
To use the mapper, you can fetch the MicroMapperInterface service. For
example, from a controller:
Reverse Transforming
To do the reverse transformation - DragonApi to Dragon - it's
the same process: create a mapper class:
The mapper:
In this case, the load() method fetches the Dragon entity from the
database if it has an id property.
Handling Nested Objects
If you have nested objects, you can use the MicroMapperInterface to map
those too. Suppose the Dragon entity has a treasures property
that is a OneToMany relation to Treasure entity. And in DragonApi, we have
a treasures property that should hold an array of TreasureApi objects.
First, create a mapper for the Treasure -> TreasureApi mapping:
Next, in the DragonEntityToApiMapper, use the MicroMapperInterface to map the
Treasure objects to TreasureApi objects:
That's it! The result will be a DragonApi object with a treasures property
that holds an array of TreasureApi objects.
MAX_DEPTH & Circular References
Imagine now that TreasureEntityToApiMapper also maps a dragon
property on the TreasureApi object:
This creates a circular reference: the Dragon entity is mapped to a
DragonApi object... which then maps its treasures property to an array
of TreasureApi objects... which then each map their dragon property to a
DragonApi object... forever... and ever... and ever...
The MAX_DEPTH option tells MicroMapper how many levels deep to
go when mapping, and you usually want to set this to 0 or 1 when mapping a
relation.
When the max depth is hit, the load() method will be called on the mapper
for that level but populate() will not be called. This results in a
"shallow" mapping of the final level object.
Let's look at a few depth examples using this code:
MAX_DEPTH = 0: Because the depth is immediately hit, theDragonentity will be mapped to aDragonApiobject by calling theload()method onDragonEntityToApiMapper. But thepopulate()method will not be called. This means that the finalDragonApiobject will have anidbut no other data.
Result:
MAX_DEPTH = 1: TheDragonentity will be fully mapped to aDragonApiobject: both theload()andpopulate()methods will be called on its mapper like normal. However, when eachTreasureinDragon.treasuresis mapped to aTreasureApiobject, this will be "shallow": theTreasureApiobject will have anidproperty but no other data (because the max depth was hit and so onlyload()is called onTreasureEntityToApiMapper).
Result:
In something like API Platform, you can also use MAX_DEPTH to limit the
depth of the serialization for performance. For example, if the TreasureApi
object has a dragon property that is expressed as the IRI string (e.g.
/api/dragons/1), then setting MAX_DEPTH to 0 is enough and prevents
extra mapping work.
Settable Collection Relations on Entities
In our example, the Dragon entity has a treasures property that is a
OneToMany relation to the Treasure entity. Our DTO classes have
the same relation: DragonApi holds an array of TreasureApi objects.
Those greedy dragons!
If you want to map a DragonApi object to the Dragon entity and
the DragonApi.treasures property may have changed, you need to
update the Dragon.treasures properly carefully.
For example, this will not work:
The problem is with the $entity->setTreasures() call. In fact, this method probably
doesn't even exist on the Dragon entity! Instead, it likely has addTreasure() and
removeTreasure() methods and these must be called instead so that the "owning"
side of the Doctrine relationship is correctly set (otherwise the changes won't save).
An easy way to do this is with the PropertyAccessorInterface service:
Standalone Library Setup
If you're not using Symfony, you can still use MicroMapper! You'll need to
instantiate the MicroMapper class and pass it all of your mappings:
In this case, the #[AsMapper] attribute is not needed.
Credits
- Ryan Weaver
- All Contributors
License
MIT License (MIT): see the License File for more details.
Security Policy
If you discover a security vulnerability, please do not open a public issue or pull request. Instead, please review this repository's Security Policy for instructions on how to report it responsibly.