Custom JSON serializers for a Symfony 3 entity - symfony

I have a Symfony 3.2 entity using Doctrine's Translatable extension.
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* Media
*
* #ORM\Table(name="medias")
* #Gedmo\TranslationEntity(class="AppBundle\Entity\Translation\MediaTranslation")
*/
class Media implements Translatable
{
/* [...] */
/**
* #var string|null
*
* #ORM\Column(type="text", nullable=true)
* #Gedmo\Translatable
* #Groups({"single_media"})
*/
private $description;
/* [...] */
}
I know how to use the basic way to serialize this entity in JSON (I use friendsofsymfony/rest-bundle for the serialization of my REST API), but I would like to serialize it in a custom way like this...
{
"description": {
"fr": "description en français",
"en": "english description",
}
}

try this :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* Media
*
* #ORM\Table(name="medias")
* #Gedmo\TranslationEntity(class="AppBundle\Entity\Translation\MediaTranslation")
*/
class Media implements Translatable, \Serializable
{
/* [...] */
/**
* #var string|null
*
* #ORM\Column(type="text", nullable=true)
* #Gedmo\Translatable
* #Groups({"single_media"})
*/
private $description;
/* [...] */
}

Related

Default API Filters Failing when referencing nested properties of related entities

I am configuring a series of ApiFilter classes from the Api-platform stack in a Symfony 4 application. I am finding that any filters using a nested property from an entity relationship takes no effect. Please see my example code below, would really appreciate any assistance with why it may not be working.
The entity I am trying to filter on is:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiProperty;
/**
* PostAuthor
* #ApiResource()
* #ORM\Table(name="POST_AUTHOR", indexes={#ORM\Index(name="IDX_CF3397D94A7000A0", columns={"IDENTITY_ID"})})
* #ORM\Entity(repositoryClass="App\Repository\PostAuthorRepository")
*/
class PostAuthor
{
/**
* #var string
*
* #ORM\Column(name="USER_ID", type="string", length=255, nullable=false)
* #ORM\Id
*/
private $userId;
/**
* #var string
*
* #ORM\Column(name="USERNAME", type="string", length=255, nullable=false)
*/
private $username;
And the collection I am filtering is:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiFilter;
use Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\NumericFilter;
use Doctrine\ORM\Mapping as ORM;
/**
* PostHeader
* #ORM\Table(name="POST_HEADER", indexes={#ORM\Index(name="IDX_1CEEE7D0B65E5FF8", columns={"EMOTION_REF_ID"}), #ORM\Index(name="IDX_1CEEE7D08AFAAB14", columns={"AUTHOR_ID"})})
* #ORM\Entity(repositoryClass="App\Repository\PostHeaderRepository")
* #ApiResource(
* normalizationContext={"groups"={"postheader:read"}},
* denormalizationContext={"groups"={"postheader:write"}},
* )
* #ApiFilter(SearchFilter::class, properties={"author.userId": "partial", "author.username": "partial"})
*/
class PostHeader
{
/**
* #var PostAuthor
*
* #ORM\ManyToOne(targetEntity="PostAuthor")
* #ORM\JoinColumns({#ORM\JoinColumn(name="AUTHOR_ID", referencedColumnName="USER_ID")})
* #Groups({"postheader:read"})
*/
private $author;
I just test on a new project with the same classes than you and it works. I can filter by author.userId.
Please give us your testing request. And the error message ;).

Symfony DiscriminatorColumn - one entity with multiple entities

I have 3 tables, Articles, ArticlesTree, fieldsi18n...
my current code has OnoToOne relationship between fieldsi18n and the other 2 entities.
So my fieldsi18n's table has one column to the articles_id and other for the tree_id... how can I accomplish this with just one column that will be named to element_id
How can i use the DiscriminatorColumn ?
HexFieldI18n:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\HexFieldI18nRepository")
*/
class HexFieldI18n
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="App\Entity\HexArticlesTree", mappedBy="label", cascade={"persist", "remove"})
*/
private $tree;
/**
* #ORM\OneToOne(targetEntity="App\Entity\HexArticles", mappedBy="label", cascade={"persist", "remove"})
*/
/**
* #ORM\OneToOne(targetEntity="App\Entity\HexArticles", mappedBy="label", cascade={"persist", "remove"})
*/
private $article;
}
HexArticles
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\HexArticlesRepository")
*/
class HexArticles
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="App\Entity\HexFieldI18n", inversedBy="article", cascade={"persist", "remove"})
*/
private $label;
}
HexArticlesTree
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\HexArticlesTreeRepository")
*/
class HexArticlesTree
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="App\Entity\HexFieldI18n", inversedBy="article", cascade={"persist", "remove"})
*/
private $label;
}
Any ideas?
Thanks
I don't undertand just one column that will be named to element_id. Doctrine has several annotations like #InheritanceType to determinate the inheranceType SINGLE_TABLE or JOINED. I only have used SINGLE_TABLE inheritance that basicly has columns to determinate its entity, which are saved in the column that you mark with #DiscrimatorType annotation, you must remember that entities will not be persisting to the database, only acts like a descriminator.

