Manual Mapping using an Object Mapper
If you need a custom logic in an object to another object mapping, one way to do
it is to create a service, and add the AsObjectMapper
attribute to a method.
Example:
use Brick\Money\Money;
use Rekalogika\Mapper\Attribute\AsObjectMapper;
class MoneyObjectMapper
{
#[AsObjectMapper]
public function mapMoneyToMoneyDto(Money $money): MoneyDto
{
return new MoneyDto(
$money->getAmount()->__toString(),
$money->getCurrency()->getCurrencyCode(),
);
}
#[AsObjectMapper]
public function mapMoneyDtoToMoney(MoneyDto $moneyDto): Money
{
return Money::of($moneyDto->getAmount(), $moneyDto->getCurrency());
}
}
Getting the Existing Target Value
If you need to get the existing value of the target property, you can add the optional second argument to the method. The mapper will pass the existing value to the method.
use Brick\Money\Money;
use Rekalogika\Mapper\Attribute\AsObjectMapper;
class MoneyObjectMapper
{
#[AsObjectMapper]
public function mapMoneyDtoToMoney(
MoneyDto $moneyDto,
Money $existingMoney
): Money {
return Money::of($moneyDto->getAmount(), $moneyDto->getCurrency());
}
}
You may return the original instance or a new instance. If you return a new instance, Mapper will replace the original instance with the new one.
Extra Arguments
You also have the option to inject the main transformer, sub-mapper, and the context to the property mapper. This can be in any order, but the first argument must be the source object.
use Brick\Money\Money;
use Rekalogika\Mapper\Attribute\AsObjectMapper;
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\MainTransformerInterface;
use Rekalogika\Mapper\SubMapper\SubMapperInterface;
class MoneyObjectMapper
{
#[AsObjectMapper]
public function mapMoneyToMoneyDto(
Money $money,
MainTransformerInterface $mainTransformer,
SubMapperInterface $subMapper,
Context $context
): MoneyDto {
return new MoneyDto(
$money->getAmount()->__toString(),
$money->getCurrency()->getCurrencyCode(),
);
}
}
Source Union Types
Union types on the source side are supported.
use Rekalogika\Mapper\Attribute\AsObjectMapper;
class AnimalMapper
{
#[AsObjectMapper()]
public function mapCatOrDogToAnimalDto(Cat|Dog $animal): AnimalDto
{
return new AnimalDto($animal);
}
}
Read more about the sub mapper in the SubMapper chapter.
Using a Lazy-Loading Proxy
Instead of doing the mapping immediately, you can also use the createProxy()
method to create a target proxy object. The mapping will be deferred to the
point when you first access the properties of the proxy object.
use Brick\Money\Money;
use Rekalogika\Mapper\Attribute\AsObjectMapper;
use Rekalogika\Mapper\Context\Context;
use Rekalogika\Mapper\MainTransformerInterface;
use Rekalogika\Mapper\SubMapper\SubMapperInterface;
class MoneyObjectMapper
{
#[AsObjectMapper]
public function mapMoneyToMoneyDto(
Money $source,
SubMapperInterface $subMapper,
): MoneyDto {
return $subMapper->createProxy(
MoneyDto::class,
static function (MoneyDto $target) use ($source) {
$target->__construct(
$source->getAmount()->__toString(),
$source->getCurrency()->getCurrencyCode(),
);
},
);
}
}
Read more about the createProxy()
method in the SubMapper
chapter.