Core: How to POST new entry in OneToOne with automatically creation relation

Created on 14 Mar 2018  路  3Comments  路  Source: api-platform/core

I have two entities User and UserSettings.
I would like to add new user entry with settings entry that are linked by OneToOne relation.

Entity User

namespace App\Entity;

use ApiPlatform\Core\Annotation as API;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 *
 * @API\ApiResource(
 *     itemOperations={
 *         "GET"={
 *             "normalization_context"={"groups"={"user-get"}}
 *         }
 *     },
 *     collectionOperations={
 *         "GET"={
 *             "normalization_context"={"groups"={"user-get"}}
 *         },
 *         "POST"={
 *             "denormalization_context"={"groups"={"user-post"}}
 *         },
 *     }
 * )
 */
class User
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Serializer\Groups({"user-get"})
     */
    private $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=64, nullable=false)
     * @Serializer\Groups({"user-get", "user-post"})
     */
    private $name;

    /**
     * @var UserSettings
     * @ORM\OneToOne(targetEntity="UserSettings", mappedBy="user", cascade={"persist", "remove"})
     * @Serializer\Groups({"user-get", "user-post"})
     * @API\ApiSubresource()
     */
    private $settings;
}

Entity UserSettings

namespace App\Entity;

use ApiPlatform\Core\Annotation as API;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;


/**
 * @ORM\Entity(repositoryClass="App\Repository\UserSettingsRepository")
 *
 * @API\ApiResource(
 *     itemOperations={"GET"},
 *     collectionOperations={"POST"},
 * )
 */
class UserSettings
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Serializer\Groups({"user-get"})
     */
    private $id;

    /**
     * @var User
     * @ORM\OneToOne(targetEntity="User", inversedBy="settings")
     * @ORM\JoinColumn(onDelete="CASCADE", nullable=true)
     */
    private $user;

    /**
     * @var string
     * @ORM\Column(type="string")
     * @Serializer\Groups({"user-get", "user-post"})
     */
    private $test;
}

POST request data

{
    "@type": "User",
    "name": "admin",
    "settings": {
        "@type": "UserSettings",
        "test": "test string"
    }
}

When I try to POST in database is created two entry in both tables but without relation. Unfortunately user_id field in UserSettings table contains null. Relation is not created.

RAW SQL queries log:

INSERT INTO user (name) VALUES (?) {"1":"admin"}
INSERT INTO user_settings (test, user_id) VALUES (?, ?) {"1":"test string","2":null}

But I expect that will be created entry in User table and after that will be created UserSettings entry by using id of new user for set this value into user_id field as OneToOne relation.

  1. Does api-platfom support this behavior from the box?
  2. If yes what is wrong in my code?
  3. Perhaps there is a way to do this manually. What is the right approach in this case?

Most helpful comment

Use this:

<?php
class User {
    public function setSettings(UserSettings $settings) {
       $settings->setUser($this);
       $this->settings = $settings;
    }
}

All 3 comments

Use this:

<?php
class User {
    public function setSettings(UserSettings $settings) {
       $settings->setUser($this);
       $this->settings = $settings;
    }
}

@soyuka Thanks ! Your advice is helpful

Working approach

  1. Add these methods to User
    /**
     * @return UserSettings
     */
    public function getSettings(): ?UserSettings
    {
        return $this->settings;
    }

    /**
     * @param UserSettings $settings
     *
     * @return User
     */
    public function setSettings(UserSettings $settings): User
    {
        $this->settings = $settings;
       if ($settings->getUser() !== $this) {
            $settings->setUser($this);
        }

        return $this;
    }
  1. Add these methods to UserSettings
    /**
     * @return User
     */
    public function getUser(): ?User
    {
        return $this->user;
    }

    /
     * @param User $user
     * @return UserSettings
     */
    public function setUser($user): UserSettings
    {
        $this->user = $user;
       if ($user->getSettings() !== $this) {
            $user->setSettings($this);
        }

        return $this;
    }

I have same problem but when i do a PUT with null data (to delete relation), after a post with some settings example:

FIRST, A POST

{
    "@type": "User",
    "name": "admin",
    "settings": {
        "@type": "UserSettings",
        "test": "test string"
    }
}

AFTER, A PUT

{
    "@type": "User",
    "name": "adminEdited",
    "settings": null
}

The field "name" is edited with "adminEdited", but the settings are not removed.

Was this page helpful?
0 / 5 - 0 ratings