I have entities that make use of Inheritance Mapping Doctrine inheritance. I have a custom identifier that I generate with #ORM\PrePersist(), which is in a trait and this is used in the parent class.
I want to be able to update properties that the child class has, for this reason, I need to run endpoints on the child entity
When I run an item operation, api platform can't find the resource.
PATCH /api/childas/{hash}
NotFoundHttpException
Not Found
api platform, it doesn't recognize hash as identifier. Take the id as your identified, even if it is false and hash is true.
Trait to generate hashes with which I identify the resource
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use Doctrine\ORM\Mapping as ORM;
trait HashableTrait
{
/**
* #ORM\Column(type="string", length=255)
* #ApiProperty(identifier=true)
*/
private $hash;
public function getHash(): ?string
{
return $this->hash;
}
/**
* #ORM\PrePersist()
*/
public function setHash()
{
$this->hash = \sha1(\random_bytes(10));
}
}
Parent class, is the table where the hash will be stored
<?php
namespace App\Entity;
use App\Entity\HashableTrait;
/**
* #ORM\HasLifecycleCallbacks()
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="integer")
* #ORM\DiscriminatorMap({
* 1 = "App\Entity\ChildA",
* 2 = "App\Entity\ChildB"
* })
*/
class Parent
{
use HashableTrait;
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #ApiProperty(identifier=false)
*/
private $id;
public function getId(): ?int
{
return $this->id;
}
// Properties, setters, getters
}
Child class, on which I want to perform operations, such as updating some property that belongs to this class
<?php
namespace App\Entity;
class ChildA extends Parent
{
// Custom properties for ChildA
}
Config api platform operations for entity Child
App\Entity\ChildA:
collectionOperations:
post: ~
itemOperations:
post: ~
get: ~
patch: ~
delete: ~
I have thought about using data providers, but I keep getting the error.
The error was because both the hash property in the trait and the id property in the parent entity must be accessible from the entity to use.
Doctrine ORM uses reflection class to get information about attributes and their annotations. ReflectionClass::hasProperty obviously does not allow viewing private properties in the parent class.
Related
I am using Symfony 4 and with Doctrine where I have entities which have the same common attributes such as createdWhen, editedWhen, ...
What i would like to do is this:
Defining a kind of base entity that holds these common attributes and implements the setter and getter. And many entities which inherit from that base entity. The database fields should all be defined in the table of the respective sub entity (no super table or the like should be created in the db).
Example:
/**
* #ORM\Entity(repositoryClass="App\Repository\BaseRepository")
*/
class Base
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=127, nullable=true)
*/
private $createdWhen;
// Getter and setter
...
}
/**
* #ORM\Entity(repositoryClass="App\Repository\PersonRepository")
*/
class Person extends Base
{
/**
* #ORM\Column(type="string", length=127, nullable=true)
*/
private $name;
// Getter and setter
...
}
/**
* #ORM\Entity(repositoryClass="App\Repository\CarRepository")
*/
class Car extends Base
{
/**
* #ORM\Column(type="string", length=127, nullable=true)
*/
private $brand;
// Setter and getter
...
}
This should create the tables "person" and "car" (each with id, created_when) but no table base.
I would still like to be able to use the bin/console make:migration for updating the database schema.
Is this kind of approach possible with Symfony 4? If yes how would I define the entities and what do I have to change in terms of configuration, etc.?
You are looking for entity inheritance
Rewrite your code like so
/** #MappedSuperclass */
class Base
{
...
}
In fact, this is a part of Doctrine, here is what an official documentation says
A mapped superclass is an abstract or concrete class that provides
persistent entity state and mapping information for its subclasses,
but which is not itself an entity. Typically, the purpose of such a
mapped superclass is to define state and mapping information that is
common to multiple entity classes.
I'm facing an issue concerning OneToOne relation between some Entities.
The subtlety is that the owner side can be multiple classes (all children of the same class).
Here is the summary
I've got Process which have several children entity classes (let's take ProcessPassport, ProcessIdentityCard and ProcessCadaster for example)
Some of my children entities need a relation with another entity TaxStamp, but not all of them. So I cannot put this association in the Process main entity.
Instead I created a trait TaxStampTrait, containing my relation mapping.
But this does not work properly :
I cannot define multiple possibilities for the association on the TaxStamp entity
Doctrine tells me there are error in my annotations for the relation, because I refer to the Process (legit since only some entities use the TaxStampTrait)
Question: what should I do to make it all work the right way?
Here is the gist with a summary of the code and classes: https://gist.github.com/bastos71/8e15f69ebecf5e97dc75187d130fe109
<?php
/**
* #ORM\Entity(repositoryClass="ProcessRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
*/
class Process
{
// ...
}
<?php
/**
* #ORM\Entity(repositoryClass="ProcessCadasterRepository")
*/
class ProcessCadaster extends Process implements EntityWithTaxStampInterface
{
use TaxStampTrait;
// ...
}
<?php
/**
* #ORM\Entity(repositoryClass="ProcessIdentityCardRepository")
*/
class ProcessIdentityCard extends Process implements EntityWithTaxStampInterface
{
use TaxStampTrait;
// ...
}
<?php
/**
* #ORM\Entity(repositoryClass="ProcessPassportRepository")
*/
class ProcessPassport extends Process implements EntityWithTaxStampInterface
{
use TaxStampTrait;
// ...
}
<?php
/**
* #ORM\Entity(repositoryClass="TaxStampRepository")
*/
class TaxStamp
{
/**
* #ORM\OneToOne(targetEntity="Advercity\AdminBundle\Entity\Process", mappedBy="taxStamp")
*/
private $process;
// ...
}
<?php
trait TaxStampTrait
{
/**
* #ORM\OneToOne(targetEntity="TaxStamp", cascade={"persist"})
* #ORM\JoinColumn(name="tax_stamp_id", referencedColumnName="id")
*/
private $taxStamp;
// ...
}
I'm using the SyliusResourceBundle as a standalone package for exposing data through an API.
When i request entities that have relationships with some other entities, i always get a full response with all the related entities properties included. This leads to heavy JSON responses, and too much data to download on the client side.
Typically, if my entity has a $user property like this :
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="object")
*/
private $user;
I get all the user's stuff in the API response when i request the object : name, email, etc.
Is there a way to only get a list of properties/entities i need ? Like with an annotation or something ?
Thanks
For the record, SyliusResourceBundle uses JMSSeriliazerBundle, so it was just a matter of exclusion policy in the Resource Entity.
I just had to exclude all fields at the Entity level, and only expose the field i needed like this :
namespace AppBundle\Entity;
use JMS\Serializer\Annotation as JMS;
use Sylius\Component\Resource\Model\ResourceInterface;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #JMS\ExclusionPolicy("all")
*/
class MyResource implements ResourceInterface
{
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="object")
*/
private $user;
/**
* #ORM\Column(type="string")
* #JMS\Expose()
*/
private $name;
}
See doc here.
I have two entities Entity1 and Entity2 with a OneToMany relation, but they live in two MySQL databases.
How can I implement those entities with their relation in Symfony?
Is it possible to create two separated bundles where to implement those entities?
In Doctrine, joining data across databases is not technically “supported” by a designed feature, but you can make it work by tricking Doctrine a little bit.
If you want to build a relationship between entities then they must use the same connection: same database.
The key to getting multiple databases to work is within your entity classes, you need to specify the table name of the entity with a prefix of the name of the database to which the table belongs. Here is an example using annotations:
<?php
namespace Demo\UserBundle\Entity;
use DoctrineORMMapping as ORM;
/**
* Demo\UserBundle\Entity\User
*
* #ORMTable(name="users.User")
*/
class User implements
{
/* ... */
}
and
<?php
namespace Demo\PostBundle\Entity;
use DoctrineORMMapping as ORM;
/**
* Demo\PostBundle\Entity\Post
*
* #ORMTable(name="posts.Post")
*/
class Post implements
{
/* ... */
}
and the relation table:
<?php
namespace Demo\PostBundle\Entity;
use DoctrineORMMapping as ORM;
/**
* Demo\PostBundle\Entity\Post
*
* #ORMTable(name="posts.Post")
*/
class Post implements
{
/**
* #ORM\ManyToOne(targetEntity="\Demo\UserBundle\Entity\User")
**/
private $user;
/* ... */
/**
* Set user
*
* #param \Demo\UserBundle\Entity\Site $site
* #return Post
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Demo\UserBundle\Entity\Site
*/
public function getUser()
{
return $this->user;
}
}
Here an article about it.
Hope this help
What is the debugger trying to tell me from that red notification in the toolbar?
When i clicked it, it showed me some papping errors. Why is it an error?
Category Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Category
*
* #ORM\Table(name="ewaste_category")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Category
{
/**
* #ORM\OneToMany(targetEntity="Type", mappedBy="category")
*/
protected $type;
}
Model Entity
class Model
{
/**
* #ORM\ManyToOne(targetEntity="Type", inversedBy="model")
* #ORM\JoinColumn(name="model_id", referencedColumnName="id")
*/
protected $type;
}
Type entity
class Type
{
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="type")
* #ORM\JoinColumn(name="type_id", referencedColumnName="id")
*/
protected $category;
/**
* #ORM\OneToMany(targetEntity="Model", mappedBy="model")
*/
protected $model;
}
Solved the problem.
I changed the $type to $model in Model Entity
You should check your doctrine mapping configuration specialy indexedBy and mappedBy properties
You have an entity named Type that has a relationship with another entity named Model.
Somewhere in Type you have an association that tries to map to a field that should be into Model entity (named model itself) that isn't there. This is first error you're seeing here.
Second error talks about Model entity. It says that the association between Category and Model and Model And Type are not consistent, so you're using some fields for mappings that aren't correct.
Could you paste those three entities so we can provide you a solution also?