- 
                Notifications
    You must be signed in to change notification settings 
- Fork 20
Open
Description
Assuming we have the following code:
class Category
{
    /** @var Post[] */
    public array $posts = [];
    public function __construct(
        public string $name
    ) {
    }
}
class Post
{
    public function __construct(
        public string $name,
        public Category $category
    ) {
    }
}
class CategoryDTO
{
    /**
     * @var PostDTO[]
     */
    public array $posts = [];
    public function __construct(
        public string $name,
    ) {
    }
}
class PostDTO
{
    public function __construct(
        public string $name,
        public CategoryDTO $category,
    )  {
    }
}the generated mapper becomes:
/** @param \AutoMapper\Tests\Fixtures\Category $value */
    public function &map($value, array $context = []): mixed
    {
        if (null === $value) {
            return $value;
        }
        $sourcehash = spl_object_hash($value) . 'AutoMapper\Tests\Fixtures\CategoryDTO';
        if (\AutoMapper\MapperContext::shouldHandleCircularReference($context, $sourcehash)) {
            return \AutoMapper\MapperContext::handleCircularReference($context, $sourcehash, $value);
        }
        /** @var \AutoMapper\Tests\Fixtures\CategoryDTO|null $result */
        $result = $context['target_to_populate'] ?? null;
        if (null === $result) {
            $constructargs = [];
            if (isset($value->name)) {
                $constructargs['name'] = $value->name;
            } elseif (\AutoMapper\MapperContext::hasConstructorArgument($context, 'AutoMapper\Tests\Fixtures\CategoryDTO', 'name')) {
                $constructargs['name'] = \AutoMapper\MapperContext::getConstructorArgument($context, 'AutoMapper\Tests\Fixtures\CategoryDTO', 'name');
            } else {
                $constructargs['name'] = throw new \AutoMapper\Exception\MissingConstructorArgumentsException('Cannot create an instance of "AutoMapper\Tests\Fixtures\CategoryDTO" from mapping data because its constructor requires the following parameters to be present : "$name".', 0, null, ['name'], 'AutoMapper\Tests\Fixtures\CategoryDTO');
            }
            $result = new \AutoMapper\Tests\Fixtures\CategoryDTO(...$constructargs);
        }
        else {
            $context = \AutoMapper\MapperContext::withReference($context, $sourcehash, $result);
            $context = \AutoMapper\MapperContext::withIncrementedDepth($context);
            if (\AutoMapper\MapperContext::isAllowedAttribute($context, 'name', function () use ($value) {
                return !isset($value->name) and null === $value->name;
            }, !array_key_exists('name', (array) $value)) && (!array_key_exists('groups', $context) || !$context['groups'])) {
                $result->name = $value->name;
            }
        }
        if (\AutoMapper\MapperContext::isAllowedAttribute($context, 'posts', function () use ($value) {
            return !isset($value->posts) and null === $value->posts;
        }, !array_key_exists('posts', (array) $value)) && (!array_key_exists('groups', $context) || !$context['groups'])) {
            $values = $context['deep_target_to_populate'] ?? false ? isset($result->posts) ? $result->posts : [] : [];
            foreach ($value->posts ?? [] as $key => $value_1) {
                $values[] =& $this->mappers['Mapper_AutoMapper\Tests\Fixtures\Post_AutoMapper\Tests\Fixtures\PostDTO']->map($value_1, \AutoMapper\MapperContext::withNewContext($context, 'posts'));
            }
            $result->posts = $values;
        }
        return $result;
    }As we can see, the context is only updated when we specify a target to fill. Otherwise it will cause an infinite loop. I would expect the mapper to handle this case as well.
Metadata
Metadata
Assignees
Labels
No labels