How to proper relate(group) Entities in Symfony and api-platform - symfony

Im getting the error:
Nested documents for attribute "players" are not allowed. Use IRIs instead.
So, I understand that I need to make groups with a serializer.
What im working with; I use symfony 5, doctrine(SQLite) and api-platform.
Im making a game and a game needs players. So when I add a game in the DB I also want to add players. Both have their own entity; Game.php and Player.php (Also both in the entity folder).
For some reason I cant proper link 2 entities, what am i doing wrong?
I use API-platform to execute this json;
{
"active": 0,
"hints": 0,
"players": [
{
"game": 1,
"nickname": "string",
"code": "string"
}
],
"price": "345",
"gameMap": "/api/game_maps/2",
"uidGame": "4",
"teamName": "3",
"secretKey": "fdgfdg",
"startTime": "2021-03-11T11:38:45.923Z",
"lastActionOnTime": "2021-03-11T11:38:45.923Z",
"endTime": "2021-03-11T11:38:45.923Z",
"penaltyTime": "g",
"testGame": 0
}
The Game entity:
<?php
namespace App\Entity;
use App\Repository\GameRepository;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(normalizationContext={ "groups": {"boost"} })
* #ORM\Entity(repositoryClass=GameRepository::class)
*/
class Game
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"boost"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=GameMap::class, inversedBy="games", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"boost"})
*/
private $game_map;
/**
* #ORM\Column(type="string", length=255)
*/
private $uid_game;
/**
* #ORM\Column(type="string", length=255)
*/
private $team_name;
/**
* #ORM\Column(type="string", length=255)
*/
private $secret_key;
/**
* #ORM\Column(type="datetime")
*/
private $start_time;
/**
* #ORM\Column(type="datetime")
*/
private $last_action_on_time;
/**
* #ORM\Column(type="smallint")
*/
private $active;
/**
* #ORM\Column(type="datetime")
*/
private $end_time;
/**
* #ORM\Column(type="integer")
*/
private $hints;
/**
* #ORM\Column(type="bigint")
*/
private $penalty_time;
/**
* #ORM\Column(type="json")
*/
private $progress = [];
/**
* #ORM\Column(type="string", length=255)
*/
private $price;
/**
* #ORM\Column(type="smallint")
*/
private $test_game;
/**
* #ORM\OneToMany(targetEntity=Player::class, mappedBy="game", orphanRemoval=true, cascade={"persist"})
* #Groups({"boost"})
*/
private $players;
/**
* #ORM\OneToMany(targetEntity=UserGame::class, mappedBy="game", orphanRemoval=true, cascade={"persist"})
* #Groups({"boost"})
*/
private $userGames;
}
And the Player entity:
<?php
namespace App\Entity;
use App\Repository\PlayerRepository;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass=PlayerRepository::class)
*/
class Player
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"boost"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Game::class, inversedBy="players")
* #ORM\JoinColumn(nullable=false)
* #Groups({"boost"})
*/
private $game;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"boost"})
*/
private $nickname;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"boost"})
*/
private $code;
}

