mark-gerarts / automapper-plus

An AutoMapper for PHP
MIT License
551 stars 30 forks source link

[RFC] Context aware operations #30

Closed BoShurik closed 5 years ago

BoShurik commented 5 years ago

Hello!

I have the following use case: https://gist.github.com/BoShurik/7aafc932e9dcf74be2196a09d6da15bd

To build children elements I need access to parent object

$config
    ->registerMapping(ItemDTO::class, Item::class)
    ->forMember('value', Operation::mapFrom(function (ItemDTO $dto) {
        return new Value(/*OrderDTO::$currency*/, $dto->value);
    }))
;

I suggest to use context:

$config
    ->registerMapping(OrderDTO::class, Order::class)
    ->forMember('value', Operation::mapFrom(function (OrderDTO $dto) {
        return new Value($dto->currency, $dto->value);
    }))
    ->forMember('items', Operation::mapFromWithMapper(function (OrderDTO $dto, AutoMapper $mapper) {
        $items = [];
        foreach ($dto->items as $item) {
            $items[] = $mapper->map($item, Item::class, [
               'currency' => $dto->currency,
            ]);
        }

        return $items;
    }))
;
$config
    ->registerMapping(ItemDTO::class, Item::class)
    ->forMember('value', Operation::mapFromWithContext(function (ItemDTO $dto, array $context) {
        return new Value($context['currency'] ?? 'EUR', $dto->value);
    }))
;

Not sure, but may be it solves problem described in #16

mark-gerarts commented 5 years ago

Hello @BoShurik. I like this suggestion, it seems really useful. I've skimmed through the code a bit, and it certainly seems possible to implement. However, to be consistent I think I would want to pass the context to every operation (where it makes sense), and not make a specific mapFromWithContext. This way you could just do something like this:

$config->registerMapping(ItemDTO::class, Item::class)
    ->forMember('value', Operation::mapFrom(function (ItemDTO $dto, AutoMapper $mapper, array $context) {
        // ...
    });

I'm gonna give this some more tought, and I hope to start experimenting a bit next week. I'll get back to you!

As a side note, I plan on making the automapper always available to the MapFrom operation, instead of using a separate mapFromWithMapper operation. Seems a bit more user-friendly to me.

BoShurik commented 5 years ago

As a side note, I plan on making the automapper always available to the MapFrom operation, instead of using a separate mapFromWithMapper operation. Seems a bit more user-friendly to me.

It was my next suggestion :)

mark-gerarts commented 5 years ago

Hi @BoShurik. The feature has been implemented on the feature/context branch. You can view the documentation here. If you have any remarks or suggestions, let me know. Otherwise I'm merging it into master and tagging a new release.

BoShurik commented 5 years ago

Looks good to me

mark-gerarts commented 5 years ago

Released in 1.3.0! :tada: