Search code examples
phpsymfonyapi-platform.comnelmio-alice

Symfony ApiPlattform-Mapping vs. AliceDataFixtures: ManyToMany problems


I have some problems with setting up an api-platform-project with symfony and loading fixtures with hautelook/alice-bundle.

Following entities are given:

// ./src/Entity/UserGroup.php

#[ApiResource(
    collectionOperations: [
        'get' => [
            'normalization_context' => [
                'groups' => [
                    'userGroup:collection:get',
                    'item:collection:get',
                ],
            ],
        ],
        'post' => [
            'normalization_context' => [
                'groups' => [
                    'userGroup:collection:post',
                    'item:collection:get',
                ],
            ],
            'denormalization_context' => [
                'groups' => [
                    'userGroup:collection:post',
                ],
            ],
        ],
    ],
    itemOperations: [
        'get' => [
            'normalization_context' => [
                'groups' => [
                    'userGroup:item:get',
                    'item:get',
                ],
            ],
        ],
        'put' => [
            'normalization_context' => [
                'groups' => [
                    'userGroup:item:get',
                    'item:get',
                ],
            ],
            'denormalization_context' => [
                'groups' => [
                    'userGroup:item:put',
                ],
            ],
        ]
    ]
)]
#[ORM\Entity]
class UserGroup
{
    #[ORM\Column(type: Types::STRING, length: 128)]
    #[Assert\NotBlank]
    #[Assert\Length(min: 2, max: 128)]
    #[Groups([
        "userGroup:item:get",
        "userGroup:collection:get",
        "userGroup:collection:post",
        "userGroup:item:put",
    ])]
    protected string $name;

    // ID, other attributes, name getter and setter, ...
}
./src/Entity/User.php
#[ApiResource(
    collectionOperations: [
        'get' => [
            'normalization_context' => [
                'groups' => [
                    'user:collection:get',
                    'item:collection:get',
                ],
            ],
        ],
        'post' => [
            'normalization_context' => [
                'groups' => [
                    'user:collection:post',
                    'item:collection:get',
                ],
            ],
            'denormalization_context' => [
                'groups' => [
                    'user:collection:post',
                ],
            ],
        ],
    ],
    itemOperations: [
        'get' => [
            'normalization_context' => [
                'groups' => [
                    'user:item:get',
                    'item:get',
                ],
            ],
        ],
        'put' => [
            'normalization_context' => [
                'groups' => [
                    'user:item:get',
                    'item:get',
                ],
            ],
            'denormalization_context' => [
                'groups' => [
                    'user:item:put',
                ],
            ],
        ]
    ]
)]
#[ORM\Entity]
class User
{
    #[ORM\ManyToMany(targetEntity: UserGroup::class)]
    #[Groups([
        'userReal:item:get',
        'userReal:collection:post',
        'userReal:item:put'
    ])]
    protected $userGroups;

/**
     * @param mixed $userGroups
     */
    public function setUserGroups($userGroups): void
    {
        $this->userGroups = $userGroups;
    }

    // ID, other attributes, name getter and setter, ...
}

The fixture file contains following data:

App\Entity\UserGroup:
  userGroup_admin:
    name: 'Administrator'
    active: true
App\Entity\User:
  admin:
    email: '[email protected]'
    userGroups: [
        '@userGroup_admin'
    ]

Running command "php bin/console hautelook:fixtures:load" displays following error:

Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister::getMetadata(): Argument #2 (  
  $object) must be of type object, array given, called in [...]/vendor/theofidry/alice-data-fixtures/src/Bridge/Doctrine/Persister/ObjectManagerPersister.php o  
  n line 158                                   

If adding "addUserGroup" and "removeUserGroup" and removing getter and setter for UserGroup in User-class, the command runs as expected. After this fix the problem is in the ApiPlatform-Request handling: If an entity has two UserGroups and a PUT-request (full update of the entity) sends other UserGroups, the old UserGroups still exists (of course, cause only add-methods existing and not full setter).

Any ideas how to solve this problem?

// composer.json 
{
"api-platform/core": "^2.6",
"hautelook/alice-bundle": "^2.9",
"symfony/*": "5.4.*",
}

```

Solution

  • You might consider modifying your User::setUserGroups() method to look like this:

    // be sure to import the ArrayCollection
    use Doctrine\Common\Collections\ArrayCollection;
    
    /**
     * @param array $userGroups
     */
    public function setUserGroups(array $userGroups): void
    {
        $this->userGroups = new ArrayCollection($userGroups);
    }
    

    The error is likely a type issue when setting the $userGroups. You are sending an array (using [] in the fixture) and the property is a ManyToMany which is usually a Collection.

    Before doing this you should inspect the rest of your codebase and be sure this will not break something else.