So, there are two different issues in your case.
Use different normalization and denormalization contexts. Add all needed fields in both Game and Player into the denormalization group:
/**
* #ApiResource(
* normalizationContext={ "groups": {"boost"} },
* denormalizationContext={ "groups": {"write"} }
* )
* #ORM\Entity()
*/
class Game
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"boost"})
*/
private $id;
...
/**
* #ORM\OneToMany(targetEntity=Player::class, mappedBy="game",
orphanRemoval=true, cascade={"persist"})
* #Groups({"boost", "write"})
*/
private $players;
}
And:
/**
* #ApiResource()
* #ORM\Entity()
*/
class Player
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
* #Groups({"boost"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Game::class, inversedBy="players")
* #ORM\JoinColumn(nullable=false)
*/
private $game;
/**
* #ORM\Column(type="string", length=255)
*
* #Groups({"boost", "write"})
*/
private $nickname;
/**
* #ORM\Column(type="string", length=255)
*
* #Groups({"boost", "write"})
*/
private $code;
In your POST /api/games you use game: 1 in body request, in players nested collection. It's bad because you run create game requests actually. How in this case a player can be linked to an already existed game? The relationship between Game and Player is OneToMany. Do you see what I mean?
After these changes and POST /api/games the body
{
"active": 0,
"hints": 0,
"players": [
{
"nickname": "string",
"code": "string"
}
],
"price": "345",
"uidGame": "4",
"teamName": "3",
"secretKey": "fdgfdg",
"startTime": "2021-03-11T11:38:45.923Z",
"lastActionOnTime": "2021-03-11T11:38:45.923Z",
"endTime": "2021-03-11T11:38:45.923Z",
"penaltyTime": "9",
"testGame": 0
}
I got the response on GET /api/games:
[
{
"id": 1,
"uidGame": "4",
"teamName": "3",
"secretKey": "fdgfdg",
"startTime": "2021-03-11T11:38:45+00:00",
"lastActionOnTime": "2021-03-11T11:38:45+00:00",
"active": 0,
"endTime": "2021-03-11T11:38:45+00:00",
"hints": 0,
"penaltyTime": "9",
"progress": [],
"price": "345",
"testGame": 0,
"players": [
{
"id": 1,
"nickname": "string",
"code": "string"
}
]
}
]
Is it expected for you?

Related

Get collection without deleted resources API-Platform

