Symfony 4 #UniqueEntity does not work on GEDMO tree composite fields - php

I seem to have done the set up correctly, but still this does not work, ie, it will not set the database table correctly. In fact it ignores completely the #UniqueEntity annotation.
I am setting up a GEDMO tree, where the title of the category should not be repeated for the same parent_id.
So, looking at the the #UniqueEntity documentation and also at some prior code I built, this should work:
/App/Entity/Category
namespace App\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #Gedmo\Tree(type="nested")
* #ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
* #UniqueEntity(
* fields={"parent", "title"}, // or fields={"parent_id", "title"}
* errorPath="title",
* message="This title is already in use for this parent.")
* #ORM\Table(name="categories")
*/
class Category
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(type="string", length=190)
*/
private $title;
.....
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
....
}
There's actually a similar question in here, without a solution.

If you want checking on the database level you will need to use Doctrine's UniqueConstraint annotation:
/*
* #ORM\Table(name="categories", uniqueConstraints={
* #ORM\UniqueConstraint(name="uq_cat_parent_title", columns={"parent_id", "title"})
* })
*/
EDIT: Modified my answer to include the name of the index. Doctrine documentation states that it is required.

Related

Disable automatic Id field generation in Doctrine

Disable automatic Id field generation in Doctrine
this a part of my entity file:
<?php
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Variables
* #ORM\Table(name="variables")
* #ORM\Entity(repositoryClass="MyBundle\Repository\VariablesRepository")
*/
class Variables
{
/**
* #var int
* #ORM\Column(name="variablesRef", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $variablesRef;
/**
* #var string
* #ORM\Column(name="variablesLibelle", type="string", length=250)
*/
private $variablesLibelle;
when i try to create a schema :
erreur
Property MyBundle\Entity\Employeursecteur::$id does not exist
i want to Disable automatic Id field generation in Doctrine
i don't need the id Column
please help
If you want a primary key field without a generated value you just have to set the strategy of generation to none:
#ORM\GeneratedValue(strategy="NONE")

Error on doctrine:schema:update, table with name already exists

in my entity Class i have added some new attributes and i want to update schema of my database. So when i run php app/console doctrine:schema:update --force im getting this error every time
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'postgres.day' already exists.
and my database won't update. So does anyone know how to solve this problem?
I have read the other question with that problem but it didn't helped me. So can anyone explain me whats going on, or how to solve this? Thanks.
<?php
namespace DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RadniNalog
*
* #ORM\Table()
* #ORM\Entity
*/
class RadniNalog
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="time_from", type="string", length=255)
*/
private $time_from;
/**
* #var string
*
* #ORM\Column(name="time_to", type="string", length=255)
*/
private $time_to;
/**
* #var string
*
* #ORM\Column(name="full_date_time", type="string", length=255)
*/
private $full_date_time;
}
it can cause this error message if you want to use a table name which is already used by one of the installed bundles.
In your case the conflicting table name is: day.
#ORM\Table no name provided within your annotation, which is required. See: Doctrine ORM | 21. Annotations Reference
#ORM\Table(name="radniNalog")
Either don't add the annotation if you want the default behaviour of Doctrine or add it correctly with the required options.

Symfony 3.1 Doctrine Entity Cannot alter table add foreign key

Symfony 3.1 - Doctrine: I am trying to add relationships between entities and thereby want to add foreign key to link tables in my example. I tried several settings, utilizing various combination of arguments, but none of them were able to ALTER the tables with Foreign key.
My entities are namely "Trips" and "Airlines" with the content attached below. I would like to use airline_id as a foreign key inside trips table. Here are the extract from my entity scripts:
Entity#1: Trips
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="trips")
*/
class Trips
{
/**
* #ORM\Column(name="trip_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $trip_id;
/**
* #ORM\Column(name="airline_id", type="integer")
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Airlines")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="airline_id", referencedColumnName="airline_id")
* })
*/
private $airline_id;
}
Entity#2: Airlines
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="airlines")
*/
class Airlines
{
/**
* #ORM\Column(name="airline_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $airline_id;
/**
* #ORM\Column(type="string", length=80)
*/
private $name;
}
I tried updating the schema from console , but all it says is
Nothing to update - your database is already in sync with the current entity metadata.
Also tried deleting the table and re-creating them with console; the result did not change much and the foreign key is still missing. :/
Any thoughts, or perhaps you know the solution?
I have a few suggestions, as I've gone through the same process of design.
First off, should I presume that "a trip has one airline" and also "an airline has many trips"? This seems logical, and since you show #ORM\ManyToOne annotation for the Trips class, that would equate to my same presumptions.
If this is so, then these are the suggestions:
First, don't call the classes "Trips" and "Airlines", but rather in the singular, that is "Trip" and "Airline". This is object oriented thinking. So when you create a "Trip" Doctrine object, it represents a trip for example. This also makes you code more readable and also supportable from a future standpoint; as because when people read your code, they will understand that a single instance of a Trip (from the Trip class), represents a trip (that a person takes). This is important when designing code.
Given the above, make these code changes.
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="trip")
*/
class Trip
{
/**
* #ORM\Id
* #ORM\Column(name="trip_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $trip_id;
/**
* #ORM\ManyToOne(targetEntity="Airline", inversedBy="trips")
* #ORM\JoinColumn(name="trip_airline_id", referencedColumnName="airline_id")
*/
private $airline;
...
/**
* Set airline - Adds this trip to the passed in airline and sets the airline
* property to resultant airline.
*
* #param \AppBundle\Entity\Airline
*/
public function setAirline($airline){
$airline->addTrip($this);
$this->airline = $airline;
}
}
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="airlines")
*/
class Airlines
{
/**
* #ORM\Column(name="airline_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $airline_id;
/**
* #ORM\Column(type="string", length=80)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Trip", mappedBy="airline")
*/
protected $trips = null;
...
public function __construct(){
// This is an array of trips.
$this->trips = new ArrayCollection();
}
...
/**
* Add trip - Adds a course to the array.
*/
public function addTrip($trip){
$this->trips[] = $trip;
}
}
Now you can get trips from the airline, and also you can do the other way around, get the airline from the trip.
When #ORM\Column is specified along with #ORM\JoinColumn on same column, then JoinColumn's association gets ignored and Foreign Key isn't created on table. so dont use both #ORM\Column and #ORM\JoinColumn in same column. There is no need to specify data type with #ORM\Column for associations, doctrine handles it and assign data type based on database engine. For MySql, it is int.

