Create an inheritance table and how to get superclass ? Doctrine Symfony - symfony

I've two entities: Act and Birth with Birth which extends Act like that
/**
* Act
*
* #ORM\InheritanceType("JOINED")
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\ActRepository")
*/
class Act
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=30, nullable=true)
*/
private $type;
}
/**
* Birth
*
* #ORM\Table(name="birth")
* #ORM\Entity(repositoryClass="AppBundle\Repository\BirthRepository")
*/
class Birth extends Acte
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
And when I create a birth instance
new Birth();
I would like to recover the instance of its super class ie Act Entity !
I have to assign it to another class (Individual) with individual->setAct() and not individu->setBirth() ...
I do not know if it's possible but I want some advice for another approach
Thanks !

Just do no redefine the $id in the child class, and declare the $id in Act protected.
Then
$birth = new Birth();
if($birth instanceof Act){
// TRUE!
// you could access $birth->type if it was public
}

Related

Add ArrayCollection of Entities in the same entity type

Is it possible to keep an array of entities A in the entity A ? How to do this with Doctrine ?
I have :
class A {
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*/
private $sisters;
}
But I don't know what to add to have Doctrine do what I need.
A can have many sisters, and many sisters can be sister of A (Many-To-Many, Self-referencing):
/**
* #ORM\Entity()
* #ORM\Table()
*/
class A
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\A")
*/
private $sisters;
}
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-self-referencing

How can I access a global list within a entity without relation mappings?

I have two doctrine entities defined as below:
/**
* #ORM\Table(name="users")
* #ORM\Entity
*/
class User {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string")
*/
private $name;
}
/**
* #ORM\Table(name="holidays")
* #ORM\Entity
*/
class Holiday {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="date")
*/
private $date;
}
Holiday is a global list of holidays. There is no relation (Doctrine Mapping) between User and Holiday but I need to access holidays in user class.
How can I access holidays within user class without any mappings? I don't want to inject Entity Manager into my user class.
Update: Let's assume I have a method in User like below:
function getWorkedDaysExcludingHolidays() {
// calculation $days here based on holidays
return $days;
}

Doctrine2 relation for non Id column

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!

One join table for two Many-to-Many relations

I'm working on a solution for adding tags to two differente entities.
in order to get data easily in the frontend i created a joinTable named Tag_Mapping like this :
class TagMapping
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Tag", inversedBy="tags")
*/
private $tag;
/**
* #ORM\ManyToOne(targetEntity="Feed", inversedBy="tags")
*/
private $feed;
/**
* #ORM\ManyToOne(targetEntity="Question", inversedBy="tags")
*/
private $question;
...
}
The Tag Entity :
class Tag
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255, unique=true)
*/
private $name;
/**
* #Gedmo\Slug(fields={"name"})
* #ORM\Column(unique=true)
*/
private $slug;
/**
* #ORM\OneToMany(targetEntity="TagMapping", mappedBy="tag", cascade="remove")
*/
private $tags;
...
}
and in both other entities (Feed and Question) I made reference to TagMapping entity like this
...
/**
* #ORM\ManyToMany(targetEntity="Tag")
* #JoinTable(name="tag_mapping",
* joinColumns={#JoinColumn(name="feed_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
private $tags;
...
the problem I'm facing is that it's not a valid way to do it, as it shows an error when i'm trying to execute :
php app/console doctrine:schema:update --force
saying that tag_mapping table already exists.
do you have any idea how can i get it done using only one joinTable instead of one for each relation ?
Thanks.

Multiple JoinColumns in Symfony2 using Doctrine annotations?

Here is the problem:
Class Routing with attributes objectId and objectType. objectId is an int, and objectType is a string. The reason for this was to allow the same table to hold data for different kind of routings. For instance for the routing of Products, Department and Brand. So, the combination of the objectType and the objectId is my JoinColumn.
How do I create such a bidirectional relationship with Doctrine2? I looked at inherited relationships, but none of the concepts seemed to be what I'm looking for.
I could create some views in the database and just have a couple of different Routing entities, but this does not seem the best route.
Here are my entities Department, Product and Brand.
../Entity/Department.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="departments")
*/
class Department implements DescribableInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status;
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
../Entity/Product.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product implements DescribableInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status;
/**
* #ORM\Column(name="product_code", type="string", length=100, nullable=true)
*/
private $productCode = '';
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
../Entity/Brand.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="brands")
*/
class Brand
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status = 'a';
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
Each product, brand and department has its own URL that is held in the routing table set by the object_type and object_id where the object_type is simply department, product or brand and the object_id is the unique id of the corresponding product, brand or department.
../Entity/Routing.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="routing")
*/
class Routing
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="object_id", type="integer", length=11)
*/
private $objectId;
/**
* #ORM\Column(name="object_type", type="string", length=100)
*/
private $objectType;
/**
* #ORM\Column(name="url", type="text")
*/
private $url;
...
What I am really struggling with is how do I setup the relationship, so the departments, products and brands can access their URL from the single routing entity.
I have tried adding the relationships to the $objectId, but it doesn't seem to like that. Is it possible to set this up like this?
What I am basically trying to achieve is to get the data object and have the ability to get the URL of an object, for example:
$departments = $em->getRepository("AdamStaceySiteBundle:Department")->findAll();
foreach ($departments as $department)
{
echo ''.$department->getMenuTitle().';
}
Can anyone help?
After further researching I found a man (Dirk Olbertz) in the know who had the same problem.
Information can be found at: Google Groups: Multiple JoinColumns?
I have now implemented this and I will explain how I did it incase it might help anyone else.
The answer to my problem was the use of single table inheritance.
The first thing I needed to do was update the routing entity to use single table inheritance:
../Entity/Routing.php
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="object_type", type="string")
* #ORM\DiscriminatorMap({"product" = "ProductRouting", "department" = "DepartmentRouting", "brand" = "BrandRouting"})
* #ORM\Table(name="routing")
*/
class Routing
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
The DiscriminatorColumn allowed me to specify what column would be used to link, which in this case was the object_type field.
The DiscriminatorMap allowed me to specify what object_type will link with what entities.
These entities then had to be created that extended the Routing entity.
../Entity/ProductRouting.php
/**
* #ORM\Entity
*/
class ProductRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Product")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $product;
...
../Entity/DepartmentRouting.php
/**
* #ORM\Entity
*/
class DepartmentRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Department")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $department;
...
../Entity/BrandRouting.php
/**
* #ORM\Entity
*/
class BrandRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Brand")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $brand;
...
Then in each of the Product, Department and Brand entities I needed to add the new $routings.
../Entity/Product.php
...
class Product
{
...
/**
* #ORM\OneToMany(targetEntity="ProductRouting", mappedBy="product", cascade={"all"})
*/
private $routings;
...
../Entity/Department.php
...
class Department
{
...
/**
* #ORM\OneToMany(targetEntity="DepartmentRouting", mappedBy="department", cascade={"all"})
*/
private $routings;
...
../Entity/Brand.php
...
class Brand
{
...
/**
* #ORM\OneToMany(targetEntity="BrandRouting", mappedBy="brand", cascade={"all"})
*/
private $routings;
...
Hope that helps...

Resources