How can I select a resource without it's releted resources deleted using API-Platform ?
I have this relation Don ManyTOOne Donateur. In the Don resouce, I have $isDeleted as field. When its value is true, and a try to select a item form Donateur, I get it.
Show here:
// The GET operation http://localhost:8000/api/donateurs/3
{
"#context": "\/api\/contexts\/Donateur",
"#id": "\/api\/donateurs\/3",
"#type": "Donateur",
"id": 3,
"nom": "Yazid Ibn Amr",
"solde": 135000,
"isDeleted": false,
"dons": [
{
"#id": "\/api\/dons\/1",
"#type": "Don",
"id": 1,
"date": "2021-07-26T00:00:00+00:00",
"montant": 35000,
"isDeleted": true
},
{
"#id": "\/api\/dons\/2",
"#type": "Don",
"id": 2,
"date": "2021-07-28T00:00:00+00:00",
"montant": 60000,
"isDeleted": false
},
{
"#id": "\/api\/dons\/3",
"#type": "Don",
"id": 3,
"date": "2021-07-28T00:00:00+00:00",
"montant": 75000,
"isDeleted": false
}
]
}
I don't need deleted resource in this returned collection of Don when getting a Donateur item.
Here is my code
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\DonRepository;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={
* "read:Don:item",
* "read:Don:collection"
* }
* },
* denormalizationContext={
* "groups"={
* "write:Don"
* }
* },
* collectionOperations={
* "get", "post"
* },
* itemOperations={
* "get"={
* "normalization_context"={
* "groups"={
* "read:Don:item",
* "read:Don:collection"
* }
* }
* },
* "patch", "delete"
* }
* )
* #ORM\Entity(repositoryClass=DonRepository::class)
*/
class Don
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read:Donateur:item"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Donateur::class, inversedBy="dons")
* #ORM\JoinColumn(nullable=false)
* #Groups({"read:Don:collection", "write:Don"})
*/
private $donateur;
/**
* #ORM\Column(type="date", nullable=true)
* #Groups({"read:Don:collection", "write:Don", "read:Donateur:item"})
*/
private $date;
/**
* #ORM\Column(type="float")
* #Groups({"read:Don:collection", "write:Don", "read:Donateur:item"})
*/
private $montant;
And
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\DonateurRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={
* "read:Donateur:item",
* "read:Donateur:collection"
* }
* },
* denormalizationContext={
* "groups"={
* "write:Donateur"
* }
* },
* collectionOperations={
* "get", "post"
* },
* itemOperations={
* "get", "patch", "delete"
* }
* )
* #ORM\Entity(repositoryClass=DonateurRepository::class)
*/
class Donateur
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups("read:Donateur:collection")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"read:Donateur:collection", "write:Donateur"})
*/
private $nom;
/**
* #ORM\Column(type="text", nullable=true)
* #Groups({"read:Donateur:collection", "write:Donateur"})
*/
private $presentation;
/**
* #ORM\Column(type="float")
* #Groups({"read:Donateur:collection", "write:Don"})
*/
private $solde;
/**
* #ORM\Column(type="boolean")
* #Groups("read:Donateur:collection")
*/
private $isDeleted;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $createdAt;
/**
* #ORM\ManyToOne(targetEntity=User::class)
*/
private $createdBy;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $updatedAt;
/**
* #ORM\ManyToOne(targetEntity=User::class)
*/
private $updatedBy;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $deletedAt;
/**
* #ORM\ManyToOne(targetEntity=User::class)
*/
private $deletedBy;
/**
* #ORM\OneToMany(targetEntity=Don::class, mappedBy="donateur")
* #Groups({"read:Donateur:item"})
*/
private $dons;
And this one
<?php
namespace App\Doctrine;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use Doctrine\ORM\QueryBuilder;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Don;
use App\Entity\Donateur;
use App\Entity\TypeOeuvre;
class NoneDeletedResources implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
public function addWhere(QueryBuilder $queryBuilder, string $resourceClass)
{
if($resourceClass === TypeOeuvre::class or $resourceClass === Don::class or $resourceClass === Donateur::class){
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere("$rootAlias.isDeleted = :isDeleted");
$queryBuilder->orderBy("$rootAlias.id", "DESC");
$queryBuilder->setParameter("isDeleted", false);
}
}
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?string $operationName = null)
{
$this->addWhere($queryBuilder, $resourceClass);
}
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, ?string $operationName = null, array $context = [])
{
// dd($context);
$this->addWhere($queryBuilder, $resourceClass);
}
}
Thank you for helping
$queryBuilder->andWhere("$rootAlias.isDeleted = :isDeleted");
With this code, you're only filtering on the root alias, not on its relations. You should alter your code in such a way that it filters on those relations as well.
public function addWhere(QueryBuilder $queryBuilder, string $resourceClass)
{
if($resourceClass === Donateur::class) {
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere("$rootAlias.isDeleted = :isDeleted");
$queryBuilder->orderBy("$rootAlias.id", "DESC");
$queryBuilder->setParameter("isDeleted", false);
// add something like this:
$queryBuilder->andWhere("dons.isDeleted = :isDeleted");
}
}
The exact name of the alias (I used dons as an example) depends on your use case. Maybe you should join Don before you can use it.
I hope you can use my suggestion to fix your problem. If not, please let me know; I'll help with adding some implementation details.
public function addWhere(QueryBuilder $queryBuilder, string $resourceClass)
{
if($resourceClass === TypeOeuvre::class or $resourceClass === Don::class or $resourceClass === Donateur::class or $resourceClass === Oeuvre::class or $resourceClass === DonOeuvre::class){
$rootAlias = $queryBuilder->getRootAliases()[0];
if($resourceClass === Donateur::class) {
$queryBuilder->join("$rootAlias.dons", "d");
$queryBuilder->andWhere("d.isDeleted = :isDeleted");
}
if($resourceClass === Oeuvre::class or $resourceClass === Don::class) {
$queryBuilder->join("$rootAlias.donOeuvres", "d");
$queryBuilder->andWhere("d.isDeleted = :isDeleted");
// dd($queryBuilder);
}
$queryBuilder->andWhere("$rootAlias.isDeleted = :isDeleted");
$queryBuilder->orderBy("$rootAlias.id", "DESC");
$queryBuilder->setParameter("isDeleted", false);
}
}
The first if is working correctly. But not the second
This is my resources code:
Don.php
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\DonRepository;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={
* "read:Don:item",
* "read:Don:collection"
* }
* },
* denormalizationContext={
* "groups"={
* "write:Don"
* }
* },
* collectionOperations={
* "get", "post"
* },
* itemOperations={
* "get"={
* "normalization_context"={
* "groups"={
* "read:Don:item",
* "read:Don:collection"
* }
* }
* },
* "utilisation_don" = {
* "path" = "/{id}/utilisation-don,
* "controller" =
* }
* "patch", "delete"
* }
* )
* #ORM\Entity(repositoryClass=DonRepository::class)
*/
class Don
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read:Donateur:item"})
*/
private $id;
...
/**
* #ORM\OneToMany(targetEntity=DonOeuvre::class, mappedBy="don")
*/
private $donOeuvres;
Oeuvre.php
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Annotation\Groups;
use App\Repository\OeuvreRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource(
* normalizationContext={
* "groups"={
* "read:Oeuvre:collection"
* }
* },
* denormalizationContext={
* "groups"={
* "write:Oeuvre"
* }
* },
* collectionOperations={
* "get",
* "post" = {
* "denormalization_context"={
* "groups"={
* "write:Oeuvre"
* }
* }
* }
* },
* itemOperations={
* "get",
* "patch" = {
* "denormalization_context"={
* "groups"={
* "update:Oeuvre:patch"
* }
* }
* },
* "delete"
* }
* )
* #ORM\Entity(repositoryClass=OeuvreRepository::class)
*/
class Oeuvre
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups("read:Oeuvre:collection")
*/
private $id;
...
/**
* #ORM\OneToMany(targetEntity=DonOeuvre::class, mappedBy="oeuvre")
* #Groups({"write:Oeuvre"})
*/
private $donOeuvres;
and DonOeuvre.php
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\DonOeuvreRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={
* "read:DonOeuvre:collection"
* }
* },
* denormalizationContext={
* "groups"={
* "write:DonOeuvre"
* }
* },
* collectionOperations={
* "get", "post"
* },
* itemOperations={
* "get", "patch", "delete"
* }
* )
* #ORM\Entity(repositoryClass=DonOeuvreRepository::class)
*/
class DonOeuvre
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read:DonOeuvre:collection", "read:Don:item"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Don::class, inversedBy="donOeuvres")
* #ORM\JoinColumn(nullable=false)
* #Groups({"read:DonOeuvre:collection", "write:DonOeuvre", "write:Oeuvre"})
*/
private $don;
/**
* #ORM\ManyToOne(targetEntity=Oeuvre::class, inversedBy="donOeuvres", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"read:DonOeuvre:collection", "write:DonOeuvre", "read:Don:item"})
*/
private $oeuvre;