PHP Doctrine2 property inheritance

I have this scenario.
Entity File, with some usefull properties like path for file and others.
Entity Image, which is file too, so it have same properties, but contains some more as width,height...
My implementation looks like this
Entity File.php
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity
* #ORM\Table(name="files")
* #Vich\Uploadable
*/
class File
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="file_seq")
* #var integer
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
* #var string
*/
protected $fileName;
.
.
.
Entity Image.php
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity
* #ORM\Table(name="images")
* #Vich\Uploadable
*/
class Image extends File
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="image_seq")
* #var integer
*/
protected $id;
.
.
other properties...
}
Everything works just fine except of property id. Table images is not joined to image_seq(which also is not even created) and takes nextval from file_seq. Is there any way how to get this scenario fully working and inherit entities? Thanks.
This is a perfect situation for implementing a mapped superclass.
You need to tell doctrine what type of inheritance you would like to apply. Read the docs for the different strategies Doctrine supports.
If you want to have a table for file as well as image then use 'Class Table Inheritance' - still read the docs you have been provided with by the other answers. This is suitable for you given your input!
You won't need to define $id again in your Image class and you shouldn't.

Update Recursive entity property

I have a recursive entity containing parent/children item
namespace Vendor\StructureBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Events;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Vendor\StructureBundle\Entity\Structure
* #Gedmo\Tree(type="nested")
*
* #ORM\Table(name="lowbi_structure")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
* #ORM\HasLifecycleCallbacks()
* #CustomAssert\ganttDate
*/
class Structure {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
/**
* #ORM\Column(name="title", type="string", length=64)
*/
private $title;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Structure", inversedBy="children",cascade={"persist"})
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
private $parent;
/*
* #ORM\OneToMany(targetEntity="Structure", mappedBy="parent",cascade={"persist","remove"})
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
...
}
and i want to update the "parent" when i persit this entity.
/**
* Set prePersist
*
* #ORM\PrePersist()
* #ORM\PreUpdate()
*
*/
public function prePersist()
{
$this->getParent()->setTitle('Foo');
}
The probleme is that my current entity is persisted but the parent entity is not. The title is not saved. How can i save the parent's properties?
PS : I simplified the code. In real world, i need to update parent start dates/end dates to fit the children (project management tree)
What you're trying to do here is not possible with a Lifecycle callback (i.e. #PrePersist) if you save only the child afterwards.
Doctrine only tracks and saves changes to the owning side of a relation.
When a bidirectional assocation is updated, Doctrine only checks on
one of both sides for these changes. This is called the owning side of
the association.
Therefore you can't persist an update of the parent from the child by persisting the child only.
You can find more information about the concepts of the inverse and owning side in this answer and in the documentation chapter Working with Associations.
To solve this issue ... you can either persist the parent instead of the child ... or (instead of using the lifecycle callback #PrePersist) create an event listener that will automatically persist the parent. This is a better practice in general because it keeps application logic out of your model.
The documentation chapter How to Register Event Listeners and Subscribers provides all the necessary information to get you started.
I don't know why, but if i return $this in the prePersist function, IT WORKS.
**
* Set prePersist
*
* #ORM\PrePersist()
* #ORM\PreUpdate()
*
*/
public function prePersist()
{
//$this->getParent()->setTitle('Foo');
return $this->getParent()->setTitle('Foo'); //solved this problem!!!!
}

Categories