Why does Doctrine update related entities, after JMS deserialize

I'm using Doctrine+JMSserializer in Symfony2 project, just found a problem that related entities and their data could be compromised during typical JMS "deserialize" and Doctrine "persist" operation.
$data = [
'locale' => 'en',
'name' => $this->faker->sentence(),
'content' => $this->faker->text(),
'subject' => [
'id' => $page->getId(),
'name' => 'new name' // <-- compromised property
]
];
$rawPayload = json_encode($data);
$entity = $this->serializer->deserialize(
$rawPayload,
$resolvedClass,
'json'
);
and after typical persist operation for new $entity related Page entity name, being change - so its a problem.
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
The goal is to set page Id for the review, but prevent change for other properties, otherwise Page entity can be compromised. I tried to solve this issue changing annotations, doctrine settings, etc..
Any ideas how to solve this issue in natural way?
Review and Page entites:
use Aisel\ReviewBundle\Entity\Review as BaseReview;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation as JMS;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Review
*
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="aisel_page_review")
* #ORM\Entity(repositoryClass="Aisel\ResourceBundle\Repository\CollectionRepository")
* #JMS\ExclusionPolicy("all")
*/
class Review extends BaseReview
{
/**
* #var Page
* #Assert\NotNull()
* #ORM\ManyToOne(targetEntity="Aisel\PageBundle\Entity\Page", inversedBy="pages")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="page_id", referencedColumnName="id", nullable=false)
* })
* #JMS\Type("Aisel\PageBundle\Entity\Page")
* #JMS\Expose
* #JMS\MaxDepth(2)
*/
private $subject;
/**
* #return Page
*/
public function getSubject()
{
return $this->subject;
}
/**
* #param Page $subject
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
}
<?php
namespace Aisel\PageBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use JMS\Serializer\Annotation as JMS;
use Aisel\ResourceBundle\Domain\UrlInterface;
use Aisel\PageBundle\Entity\Node;
use Aisel\PageBundle\Entity\Review;
use Aisel\UserBundle\Entity\User;
use Aisel\ResourceBundle\Domain\IdTrait;
use Aisel\ResourceBundle\Domain\UpdateCreateTrait;
use Aisel\ResourceBundle\Domain\MetaTrait;
use Aisel\ResourceBundle\Domain\LocaleTrait;
use Aisel\ResourceBundle\Domain\StatusTrait;
use Aisel\ResourceBundle\Domain\NameTrait;
use Aisel\ResourceBundle\Domain\ContentTrait;
use Aisel\ResourceBundle\Domain\CommentStatusTrait;
/**
* Page
*
* #author Ivan Proskuryakov <volgodark#gmail.com>
*
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="aisel_page")
* #ORM\Entity(repositoryClass="Aisel\ResourceBundle\Repository\CollectionRepository")
* #JMS\ExclusionPolicy("all")
*/
class Page implements UrlInterface
{
use IdTrait;
use NameTrait;
use ContentTrait;
use LocaleTrait;
use StatusTrait;
use CommentStatusTrait;
use MetaTrait;
use UpdateCreateTrait;
/**
* #var ArrayCollection
* #ORM\ManyToMany(targetEntity="Aisel\PageBundle\Entity\Node")
* #ORM\JoinTable(
* name="aisel_page_page_node",
* joinColumns={#ORM\JoinColumn(name="page_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="node_id", referencedColumnName="id")}
* )
* #JMS\Type("ArrayCollection<Aisel\PageBundle\Entity\Node>")
* #JMS\Expose
* #JMS\MaxDepth(2)
* #JMS\Groups({"collection","details"})
*/
private $nodes;
/**
* #var ArrayCollection<Aisel\PageBundle\Entity\Review>
* #ORM\OneToMany(targetEntity="Aisel\PageBundle\Entity\Review", mappedBy="subject", cascade={"remove"})
* #ORM\OrderBy({"createdAt" = "DESC"})
* #JMS\Expose
* #JMS\MaxDepth(2)
* #JMS\Type("ArrayCollection<Aisel\PageBundle\Entity\Review>")
* #JMS\Groups({"collection","details"})
*/
private $reviews;

how to extend an entity from one bundle to another bundle

i have an already created symfony bundle. i wanted to add another bundle for my application separately. so now im facing a problem that how to extend an entity from old bundle to newly created one. i extended it normally but it giving errors.
i have these 2 bundles,
MyFirstBundle
MySecondBundle
MyFirstBundle entity,
namespace My\FirstBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="companies")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Company
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #Groups({"list_companies", "company_details", "ad_details"})
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=50, nullable=true)'
*
* #Groups({"ad_details"})
*/
private $name;
MySecondBundle Entity,
namespace My\SecondBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use My\FirstBundle\Entity\Company as BaseCompany;
class Companies extends BaseCompany
{
public function __construct() {
parent::__construct();
}
}
im not sure that i can extend my entity like this. im getting error when creating forms with this entity
Class "MySecondBundle:companies" seems not to be a managed Doctrine entity. Did you forget to map it?
You need to add the doctrine annotations for the second entity as well.
/**
*
* #ORM\Table(name="companies")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Companies extends BaseCompany
{
public function __construct() {
parent::__construct();
}
}

Doctrine2 - OneToMany/ManyToOne Bidirectional not working

Hi everyone and thanks for help,
I'm currently dealing with a problem while I want to make an OneToMany/ManyToOne Bidirectional Relationship with Doctrine2 (& Symfony2).
Here are my two classes : User (which extends FOSUser) and collection which represents a collection of videos.
Of course, a user can have several collections, but a collection is only related to one user.
/* COLLECTION */
namespace Com\ComBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Com\ComBundle\Entity\Collection
*
* #ORM\Table(name="collection")
* #ORM\HasLifecycleCallbacks
*/
class Collection
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Com\UserBundle\Entity\User", inversedBy="collections")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* Set user
*
* #param Com\UserBundle\Entity\User $user
* #return Collection
*/
public function setUser(\Com\UserBundle\Entity\User $user) {
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return Com\UserBundle\Entity\User User
*/
public function getUser() {
return $this->user;
}
}
And user,
/* USER */
namespace Com\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/*
* #ORM\OneToMany(targetEntity="Com\ComBundle\Entity\Collection", mappedBy="user")
*/
private $collections;
public function __construct()
{
parent::__construct();
$this->collections = \Doctrine\Common\Collections\ArrayCollection();
}
}
When I use the doctrine:generate:entities command, it does not generate the methods relative to $collections (get/add/remove), and even if I wrote it myself, it does not work.
getCollections() return NULL for example.
What am I missing in this code ?

Resources