Symfony / Doctrine materializedPath issues

I have followed the docs:
https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/tree.md#materialized-path
I am getting the following error:
An exception occurred while executing 'UPDATE task SET path = ?, task_id = ?, lvl = ? WHERE id = ?' with params ["-1", "-1", 0, 1]:
SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'task_id' at row 1
Here is my entity:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\MaterializedPathRepository")
* #Gedmo\Tree(type="materializedPath")
*/
class Task
{
/**
* #ORM\Id
* #ORM\Column(type="integer", options={"unsigned":true})
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=128, nullable=false)
*/
private $title;
/**
* #ORM\Column(type="integer", nullable=true)
* #Gedmo\TreeLevel
*/
private $lvl;
/**
* #ORM\Column(type="integer", nullable=true)
* #Gedmo\TreeLeft
*/
private $lft;
/**
* #ORM\Column(type="integer", nullable=true)
* #Gedmo\TreeRight
*/
private $rgt;
/**
* #ORM\Column(type="string", nullable=true)
* #Gedmo\TreePath(separator=".", startsWithSeparator=false, endsWithSeparator=false)
*/
private $path;
/**
* #ORM\Column(type="string", nullable=true)
* #Gedmo\TreePathSource
*/
private $source;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Task", mappedBy="parent")
* #ORM\OrderBy({"lft":"ASC"})
*/
private $children;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Task")
* #ORM\JoinColumn(name="task_id", referencedColumnName="id", onDelete="CASCADE")
* #Gedmo\TreeRoot
*/
private $root;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Task", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
* #Gedmo\TreeParent
*/
private $parent;
}
What am I not understanding or what am I missing about the configuration for materialized path?
Why are the node ID's coming up as negative also??? Very odd...

change default identity column name in inherited (joined ) class in symfony

