Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flattening objects and reusability #62

Closed
peter-si opened this issue Nov 25, 2020 · 2 comments
Closed

Flattening objects and reusability #62

peter-si opened this issue Nov 25, 2020 · 2 comments

Comments

@peter-si
Copy link

peter-si commented Nov 25, 2020

Hi, I have a question regarding flattening objects and reusability of mappings for child objects. Imagine having structure like this:

class Tyre
{
    /** @var string */
    public $name;

    /** @var int */
    public $size;
}

class Wheel
{
    /** @var Tyre */
    public $tyre;
}

class UniCycle
{
    /** @var Wheel */
    public $wheel;

}

class UniCycleDto implements Vehicle
{
    /** @var string */
    public $tyreName;
}

class CarWithOneWheelDto implements Vehicle
{
    /** @var string */
    public $tyreName;

    /** @var string */
    public $tyreSize;
}


$config->registerMapping(UniCycle::class, UniCycleDto::class)
       ->forMember(
           'tyreName',
           static function (UniCycle $uniCycle) {
               return $uniCycle->wheel->tyre->name;
           }
       );

This can result in a pretty big configuration, keeping me wondering, if this is not smaller/easier/faster (especially when I can't reuse my mapping, since I only have one unicycle in my system)

$uniCycleDto = new UniCycleDto();
$uniCycleDto->tyreName = $uniCycle->wheel->tyre->name;

Now first question is, is it possible to write it some compact way? e.g.

$config->registerMapping(UniCycle::class, UniCycleDto::class)
       ->forMember('tyreName', Operation::mapFrom('wheel.tyre.name'));

Second question is connected with my above example and this issue regarding reusability of those small value objects. I can have other objects, which have wheels and I'm interested in their tyre names (maybe some other properties). Is it possible to do something like this? I would like to have this kind of automatic, every time when I encounter Wheel, just do the mapping. However I'm not sure how to achieve that especially without recursive property accessor.

$config->registerMapping(Wheel::class, Vehicle::class)
       ->forMember('tyreName', Operation::mapFrom('tyre.name'))
       ->forMember('tyreSize', Operation::mapFrom('tyre.size'));

$config->registerMapping(UniCycle::class, UniCycleDto::class)
       ->useMapping(UniCycle::class, Vehicle::class);

$config->registerMapping(UniCycle::class, CarWithOneWheelDto::class)
       ->useMapping(UniCycle::class, Vehicle::class);
@mark-gerarts
Copy link
Owner

Hi @alulord, yes, your first question is a very valid feature request. Unfortunately it is not possible at the moment. The plan for v2 of the library is to integrate the Symfony property accessor, which would allow for the property path notation. I will have to be honest though, it can still be a while before I'm gonna work on bigger features like this, because it's a pretty busy time for me.

If you want this right away, you can try one of the solutions from #51. Keep in mind that you will not be able to access private properties this way though (which is not necessarily a bad thing). Also, this is for Operation::fromProperty.

For your second question: would copyFrom be of help? Since you can't use the property path notation (unless you implement the above), it would look like this:

$config->registerMapping(Wheel::class, Vehicle::class)
    ->forMember(
        'tyreName', 
        Operation::mapFrom(function ($source) {
            return $source->tyre->name;
        })
    );

$config->registerMapping(UniCycle::class, UniCycleDto::class)
       ->copyFrom(UniCycle::class, Vehicle::class);

$config->registerMapping(UniCycle::class, CarWithOneWheelDto::class)
       ->copyFrom(UniCycle::class, Vehicle::class);

@peter-si
Copy link
Author

Hi @mark-gerarts thanks for quick reply (btw, I had to change that username to something more sensible:). Regarding my first question; I see you already have a branch named 2.0 is it there, where you are doing these changes? I also don't have much time to spare, just but in case. Anyway thanks for looking into it.

Regarding second question, I guess you wanted to write it like this:

$config->registerMapping(UniCycle::class, CarWithOneWheelDto::class)
       ->copyFrom(Wheel::class, Vehicle::class); //no ->copyFrom(UniCycle::class

And then you will see the problem I have with it. I want it to any time that in source object is a Wheel try to map it to destination class based on the mapping. Or other way to look at it is, if you have properties in your mapping (in our case tyreName which we copied from Wheel::class, Vehicle::class mapping), try to find (recursive?) corresponding class from source and map it.

I know this is kind of complicated since the mapping is done based on destination, not source. Also things like endless recursion come to play. However I think that it will increase reusability of mappings quite a lot and help writing less code (which is the main purpose of automapper). But I have no idea if it is even possible or something you are planning to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants