Symfony Seralizer doesn't serialize OneToOne relation / Doctrin Proxy - php

I'm trying to serialize a Entity that has a OneToOne relation to a Image Entity.
When dumping the Entity I can see that the Image Entity is a Doctrine Proxy and not initialized.
It also doesn't show up in the JSON response when trying to access the Endpoint.
I've tried fetch="EAGER" with no success.
How do I go about serializing this to the "Expected Response" ?
Response:
[
{
"id": 7
}
]
Expected Response:
[
{
"id": 7,
"image": {
"webView": "someUrl"
}
}
]
Entity:
/**
* #ORM\Entity(repositoryClass=BatteryTypeRepository::class)
*/
class BatteryType
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*
* #Groups({"type"})
*/
private $id;
/**
* #ORM\OneToOne(targetEntity=Image::class, cascade={"persist", "remove"})
*
* #Groups({"type"})
*/
private $image;
/**
* #return Image|null
*/
public function getImage(): ?Image
{
return $this->image;
}
public function setImage(?Image $image): self
{
$this->image = $image;
return $this;
}
}
Image Entity:
/**
* #ORM\Entity(repositoryClass=ImageRepository::class)
* #ORM\EntityListeners({"App\EventSubscriber\ImageListener"})
*/
class Image
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
* #Groups({"type"})
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $filename;
/**
* Auto generated by entity listener
* #var string
*/
private $tempFilename;
/**
* #var File
* #Assert\Image()
* #Assert\NotBlank()
*/
private $file;
/**
* #var string
* #Groups({"type"})
*/
private $webView;
/** Getters & Setters */
}
ImageListener:
class ImageListener
{
/**
* #var S3FileManagerInterface
*/
private S3FileManagerInterface $fileManager;
public function __construct(S3FileManagerInterface $fileManager)
{
$this->fileManager = $fileManager;
}
public function postLoad(Image $image, LifecycleEventArgs $args): void
{
$image->setWebView(
$this->fileManager->getUrl($image->getFilename())
);
if (!$image->getTempFilename()) {
$image->setTempFilename($image->getFilename());
}
}
}
Controller:
public function getBatteryTypes(BatteryTypeRepository $batteryTypeRepository): Response
{
$batteryTypes = $batteryTypeRepository->findAll();
$view = $this->view($batteryTypes, Response::HTTP_OK);
$view->getContext()->setGroups(["type"]);
return $this->handleView($view);
}

In your Image entity, you have to add the #Groups({"type"}) annotation for the webView attribute.

My Problem apparently was just cache related

Related

Symfony Serializer: Deserialize with relation

I test the serializer component and try to do the following.
I have an Article entity:
class Article
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\OneToMany(targetEntity=Comment::class, mappedBy="article", orphanRemoval=true, cascade={"persist"})
*/
private $comments;
//getter/setter...
and a Comment entity :
class Comment
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity=Article::class, inversedBy="comments", cascade={ "persist" })
* #ORM\JoinColumn(nullable=false)
*/
private $article;
//getter/setter...
When a send a json to the controller:
{
"title": "My comment",
"content": "This is a comment",
"article": {
"id": 1
}
}
Article with id 1 exists
I would like the relationship with Article to be deserialized:
#[Route('', name: "comment_create", methods: ['POST'])]
public function create(Request $request): JsonResponse
{
$comment = $this->serializer->deserialize($request->getContent(), Comment::class, 'json');
// $this->entityManager->persist($comment);
// $this->entityManager->flush();
return $this->json($comment, Response::HTTP_CREATED);
}
but the article is not linked.
{"id":null,"title":"My comment","content":"This is a comment","article":{"id":null,"title":null,"content":null,"comments":[]}}
Where is my mistake ? Can the symfony serializer do this ?
Try to use following for deserialization:
$comment = $this->serializer->deserialize($request->getContent(), 'App\Entity\Comment', 'json');

Override default property value in Doctrine2 Mapped Superclass

The idea is that extending my Employee class and setting my isManager property would store it as true in the database whenever a DepartmentHead entity was created. This isn't working. Does anyone know why DepartmentHead entities are being stored with isManager equal to false?
/**
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"employee" = "Employee", "dphead" = "DepartmentHead"})
*/
class Employee
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="boolean")
*/
protected static $isManager = false;
/**
* #return bool
*/
public static function isManager(): bool
{
return static::$isManager;
}
/**
* #param bool $isManager
*/
public static function setIsManager(bool $isManager): void
{
static::$isManager = $isManager;
}
}
/**
* #Entity()
*/
class DepartmentHead extends Employee
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
protected $id;
protected static $isManager = true;
}
Do not use static properties, Doctrine cannot cope with them properly.
With a common property, everything works as expected.
/**
* #ORM\Column(type="boolean")
*/
protected $isManager = true;

Symfony 3 Doctrine undefined index

I'm trying to fetch an object from MySQL database using doctrine. It has one-to-one relation with other one. I'm getting this error: Notice: Undefined index: id
What I should correct to make this working?
My fetch code is very simple, I try to fetch all objects:
$emArt = $this->getDoctrine()->getRepository(Article::class);
$articles = $emArt->findAll();
Model is as following:
Article.php
/**
* #ORM\Entity
* #ORM\Table(name="Article")
*/
class Article
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $ID;
/**
* #ORM\OneToOne(targetEntity="ArticleTypes", inversedBy="articleTypeId")
* #ORM\JoinColumn(name="articleTypeId", referencedColumnName="id")
*/
private $articleType;
/**
* #ORM\Column(name="articleName", type="text")
*/
private $articleName;
/**
* #ORM\Column(name="content", type="text")
*/
private $content;
/**
* #ORM\Column(name="image", type="string")
* #Assert\File(mimeTypes={ "image/png" })
*/
public $image;
public function getArticleImage()
{
return $this->image;
}
public function setArticleImage($newImage)
{
$this->image = $newImage;
}
public function getArticleContent()
{
return $this->content;
}
public function setArticleContent($name)
{
$this->content = $name;
}
public function getArticleName()
{
return $this->articleName;
}
public function setArticleName($name)
{
$this->articleName = $name;
}
public function getArticleType()
{
return $this->articleType;
}
public function setArticleType($type)
{
$this->articleType = $type;
}
}
ArticleTypes.php
/**
* #ORM\Entity
* #ORM\Table(name="ArticleTypes")
*/
class ArticleTypes
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\OneToOne(targetEntity="Article", mappedBy="articleTypeId")
*/
private $ID;
/**
* #ORM\Column(name="articleType", type="text")
*/
private $articleType;
public function getArticleType()
{
return $this->articleType;
}
public function setArticleType($newType)
{
$this->articleType = $newType;
}
}
It's a PHP Notice no ? You should have also the line number in a file with the error ?
But I saw errors in your doctrine mapping too : You can't use doctrine annotation like this with fields, you should link your relationship to objects :
/**
* #ORM\Entity
* #ORM\Table(name="Article")
*/
class Article
{
/**
* #ORM\OneToOne(targetEntity="ArticleTypes", inversedBy="article")
* #ORM\JoinColumn(name="articleTypeId", referencedColumnName="id")
*/
private $articleType;
....
}
And :
/**
* #ORM\Entity
* #ORM\Table(name="ArticleTypes")
*/
class ArticleTypes
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Article $article
* #ORM\OneToOne(targetEntity="Article", mappedBy="articleType")
*/
private $article;
....
}
Even if you have a one to one relationship you can have different ids.

OneupUploaderBundle relation between 2 entities

I'm new on stackoverflow and I hope you can help me.
I use OneupUploaderBundle on symfony2 and it's working I can upload multiple images and I can persist them in my database.
But now I would like to upload multiple images for one 'Annonce' for exemple so, I have 2 entities
Annonce
namespace TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Annonce
*
* #ORM\Table(name="annonce")
* #ORM\Entity(repositoryClass="TestBundle\Repository\AnnonceRepository")
*/
class Annonce
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=255)
*/
private $titre;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set titre
*
* #param string $titre
* #return Annonce
*/
public function setTitre($titre)
{
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre()
{
return $this->titre;
}
}
And my Entity Image
namespace TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Image
*
* #ORM\Table(name="image")
* #ORM\Entity(repositoryClass="TestBundle\Repository\ImageRepository")
*/
class Image
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Image
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #ORM\ManyToOne(targetEntity="TestBundle\Entity\Annonce")
* #ORM\JoinColumn(nullable=false)
*/
private $annonce;
/**
* Set annonce
*
* #param \TestBundle\Entity\Annonce $annonce
* #return Image
*/
public function setAnnonce(\TestBundle\Entity\Annonce $annonce)
{
$this->annonce = $annonce;
return $this;
}
/**
* Get annonce
*
* #return \TestBundle\Entity\Annonce
*/
public function getAnnonce()
{
return $this->annonce;
}
}
My EventListener
namespace TestBundle\EventListener;
use Doctrine\Common\Persistence\ObjectManager;
use Oneup\UploaderBundle\Event\PostPersistEvent;
use TestBundle\Entity\Annonce;
use TestBundle\Entity\Image;
class UploadListener
{
/**
* #var ObjectManager
*/
private $em;
public function __construct(ObjectManager $em)
{
$this->em = $em;
}
public function onUpload(PostPersistEvent $event)
{
$file = $event->getFile();
$annonce = new Annonce();
$image = new Image();
/* TEST */
$annonce->setTitre("I'am a title");
$this->em->persist($annonce);
$image->setName($file->getFilename());
$image->setAnnonce($annonce);
$this->em->persist($image);
$this->em->flush();
$response = $event->getResponse();
$response['files'] = [
'name' => $file->getFilename(),
'size' => $file->getSize()
];
}
The problem is, when I upload many images, I have the same number of row in Annonce as in Image.
Someone can help me please :)

#ExclusionPolicy("all") and #Expose do nothing

I don't understand why the annotation do nothing on my GET REST API.
I have the JMS Serializer in vendor with all the class.. but when i call my webservice, there are all my properties which appears.. Whereas i did an #ExlusionPolicy("all") and just #Expose on the ID property..
This is my Entity Product :
<?php
namespace GroupeGC\Bundle\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Jms\Serializer\Annotation as JMS;
/**
* Product
*
* #ORM\Table(name="gc_product")
* #ORM\Entity
* #JMS\ExclusionPolicy("all")
*
*/
class Product
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #JMS\Type("integer")
* #JMS\Expose
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=255, nullable=false)
*/
private $code;
/**
* #var string
*
* #ORM\Column(name="label", type="string", length=255, nullable=true)
*
*/
private $label;
/**
* #var float
* #ORM\Column(name="volume", type="float")
*
*/
private $volume;
/**
* #var float
* #ORM\Column(name="weight", type="float")
*/
private $weight;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set code
*
* #param string $code
* #return Product
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set label
*
* #param string $label
* #return Product
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* #return string
*/
public function getLabel()
{
return $this->label;
}
public function getVolume() {
return $this->volume;
}
public function setVolume($volume) {
$this->volume = $volume;
return $this;
}
public function getWeight() {
return $this->weight;
}
public function setWeight($weight) {
$this->weight = $weight;
return $this;
}
But we can see that , normaly, i just should have the id propertie which should appear in my JSON , whereas i have all propertie.. and i don't understand.
EDIT 1 : This is the fos_rest config in app/config :
fos_rest:
view:
failed_validation: HTTP_BAD_REQUEST
default_engine: php
formats:
json: true
xml: true
format_listener:
prefer_extension: true
body_listener:
decoders:
json: fos_rest.decoder.json
xml: fos_rest.decoder.xml
routing_loader:
default_format: json
fos_js_routing:
routes_to_expose: [oro_*]
i don't think there are a problem here ..
By default, the serializer will retrieve, or set the value via reflection. here. So every property in your entity will be retrieve/set.
/**
* #JMS\ExclusionPolicy("all")
* #JMS\AccessType("public_method")
*/
When using the AccessType annotation, you are telling the serializer to use the public methods (such as getX, setX, hasX) to retrieve/set the values.

Categories