I have used a Class Table Inheritance so that my entity "image" inherits from the "media" Entity.
this procedure create an auto generated column id in the image table. How can i change this default name "id" to set it "media_id" so that the image column has a column "media_id" instead of "id" ?
here is my code :
namespace App\Entity\OldApp;
use Doctrine\ORM\Mapping as ORM;
use \App\Entity\OldApp\TemplateContent;
/**
* #ORM\Entity(repositoryClass="App\Repository\OldApp\MediaRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"media" = "Media", "image" = "Image"})
*/
class Media
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer",name="CAT_id")
*/
private $id;
/**
* #ORM\Column(name="filename", type="string", length=100, nullable=false)
*/
private $filename;
/**
* #ORM\Column(name="size", type="string", length=30, nullable=false)
*/
private $size;
/**
* #ORM\Column(name="date", type="datetime", nullable=false)
*/
private $date;
/**
* #ORM\Column(name="high", type="boolean", nullable=false)
*/
private $high = '0';
namespace App\Entity\OldApp;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\OldApp\ImageRepository")
*/
class Image extends Media
{
/**
* #ORM\Column(type="string", length=3)
*/
private $extension;
private static $type='image' ;
/**
* #ORM\Column(type="string", length=50)
*/
private $ratio;
/**
* #ORM\Column(type="smallint")
*/
private $height;
/**
* #ORM\Column(type="smallint")
*/
private $width;
}
i've tryed to add #PrimaryKeyJoinColumn(name="person_id") Bellow #ORM\Entity but i ged the following error
Error
[Semantical Error] The annotation "#Doctrine\ORM\Mapping\PrimaryKeyJoinColumn" in class App\Entity\OldApp\Image doe
s not exist, or could not be auto-loaded.
trait MediaTrait
{
/**
* #ORM\Column(name="filename", type="string", length=100, nullable=false)
*/
private $filename;
// getter //setter
}
/**
* #ORM\Entity(repositoryClass="App\Repository\OldApp\MediaRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"media" = "Media", "image" = "Image"})
*/
class Media
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer",name="CAT_id")
*/
private $id;
use MediaTrait;
}
/**
* #ORM\Entity(repositoryClass="App\Repository\OldApp\ImageRepository")
*/
class Image
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer",name="media_id")
*/
private $id;
use MediaTrait;
// reste of the code
....
}

Doctrine2 cascade create

Here some context information: I'm building a Symfony2 application with Doctrine2 and FOSRestBundle.
My problem: I want to be able to create a parent with his children with just one JSON and one database access.
My JSON looks like this:
{
"name": "TEST_NAME",
"info": "TEST_INFO",
"cmts": [
{
"cmt": "CMT1",
"info": "INFO1"
},
{
"cmt": "CMT2",
"info": "INFO2"
},
{
"cmt": "CMT3",
"info": "INFO3"
}
]
}
Here is my TEST entity:
<?php
namespace App\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Test
*
* #ORM\Table(name="Test")
* #ORM\Entity(repositoryClass="App\Bundle\DemoBundle\Entity\TestRepository")
*/
class Test
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="info", type="string", length=255, nullable=true)
*/
private $info;
/**
* #ORM\OneToMany(targetEntity="TestCmt", mappedBy="test", fetch="EAGER", orphanRemoval=true, cascade={"merge", "remove", "persist"})
*/
protected $cmts;
/**
* Constructor
*/
public function __construct()
{
$this->cmts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add cmts
*
* #param \App\Bundle\DemoBundle\Entity\TestCmt $cmts
* #return Test
*/
public function addCmt(\App\Bundle\DemoBundle\Entity\TestCmt $cmts)
{
$this->cmts[] = $cmts;
return $this;
}
/**
* Remove cmts
*
* #param \App\Bundle\DemoBundle\Entity\TestCmt $cmts
*/
public function removeCmt(\App\Bundle\DemoBundle\Entity\TestCmt $cmts)
{
$this->cmts->removeElement($cmts);
}
/**
* Get cmts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCmts()
{
return $this->cmts;
}
// other getters/setters...
}
And my TESTCMT entity:
<?php
namespace App\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TestCmt
*
* #ORM\Table(name="TestCmt")
* #ORM\Entity(repositoryClass="App\Bundle\DemoBundle\Entity\TestCmtRepository")
*/
class TestCmt
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="cmt", type="string", length=255)
*/
private $cmt;
/**
* #var string
*
* #ORM\Column(name="info", type="string", length=255, nullable=true)
*/
private $info;
/**
* #var Test
*
* #ORM\ManyToOne(targetEntity="Test", inversedBy="cmts")
* #ORM\JoinColumn(name="test_id", referencedColumnName="id")
**/
private $test;
/**
* Set test
*
* #param \App\Bundle\DemoBundle\Entity\Test $test
* #return TestCmt
*/
public function setTest(\App\Bundle\DemoBundle\Entity\Test $test = null)
{
$this->test = $test;
return $this;
}
/**
* Get test
*
* #return \App\Bundle\DemoBundle\Entity\Test
*/
public function getTest()
{
return $this->test;
}
}
And finaly my postTestAction():
public function postTestAction(Request $request)
{
$entity = $this->deserialize($request, 'App\DemoBundle\Entity\Test');
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $entity;
}
When I send the JSON, TEST and TESTCMTs are created. Nevertheless, all "test_id" from the created TESTCMTs are "null"... And that's my problem!
EDIT: with SQL Server Profiler, I can see that Doctrine make that Transact SQL request:
INSERT INTO TESTCMT (test_id, cmt, info) VALUES (null, 'CMT', 'INFO')
I don't know why Doctrine can't send the test_id... TEST is created before TESTCMT, so "test_id" should be reachable for Doctrine to create the associate TESTCMTs.
Can someone helped me to fix it? :)
Remove #ORM\GeneratedValue(strategy="AUTO") and it won't let the DB generate a new id for the Entity

