-
Notifications
You must be signed in to change notification settings - Fork 17
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
Impossibility of mapping in Doctrine Collection #169
Comments
Hey @KoNekoD thanks for you report ! For a similar and if you wanna give a try on making a PR, you can check: janephp/janephp#495 |
It's strange that I suspect you use an existing object to map the value to, and the value passed here is a doctrine collection where it should have been an item, can you show us the mapper that call this mapper with the collection ? |
@Korbeil Thanks for your reply, but this is not a problem with Doctrine collection, it seems to be a logical error in the generated mapper, it should have read the method signature and realizing that iterable is in front of it, build an array with the required type. Maybe we need a unique internal transformer that works specifically for Doctrine Collection? |
@joelwurtz Yes, you are right mapping is done on an existing object with deep_target_to_populate true. I think this is a logical problem because if you try to use an array it also tries to do the same with the array. Maybe you can somehow improve the logic so that the generated code understands that there is an array in front of it and that it needs to collect an array of small elements and set them, and if there is a collection, it follows the collection methods in the same way...? Here is the mapper that calls the problematic mapper: <?php
final class Symfony_Mapper_App_Dto_DigitalStore_DigitalStoreUpdateProfileDto_App_Entity_DigitalStore extends AutoMapper\GeneratedMapper
{
public function initialize(): void
{
$this->hydrateCallbacks['items'] = \Closure::bind(function ($object, $value) {
$object->items = $value;
}, null, 'App\Entity\DigitalStore');
}
/** @param \App\Dto\DigitalStore\DigitalStoreUpdateProfileDto $value */
public function &map($value, array $context = []): mixed
{
if (null === $value) {
return $value;
}
/** @var \App\Entity\DigitalStore|null $result */
$result = $context['target_to_populate'] ?? null;
if (null === $result) {
$result = new \App\Entity\DigitalStore();
}
$context = \AutoMapper\MapperContext::withIncrementedDepth($context);
if (\AutoMapper\MapperContext::isAllowedAttribute($context, 'profile', !isset($value->profile)) && (!array_key_exists('groups', $context) || !$context['groups'])) {
if (null !== $value->profile) {
}
$result->setProfile($this->mappers['Mapper_App\Dto\DigitalStore\ProfileInputDto_App\Entity\Profile']->map($value->profile, \AutoMapper\MapperContext::withNewContext($context, 'profile', ($context['deep_target_to_populate'] ?? false) ? $result->getProfile() : null)));
}
if (\AutoMapper\MapperContext::isAllowedAttribute($context, 'socialLinks', !isset($value->socialLinks)) && (!array_key_exists('groups', $context) || !$context['groups'])) {
if (null !== $value->socialLinks) {
$values = [];
foreach ($value->socialLinks as $key => $value_1) {
$values[] =& $this->mappers['Mapper_App\Dto\DigitalStore\SocialLinkDto_App\Entity\SocialLink']->map($value_1, \AutoMapper\MapperContext::withNewContext($context, 'socialLinks', ($context['deep_target_to_populate'] ?? false) ? $result->getSocialLinks() : null));
}
}
$result->setSocialLinks($values);
}
return $result;
}
public function registerMappers(AutoMapper\AutoMapperRegistryInterface $autoMapperRegistry): void
{
$this->mappers['Mapper_App\Dto\DigitalStore\ProfileInputDto_App\Entity\Profile'] = $autoMapperRegistry->getMapper('App\Dto\DigitalStore\ProfileInputDto', 'App\Entity\Profile');
$this->mappers['Mapper_App\Dto\DigitalStore\SocialLinkDto_App\Entity\SocialLink'] = $autoMapperRegistry->getMapper('App\Dto\DigitalStore\SocialLinkDto', 'App\Entity\SocialLink');
}
} I think the logical fallacy is in this point:
Where it tries to use a collection to set the Item, and if you change the collection to an array it will do the same thing |
Thanks, yeah we detect correctly, but code the code is wrongly generated, however i'm not sure what our solution should be here. Problem is, how do we choose the correct value from the collection to map to ? |
Hi @joelwurtz Sorry for the long reply, I was very zany and didn't notice the reply. I don't so much need to find a field to map and recreate fields in a collection. I just need to be able to map a DTO array into an array of entities and set them in a collection field using a setter, I don't see any problem if I for example use array $items in the setter signature and they will be set normally. So to summarize, it's easy enough to set the resulting array to an entity using a setter. |
If in the first example target_to_populate could be defined as null, then a simple mapping to a new object would occur with the following return |
Here's how the mapper call is going on right now This is mainly to successfully map data to a single object, I expected that for a collection it would not be able to find a mapping target and would just create a new object, but instead it just tries to use the collection as a mapping target-edentity, and this is wrong, maybe there is an option to recognize that the object type is a collection and work with it in a certain way. I would say that this is adding support for doctrine collections rather than a bug report, because the code managed to recognize the type, but the reality turned out to be different :) |
? |
I have difficulties with updating entities in a collection (let's omit the problem of overlapping and finding the right field by id), the problem is that instead of calling the setItems() method and transferring Collection into it, the call to the received Collection object such as setItemId() is made, which leads to an error, because Collection cannot have this method.
Below is an example of the generated code:
The text was updated successfully, but these errors were encountered: