mark-gerarts / automapper-plus

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

Map to multiple operation and map from method operation #64

Closed peter-si closed 2 years ago

peter-si commented 3 years ago

Hi, I would like to add 2 operations and wanted to know if it is wanted or can't be done already with some other operations. I'll start with the easier one:

fromProperty

we have quite a few mappings like this

        $config->registerMapping(Hosting::class, HostingDto::class)
               ->forMember('isActive', static function (Hosting $hosting) {
                   return $hosting->canBeStarted();
               })
        ;

this could be quite easily done with something like

 $config->registerMapping(Hosting::class, HostingDto::class)
               ->forMember('isActive', Operation::fromMethod('canBeStarted')
 ;

mapToMultiple

the more complicated one - support polymorphism. Sometimes we have a collection of different objects (e.g. with single table inheritance) and we would like to map them to different set of objects. Currently we are doing it like this:

               ->forMember(
                   'supportedParameters',
                   static function (Package $package, AutoMapperInterface $mapper) {
                       // Automapper is not supporting polymorphism, so we have to do it like this
                       $supportedParameters = [];

                    foreach ($package->getSupportedParameters() as $hostingTypeParameters) {
                        switch (get_class($hostingTypeParameters)) {
                            case LinuxHostingParameters::class:
                                $supportedParameters[] = $mapper->map(
                                    $hostingTypeParameters,
                                    LinuxHostingParametersDto::class
                                );

                                break;
                            case WindowsHostingParameters::class:
                                $supportedParameters[] = $mapper->map(
                                    $hostingTypeParameters,
                                    WindowsHostingParametersDto::class
                                );

                                break;                                
                            default:
                                throw new \RuntimeException(
                                    sprintf('Unsupported hosting parameters "%s"', get_class($hostingTypeParameters))
                                );
                        }
                    }

                       return $supportedParameters;
                   }
               )

My idea is to create an operation which would look like this


 $config->registerMapping(Package::class, PackageDto::class)
               ->forMember('supportedParameters', Operation::mapToMultiple([
                   LinuxHostingParameters::class,
                   WindowsHostingParameters::class
               ])
 ;
mark-gerarts commented 3 years ago

Hi @peter-si, thank you for creating this issue.

fromProperty / fromMethod

Seems a useful operation - if you open up a PR for this I'll gladly merge it!

Polymorphism

What's the behaviour here - loop through each option provided, and map to the first target for which a mapping exists? Seems a useful addition as well!

I'm not sure about the name though, mapToMultiple implies mapping to a collection of some sorts (at least to me). I can't come up with a good alternative myself either... Maybe mapToOneOf?

peter-si commented 3 years ago

Ok, I'll do it today. And yes, that's exactly how I pictured that polymorphism feature. I'm not too attached to mapToMultiple, so mapToOneOf it is

peter-si commented 3 years ago

Oh right a bit of misunderstanding on my part. My goal was to have an array of objects mapped to a different array of objects. Not single value to one of provided classes (it can work both way though). So in that regart mapToOneOf is not a good name since we won't necessarily get a single value

mark-gerarts commented 2 years ago

As discussed in #70, this has been implemented as MapToAnyOf.