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
Related
I created two entities automatically ( using this manual http://symfony.com/doc/2.8/doctrine/reverse_engineering.html) based on ER model generated in Workbench. My intention was to create one-to-one relationship but annotation show it is one-to-many relationship. I created also embeed forms. I would like to insert client and new adress to database. I still get an error:
A new entity was found through the relationship 'UlaBundle\Entity\Client#adres' that was not configured to cascade persist operations for entity: qqq. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}).
Error is shown even if i set #ManyToOne(..,cascade={"persist"}) and __toString function. What is the problem? Please help. Below my code:
///Client Entity
class Client
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45, nullable=true)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \UlaBundle\Entity\Adres
*
* #ORM\ManyToOne(targetEntity="UlaBundle\Entity\Adres", cascade= {"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="adres_id", referencedColumnName="id")
* })
*/
private $adres;
/// Adres Entity
class Adres
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45, nullable=true)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
///Controller
/**
* #Route("/client", name="client")
*/
public function clientAction(Request $request) {
$c = new Client();
$form = $this->createForm(ClientType::class,$c);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$m = $this->getDoctrine()->getManager();
$m->persist($c);
$m->flush();
return new Response('Added');
}
return $this->render('UlaBundle:Default:client_form.html.twig', array('form' => $form->createView()));
}
I think your problem come from the blank space in cascade= {"persist"}, you should remove it
/**
* #var \UlaBundle\Entity\Adres
*
* #ORM\ManyToOne(targetEntity="UlaBundle\Entity\Adres", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="adres_id", referencedColumnName="id")
* })
*/
private $adres;
I'm building a simple web-service using Symfony 3, Doctrine 2.5 and stuck at ORM relations described below in simplified structure.
I have an Action entity containing many actions with ManyToOne relation...
class Action
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="\AppBundle\Entity\Status")
* #ORM\JoinColumn(referencedColumnName="code", nullable=false)
*/
private $status;
and the Status Entity with a few statuses.
class Status
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="integer", unique=true)
*/
private $code;
I cannot get proper way to set referencedColumnName="code" column (not 'Id' as usual) for Action entity.
Configured this way repo throws wxception at persist moment with "Notice: Undefined index: code";
I guess that it is mappedBy or inversedBy annotation parameter... but can't figure out "how".
Unfortunately it's not supported in Doctrine (reference).
You may edit your Status entity like this (ensure that code is set before persist):
class Status
{
/**
* #ORM\Column(name="code", type="integer", unique=true)
* #ORM\Id
*/
private $code;
}
If autoincremented field is your requirement you can take a look on this answer for possible solutions.
Just thought I'd add you can still use the non-primary keys as many to many, by using the entity itself as the join table. This will work but you still need to set your relationship keys correctly.
Example:
/**
* #ORM\Entity
*/
class Car {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Registration", mappedBy="Cars")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")}
* )
*/
public $Registrations;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
/**
* #ORM\Entity
*/
class Registration {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var ArrayCollection
* #ORM\ManyToMany(targetEntity="Car", mappedBy="Registrations")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")},
* inverseJoinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")}
* )
*/
public $Cars;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
The upside is that it works fine as a workaround.
Keep in mind a few things:
it's a collection not a single instance;
column has to be managed manually on your end;
you must set up constraints correctly (indexes, keys, etc);
check your queries still perform!
I have a problem with two entities in Symfony2 with Doctrine:
This is the first Entity:
/**
* Pedidos
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="RestCarta\Bundle\FrontendBundle\Entity\PedidosRepository")
*/
class Pedidos
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="usuario", type="string", length=100)
*/
private $usuario;
/**
* #var string
*
* #ORM\Column(name="mesa", type="string", length=3)
*/
private $mesa;
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Articulos")
* #ORM\JoinColumn(name="articulo_id", referencedColumnName="id")
*/
private $articulo;
/**
* #var string
*
* #ORM\Column(name="precio", type="decimal")
*/
private $precio;
This is the second Entity:
/**
* Articulos
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="RestCarta\Bundle\FrontendBundle\Entity\ArticulosRepository")
*/
class Articulos
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="referencia", type="string", length=100)
*/
private $referencia;
/**
* #var string
*
* #ORM\Column(name="nombre", type="string", length=255)
*/
private $nombre;
/**
* #var string
*
* #ORM\Column(name="descripcion", type="string", length=255)
*/
private $descripcion;
/**
* #var string
*
* #ORM\Column(name="precio", type="decimal")
*/
private $precio;
/**
* #var string
*
* #ORM\Column(name="imagen", type="string", length=255)
*/
private $imagen;
/**
* #ORM\ManyToOne(targetEntity="Categorias", inversedBy="articulos")
* #ORM\JoinColumn(name="categoria_id", referencedColumnName="id")
*/
protected $categoria;
And now the problem.
How i can persist one "Pedido" with contain one "Articulo" ??
I can read all "Pedido" and the LEFT JOIN with "Articulo" work perfectly, (data inserted manually via phpMyAdmin) but when I persist more data with this code:
$em = $this->getDoctrine()->getManager();
$pedido = new Pedidos();
$pedido->setUsuario('blablabla');
$pedido->setMesa('blablabla');
$pedido->setArticulo($identi);
$pedido->setPrecio('blablabla');
$em->persist($pedido);
$em->flush();
$identi = corresponds to an id of "Articulos"
The result is:
Warning: spl_object_hash() expects parameter 1 to be object, string
given in
/Applications/MAMP/htdocs/RestCarta/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php
line 1388 500 Internal Server Error - ContextErrorException
Please, anyone can help me?
Thanks in Advance
$identi must be a entity object, not only the ID you can use
$em->getReference('YourNamespace\Articulos', $identi);
this is my entity:
/**
* #ORM\Table(name="Animal")
* #ORM\HasLifecycleCallbacks
*/
class Animal {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
private $lctitle;
/**
* #var localizedcontent $lcdescription
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcDescription", referencedColumnName="pkId", nullable=false)
*/
private $lcdescription;
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->lctitle;
$lcd = $this->lcdescription;
}
This is my dql:
SELECT a,lct FROM Animal JOIN e.lctitle lct WHERE a.id=:id
When i'm starting xdebug, it tells me that lcdescription is a proxy object and lctitle doesn't exists. I don't know why.
I think the postLoad event is too early because the localizedcontent isn't loaded at this moment, right? Is there an other listener for reading the value of lctitle in relation to the Animal Object?
Thanks
Doctrine always returns proxies. These classes inherit from the entity-classes. It might help if you declare your relations protected instead of private.
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
protected $lctitle;
or you could write a getter and call this one in your post-load function
public function getLctitle() {
return $this->lctitle;
}
public function getLcdescription() {
return $this->lcdescription;
}
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->getLctitle();
$lcd = $this->getLcdescription();
}
I'm having this issue with JMSSerializerBundle. It basically gives me an exception for something that I've already done. This is my entity:
Edited to avoid confusion about annotation lines
<?php
namespace My\ProjectBundle\Entity;
use JMS\SerializerBundle\Annotation\Type;
use Doctrine\ORM\Mapping as ORM;
/**
* My\ProjectBundle\Entity\Music
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="My\ProjectBundle\Entity\MusicRepository")
*/
class Music extends Post
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")
* #Type("string")
*/
protected $album;
/**
* #var string $artist
*
* #ORM\Column(name="artist", type="string")
* #Type("string")
*/
protected $artist;
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
* #Type("string")
*/
protected $title;
/**
* #var array $genres
*
* #ORM\Column(name="genres", type="array")
* #Type("array")
*/
protected $genres;
As you can see, I've added #Type() annotations for the fields, but it still gives me the exception when I call:
$listenedMusic = $serializer->deserialize($content, 'My\ProjectBundle\Entity\Music', 'json');
I've checked and the $content variable is not empty and has all the fields mapped in JSON format.
In my Monolog files, this is the exact Exception:
[2012-11-29 23:39:07] request.CRITICAL: JMS\SerializerBundle\Exception\RuntimeException:
You must define a type for My\ProjectBundle\Entity\Music::$album. (uncaught exception)
at /vendor/jms/serializer-bundle/JMS/SerializerBundle/Serializer/GenericDeserializationVisitor.php line 177
Why does it still give me this exception?
I'm fairly certain it's because you have two comment strings with different pieces of the whole annotation. Symfony only looks at the comment string directly preceding the class member.
Try replacing:
/** #Type("string")*/
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
with:
/**
* #Type("string")
*
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
(and in every other place you have these duplicate annotation comments)
It's only a guess, but I think it'll fix it. When I tried doing this:
class Something
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
/**
*
*/
private $id;
}
...Symfony gave me this error:
No identifier/primary key specified for Entity 'SomeApp\SomeBundle\Entity\Something'. Every Entity must have an identifier/primary key.
I have fixed this by updating my entire project to dev-master packages. It seemed it was a bug in JMSSerializer, because without modifying any code, I stopped getting this error.
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
Type 'int' doesn't exist for serialization, you must use 'integer'.