JMS Serializer doesn't expose one property

I making a RESTful app with Symfony and FOSRestBundle. FOSRestBundle uses JMS Serializer to serialize data to json format. I have everything working with one little issue.
This is my Entity class
/**
* Post
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Tomalo\AdminBundle\Entity\PostRepository")
* #ExclusionPolicy("none")
*/
class Post
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="content", type="text")
* #Assert\NotBlank()
*/
private $content;
/**
* #var float
*
* #ORM\Column(name="lat", type="float")
* #Assert\NotBlank()
*/
private $lat;
/**
* #var float
*
* #ORM\Column(name="lon", type="float")
* #Assert\NotBlank()
*/
private $lon;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="sign", type="string", length=50, nullable=true)
* #Expose
*/
private $sign;
/**
* #var integer
*
* #ORM\Column(name="status", type="integer")
*/
private $status=0;
/**
* #var integer
*
* #ORM\Column(name="points", type="integer")
*/
private $points=0;
/**
* #var string
*
* #ORM\Column(name="uuid", type="string", length=43)
* #Assert\NotBlank()
* #Exclude
*/
private $uuid;
private $owner;
//get/set method continue
and this is json I get:
{
"id": 5,
"content": "zxcvzxcvzxc",
"lat": 37.422005,
"lon": -122.084095,
"date": "2013-05-20T05:06:57+0100",
"status": 0,
"points": 0,
"owner": 0
}
In my entity $uuid is the only property haveing #Exclude annotation and is not there as expected but there is $sign property missing as well. As You see I put #Expose annotation to $sign but changed nothing. I tried using #ExclusionPolicy("all") and expose all except for uuid but I'm getting
Warning: json_encode(): recursion detected in E:\workspace\htdocs\tomalo\vendor\jms\serializer\src\JMS\Serializer\JsonSerializationVisitor.php line 29
I found some information as it is some php bug
any idea what is wrong and how to fix it?
You can serialize nulls as empty strings. Guess it help you a bit
$context = new SerializationContext();
$context->setSerializeNull(true);
$objectData = $serializer->serialize($object, 'json', $context);
For FOSRestBundle you can define it in settings
fos_rest:
view:
serialize_null: true
forgottenbas'es solution for FOSRestBundle didn't work for me. I have found a solution here https://github.com/FriendsOfSymfony/FOSRestBundle/pull/480
Use serializer section in your config, not view:
fos_rest:
serializer:
serialize_null: true

Resources