O
O
okkkman2020-10-17 13:04:08
symfony
okkkman, 2020-10-17 13:04:08

How to load DTO into Entity in Symfony?

Hello.

It was necessary to validate the data from the DTO and I wrote a Resolver that works up to the Controller and interacts with the Request. In it, I injected Serializer (for loading Request data into DTO) and Validator interfaces, respectively.

Next, I needed to load the DTO into Entity and at the same time take into account the possibility that the fields between them may differ.

To do this, I wrote EntityDtoLoader, a kind of persimmon that checks existing set methods and, in case of matches, loads its own:

protected function load($dto, $model)
{
    $modelMethods = get_class_methods($model);
    $dtoMethods   = get_class_methods($dto);

    foreach ($dtoMethods as $method) {
        preg_match('/get(.*)/', $method, $name);

        if (count($name)) {
            $name = $name[1];

            foreach ($modelMethods as $modelMethod) {
                if ($modelMethod === 'set'.$name) {
                    $model->{'set'.$name}($dto->{'get'.$name}());
                }
            }
        }
    }
}


The disadvantages of this solution are obvious.
In general, fierce game.

Usually people load their Entity model from DTO data manually, write "new User" in the service and set the data..

Why did I write EntityDtoLoader?
Should I use ModelMapper?
Or which is better?

Can you share your approach? Maybe someone has a suitable repository with an implementation example?

Thanks

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
Maxim Fedorov, 2020-10-17
@okkkman

In general, it is a bad practice to map on the essence of a DTO.
Why: an entity is some kind of business object, it controls state transitions and encapsulates the logic itself. But the entity is in the context of ... a business process, which is expressed by some other type of class (interactors or use cases, if Bob Martin's terms), for example, in CQRS, this kind of class is command handlers.
Bottom line: it’s probably not worth working with entities directly, especially since there shouldn’t be setters in entities :) and methods for converting data from DTO explicitly aka fromDto(), as Flying pointed out (with all due respect), because this is not business logic , but some transport-application... Static constructors can be, but not for DTO, but for certain data that displays a business opportunity.
In addition, your solution is fraught with high coupling - your entities are constructed for dto, dto for entities ...
How to do it well:
Create entities only as part of a business process, that is, always explicitly and directly through a constructor or factory method that embodies the business -logic.

I
index0h, 2020-10-17
@index0h

In vain I wrote EntityDtoLoader?

Who knows, probably in vain.
Or which is better?

It’s hard to say, so far I don’t quite understand why you need DTO in principle?
Your action knows what data to process from the Request - pull it out explicitly and check, yes, there is more code, but on a long run it greatly simplifies life, you clearly see where and what is.
Further, if necessary, shove where necessary.
There is another option - for each action, make a separate class *Form / *Message, which receives Request as input, pulls data directly in the constructor, validates it and pushes it into private properties by converting types. Getters are provided outside.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question