Core: [Question] ManyToMany relation in PUT

Created on 15 Mar 2017  路  6Comments  路  Source: api-platform/core

Hello,

I want to understand why what i'm trying to do not works.

Principal dependencies versions are them :

"symfony/symfony": "3.2.*",
"api-platform/core": "^2.0",
"doctrine/orm": "^2.5",
"doctrine/doctrine-bundle": "^1.6"

I have an entity "UserApp" with a "teamFollowed" field, which is a ManyToMany relation between an other entity "Team" and it.

UserApp :

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={
 *              "groups"={"userapp_norm"}
 *          },
 *          "denormalization_context"={
 *              "groups"={"userapp_denorm"}
 *          }
 *     },
 *     collectionOperations={
 *          "me"={
 *              "route_name"="api_user_apps_get_me"
 *          }
 *     },
 *     itemOperations={
 *          "get"={"method"="GET"},
 *          "put"={"method"="PUT"}
 *     }
 * )
 *
 * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
 * @ORM\Entity
 * @ORM\Table(
 *     uniqueConstraints={
 *          @UniqueConstraint(
 *              name="deviceUuid",
 *              columns={
 *                  "device_uuid",
 *                  "deleted_at"
 *              },
 *              options={"where": "(deleted_at IS NULL)"}
 *          )
 *     }
 * )
 */
class UserApp implements UserInterface
{
...
    /**
     * @var ArrayCollection
     *
     * @Groups({"userapp_norm", "userapp_denorm"})
     * @ORM\ManyToMany(targetEntity="Team", mappedBy="followers")
     */
    private $teamFollowed;

    ...

    /**
     * @param Team $teamFollowed
     *
     * @return UserApp
     */
    public function addTeamFollowed(Team $teamFollowed)
    {
        $this->teamFollowed[] = $teamFollowed;

        return $this;
    }

    /**
     * @param Team $teamFollowed
     */
    public function removeTeamFollowed(Team $teamFollowed)
    {
        $this->teamFollowed->removeElement($teamFollowed);
    }

    /**
     * @return Collection
     */
    public function getTeamFollowed() : Collection
    {
        return $this->teamFollowed;
    }
...

Team :

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={
 *              "groups"={"team_norm"}
 *          }
 *     },
 *     collectionOperations={
 *          "get"={"method"="GET"}
 *     },
 *     itemOperations={
 *          "get"={"method"="GET"}
 *     }
 * )
 *
 * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
 * @ORM\Entity
 * @ORM\Table(
 *     uniqueConstraints={
 *          @UniqueConstraint(
 *              name="name_competition",
 *              columns={
 *                  "name",
 *                  "competitionId",
 *                  "deleted_at"
 *              },
 *              options={"where": "(deleted_at IS NULL)"}
 *          )
 *     }
 * )
 */
class Team
{
...
    /**
     * @var ArrayCollection
     *
     * @Groups({"team_norm"})
     * @ORM\ManyToMany(targetEntity="UserApp", inversedBy="teamFollowed")
     */
    private $followers;

    ...

    /**
     * @param UserApp $follower
     *
     * @return Team
     */
    public function addFollower(UserApp $follower)
    {
        $this->followers[] = $follower;

        return $this;
    }

    /**
     * @param UserApp $follower
     */
    public function removeFollower(UserApp $follower)
    {
        $this->followers->removeElement($follower);
    }

    /**
     * @return Collection
     */
    public function getFollowers() : Collection
    {
        return $this->followers;
    }
...
}

When i send a PUT to UserApp entry point with team id in teamFollowed field, it works :

      {
        "teamFollowed": ["/api/teams/3"]
      }

but with team object (with "@id" field), it not works. Doctrine is trying to create a new Entity (i have no cascade persist on this field and the entity with id /api/teams/3 exist) :

      {
        "teamFollowed": [{
           "@id": "/api/teams/3"
       }]
      }

I don't understand why it's not working. Did you have any idea ?

Thanks you,
Dimitri

question

Most helpful comment

Hello @soyuka @Simperfit, we found the real cause of this issue.

PUT with the "@id" require the header to be "application/ld+json" which is required for hydra and the header sent was "application/json", so it's work only without "@id" sending.

Hope answer can help ;)

Thanks you.
Best regards.

All 6 comments

Try adding a denormalization group on Team -> id

@soyuka My id field on Team entity has the UserApp denorm group :

    /**
     * @var int
     *
     * @Groups({"team_norm", "userapp_norm", "userapp_denorm"})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

I tried to add a denormalization context to the Team entity and adding it to id field to, and it's not working too.

It's working to me, here's a patch file on api-platform/api-platform.

You can:

git clone [email protected]:api-platform/api-platform
cd api-platform
curl https://gist.githubusercontent.com/soyuka/02533d1114faca5eb78c4fde257cb320/raw/810d7f29532a10042264c26a181cd81937da3d98/custom.patch | patch -p1
bin/console doctrine:schema:create
bin/console server:start

I'm even able to PUT with both an object and a string ^^:

api-platform-put-fancy

@soyuka Thanks you, i will try it as soon as possible and check what i'm doing wrong and answer here :)

@dimzerawww Feel free to ping me if you still have an issue

Hello @soyuka @Simperfit, we found the real cause of this issue.

PUT with the "@id" require the header to be "application/ld+json" which is required for hydra and the header sent was "application/json", so it's work only without "@id" sending.

Hope answer can help ;)

Thanks you.
Best regards.

Was this page helpful?
0 / 5 - 0 ratings