Symfony UniqueEntity for two Fields doesn't work - php

I want to use an Unique entity over the fields companyID and personMailaddress.
When I use just the personMail in the fields it works without any problems. But when I add another field to the array, like below, it ignores my UniqueEntity.
/**
* person
*
* #ORM\Table(name="person")
* #ORM\Entity(repositoryClass="AppBundle\Repository\personRepository")
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(
* fields={"personMail", "companyID"},
* errorPath="personMail",
* message="ERROR_MAIL_DUPLICATE",
* )
* #Serializer\ExclusionPolicy("all")
*/
class person
{
...
/**
* #ORM\ManyToOne(targetEntity="company", inversedBy="persons")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=true)
*
*/
protected $companyID;
/**
* #var string
*
* #ORM\Column(name="personMail", type="string", length=150)
* #Assert\NotBlank(message="ERROR_MAIL_EMPTY")
*
* #Serializer\Expose
*/
private $personMail;

To enable unique you need to add the UniqueEntity validator and add unique to the column definition.
<?php
use Doctrine\ORM\Mapping as ORM,
Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity,
Symfony\Component\Validator\Constraints as Assert;
/**
* person
*
* #ORM\Table(name="person")
* #ORM\Entity(repositoryClass="AppBundle\Repository\personRepository")
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(
* fields={"personMail", "companyID"},
* errorPath="personMail",
* message="ERROR_MAIL_DUPLICATE",
* )
* #Serializer\ExclusionPolicy("all")
*/
class person
{
...
/**
* #ORM\Column(name="companyId", type="integer", unique=true)
* #ORM\ManyToOne(targetEntity="company", inversedBy="persons")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=true)
*
*/
protected $companyID;
/**
* #var string
*
* #ORM\Column(name="personMail", type="string", length=150, unique=true)
* #Assert\NotBlank(message="ERROR_MAIL_EMPTY")
*
* #Serializer\Expose
*/
private $personMail;

Related

How to create many-to-many self-referencing association with extra fields by using Doctrine 2?

The idea is as follows: there are products simple and compound. Compound products may consist of few simple products, for example:
There is product "Cocktail" - a simple product, with its own characteristics (name, description, price etc.), and there is a compound product - the "Fountain of cocktails," which includes the product "Cocktail" as a main component. One "Fountain of cocktails" consists of 50 "Cocktail".
Right now I have the Product entity which has many-to-many relationship with self-referencing:
<?php
namespace CT\AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Product
*
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product
{
/**
* #ORM\id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
* #var int
*/
protected $id;
/**
* #ORM\Column(type="string")
*
* #var string
*/
protected $name;
/**
* #ORM\Column(
* name="description",
* type="text"
* )
*
* #var string
*/
protected $desc;
/**
* #ORM\Column(type="float")
*
* #var float
*/
protected $price;
/**
* #ORM\Column(
* name="count_type",
* type="string"
* )
*
* #var string
*/
protected $countType;
/**
* #ORM\Column(
* name="default_count",
* type="integer",
* options={"unsigned": true}
* )
*
* #var int
*/
protected $defCount;
/**
* #ORM\Column(type="boolean")
*
* #var bool
*/
protected $isCountable;
/**
* #ORM\Column(type="boolean")
*
* #var bool
*/
protected $isCompound;
/**
* #ORM\ManyToMany(
* targetEntity="Product",
* mappedBy="components"
* )
*
* #var ArrayCollection
*/
private $products;
/**
* #ORM\ManyToMany(
* targetEntity="Product",
* inversedBy="products"
* )
* #ORM\JoinTable(
* name="compound_products",
* joinColumns={
* #ORM\JoinColumn(
* name="main_product_id",
* referencedColumnName="id"
* )
* },
* inverseJoinColumns={
* #ORM\JoinColumn(
* name="component_product_id",
* referencedColumnName="id"
* )
* }
* )
*
* #var ArrayCollection
*/
private $components;
/**
* Product constructor.
*/
public function __construct()
{
$this->products = new ArrayCollection();
$this->components = new ArrayCollection();
}
// Getters & setters...
}
I want to add extra field amount to compound_products table for setting the amount of simple products in one compound product, to get an output: http://prntscr.com/cgdvc3
I found one solution, but I don't quite understand how to apply it to my problem: Doctrine many to many self referencing with extra columns
Could you explain me how could I add this extra field for my task with saving the relationship many-to-many with self-referencing? Or if you has better solution could you share it?
You need to create a separate entity to link your Entities. Something like ProductCompound.
And then link it twice to your Product entity, for each relation.
/**
* Class ProductCompound
*
* #ORM\Entity
* #ORM\Table(name="compound_products")
*/
class ProductCompound
{
/**
* #ORM\id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
* #var int
*/
protected $id;
/**
* #ORM\ManyToOne(
* targetEntity="Product",
* inversedBy="products"
* )
* #ORM\JoinColumn(name="main_product_id", referencedColumnName="id"
*
* #var ArrayCollection
*/
protected $mainProduct;
/**
* #ORM\ManyToOne(
* targetEntity="Product",
* inversedBy="components"
* )
* #ORM\JoinColumn(name="component_product_id", referencedColumnName="id"
*
* #var ArrayCollection
*/
protected $componentProduct;
/**
* #var double
*
* #ORM\Column(name="amount", type="float", nullable=true)
*/
protected $amount;
And modify Product:
/**
* Class Product
*
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product
{
...
/**
* #ORM\OneToMany(
* targetEntity="ProductCompound",
* mappedBy="mainProduct"
* )
*
* #var ArrayCollection
*/
private $productLinks;
/**
* #ORM\OneToMany(
* targetEntity="ProductCompound",
* mappedBy="componentProduct"
* )
*
* #var ArrayCollection
*/
private $componentLinks;

Error: Cannot select entity through identification variables without choosing at least one root entity alias

I'm using this query builder in my repository:
public function findByCityCategory($city, $category)
{
$qb = $this->createQueryBuilder('e')
->select(['e.id','e.title','e.address', 'e.lat', 'e.lng', 'e.siteUrl', 'e.phoneNo', 'w', 'd.id as category', 'avg(r.rating) as rating'])
->innerJoin('e.workingTimes', 'w')
->innerJoin('e.category', 'd')
->where('d.id = :categoryId')
->andWhere('e.city = :cityId')
->leftJoin('e.ratings', 'r')
->groupBy('r.place')
->setParameter('categoryId', $category)
->setParameter('cityId', $city);
return $qb->getQuery()->getResult();
}
But when I try to execute it, I get:
"message": "[Semantical Error] line 0, col -1 near 'SELECT e.id,': Error: Cannot select entity through identification variables without choosing at least one root entity alias.",
"class": "Doctrine\\ORM\\Query\\QueryException",
I looked for similar problems here and here but none of these worked for me. My Entities looks like that:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Place
*
* #ORM\Table(name="place")
* #ORM\Entity(repositoryClass="AppBundle\Repository\PlaceRepository")
*/
class Place
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #Assert\NotBlank()
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #var string
* #Assert\NotBlank()
* #ORM\Column(name="address", type="string", length=255)
*/
private $address;
/**
* #var float
* #Assert\NotBlank()
* #ORM\Column(name="lat", type="float")
*/
private $lat;
/**
* #var float
* #Assert\NotBlank()
* #ORM\Column(name="lng", type="float")
*/
private $lng;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="fb_page", type="string", length=255, nullable=true)
*/
private $fbPage;
/**
* #Assert\NotBlank()
* #ORM\ManyToOne(targetEntity="City")
* #ORM\JoinColumn(name="city_id", referencedColumnName="id")
*/
private $city;
/**
* #Assert\NotBlank()
* #ORM\ManyToOne(targetEntity="Category", inversedBy="places")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #var string
*
* #ORM\Column(name="site_url", type="string", length=255, nullable=true)
*/
private $siteUrl;
/**
* #ORM\ManyToMany(targetEntity="WorkingTime", cascade={"persist"})
* #ORM\JoinTable(name="places_workingtimes",
* joinColumns={#ORM\JoinColumn(name="place_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="workingtime_id", referencedColumnName="id", unique=true)}
* )
*/
private $workingTimes;
/**
* #var string
* #ORM\Column(name="phone_no", type="string", length=255, nullable=true)
*
*/
private $phoneNo;
/**
* #ORM\OneToMany(targetEntity="Rating", mappedBy="place")
*/
private $ratings;
}
`
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Rating
*
* #ORM\Table(name="rating")
* #ORM\Entity(repositoryClass="AppBundle\Repository\RatingRepository")
*/
class Rating
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="rating", type="smallint")
*/
private $rating;
/**
* #ORM\ManyToOne(targetEntity="Place", inversedBy="ratings")
* #ORM\JoinColumn(name="place_id", referencedColumnName="id")
*/
private $place;
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
This error only occurs, when I try to select 'w'. So, how can I join this collection of objects?
If you want to only get partial fields from your entity, you have to use the PARTIAL keyword as explained on documentation: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/partial-objects.html
It would be better to load all the fields instead of some if you use the ORM query builder, because the ORM is made to work with objects. If you need only few fields, it can be a better practice to use the native SQL query builder.
I've managed to do it by excluding unnecessary fields from Place entity using JMS Serializer's Exclude() annotation instead of selecting required fields from entity.

Can't Create association on Symfony2

I'm trying to create a "OneToMany" bidirectional association in my project but when I execute "doctrine:schema:update" nothing happens.
If I create this association directly from Sequel Pro and run the update schema command, that changes dissapear... :/
The relations is:
- One "id" from Customers Table with many "customer_id" form Control table.
Here is the Customers code:
<?php
namespace Ourentec\CustomersBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Customers
*
* #ORM\Table()
* #ORM\Entity
*/
class Customers
{
/* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="lastname", type="string", length=100)
*/
private $lastname;
/**
* #var string
*
* #ORM\Column(name="address", type="text")
*/
private $address;
/**
* #var string
*
* #ORM\Column(name="phone", type="string", length=100)
*/
private $phone;
/**
* #var string
*
* #ORM\Column(name="pass", type="string", length=100)
*/
private $pass;
/**
* #var string
*
* #ORM\Column(name="tasks", type="text")
*/
private $tasks;
/**
* #var string
*
* #ORM\Column(name="status", type="string", length=100)
*/
private $status;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=100)
*/
private $email;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="location", type="string", length=100)
*/
private $location;
/**
* #ORM\OneToMany(targetEntity="Control", mappedBy="customers")
*/
private $customer_id;
public function __construct()
{
$this->customer_id = new ArrayCollection();
}
And the Control code:
<?php
namespace Ourentec\CustomersBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Control
*
* #ORM\Table()
* #ORM\Entity
*/
class Control
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="customer_id", type="integer")
*
* #ORM\ManyToOne(targetEntity="Customers", inversedBy="control")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customerId;
/**
* #var integer
*
* #ORM\Column(name="user_id", type="integer")
*/
private $userId;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var integer
*
* #ORM\Column(name="seen", type="smallint")
*/
private $seen;
I followed the documentation from this 2 websites
http://symfony.com/doc/current/book/doctrine.html
http://librosweb.es/libro/symfony_2_x/capitulo_8/relaciones_y_asociaciones_de_entidades.html
But I don't know why it does not work..
Any idea will be appreciated :)
Mapping are not correct, I will try to explain how it works.
In Customers entity (you should rename it to Customer, entites names are singular)
/**
* #ORM\OneToMany(targetEntity="Control", mappedBy="customer")
*/
private $controls;
Mapped by option defines field name in the other entity.
/**
* #var integer
*
* #ORM\Column(name="customer_id", type="integer")
*
* #ORM\ManyToOne(targetEntity="Customers", inversedBy="controls")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
Same thing with inversedBy.
In Customers entity you also need to init controls var as an ArrayCollection:
public function __construct()
{
$this->controls = new ArrayCollection();
}
With these mappings schema should be updated correctly.
For more info, check doctrine docs.

Doctrine2 many to one eager load in Zend2

I have two entities:
namespace Api\Payment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* PaySystemField
*
* #ORM\Table(name="paysystem_field")
* #ORM\Entity
*/
class PaySystemField
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50, nullable=false)
*/
private $name;
...
}
and
namespace Api\Payment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* PaySystemFieldValue
*
* #ORM\Table(name="paysystem_field_value")
* #ORM\Entity
*/
class PaySystemFieldValue
{
...
/**
* #var \Api\Payment\Entity\PaySystemField
*
* #ORM\ManyToOne(targetEntity="\Api\Payment\Entity\PaySystemField", fetch="EAGER")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="paySystemFieldId", referencedColumnName="id")
* })
*/
private $paySystemField;
...
}
My DQL request:
$fieldsValues = $this->objectManager
->createQuery('
SELECT psfv,psf FROM Api\Payment\Entity\PaySystemFieldValue psfv
JOIN Api\Payment\Entity\PaySystemField psf WITH (psfv.paySystemField=psf.id)
WHERE psfv.payment=:payment
')
->setParameter('payment', $this->payment)
->setFetchMode('Api\Payment\Entity\PaySystemFieldValue', 'paySystemField', 'EAGER')
->getResult();
This query returns PaySystemFieldValue with paySystemField relation already initialised, but $fieldsValues contain both PaySystemFieldValue entities and PaySystemField. How can i do the way $fieldsValues will contain only PaySystemFieldValue entities with paySystemField relation initialised?
try with this query:
$fieldsValues = $this->objectManager->createQuery('SELECT psfv FROM Api\Payment\Entity\PaySystemFieldValue psfv WHERE psfv.payment=:payment')->setParameter('payment', $this->payment)->getResult();
or
$this->getServiceLocator()->get('doctrine.entitymanager.orm_default')->getRepository("Api\Payment\Entity\PaySystemFieldValue")->findBy(array('payment' => $this->payment));

Doctrine creating useless join table

so, i have two entities: Genre and Game
Genre.php
<?php
namespace Acme\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Genre
*
* #ORM\Table(name="genre")
* #ORM\Entity
*/
class Genre
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=64, nullable=false)
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="display", type="string", length=64, nullable=false)
*/
protected $display;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=false)
*/
protected $description;
/**
* #var ArrayCollection|Game[]
*
* #ORM\ManyToMany(targetEntity="Game", inversedBy="genres", cascade={"persist"})
*/
protected $games;
// ... Irrelevant Constructor and following getters/setters
}
Game.php
<?php
namespace Acme\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Game
*
* #ORM\Table(name="game")
* #ORM\Entity
*/
class Game
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=256, nullable=false)
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="display", type="string", length=256, nullable=false)
*/
protected $display;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=false)
*/
protected $description;
/**
* #var ArrayCollection|Genre[]
*
* #ORM\ManyToMany(targetEntity="Genre", inversedBy="games", cascade={"persist"})
* #ORM\JoinTable(name="genre_game",
* joinColumns={#ORM\JoinColumn(name="genre_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="game_id", referencedColumnName="id")}
* )
*/
protected $genres;
/**
* #var ArrayCollection|Platform[]
*
* #ORM\ManyToMany(targetEntity="Platform", inversedBy="games", cascade={"persist"})
* #ORM\JoinTable(name="platform_game",
* joinColumns={#ORM\JoinColumn(name="platform_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="game_id", referencedColumnName="id")}
* )
*/
protected $platforms;
/**
* #var Image[]
*
* #ORM\OneToMany(targetEntity="Image",mappedBy="game_id", cascade={"persist"})
*/
protected $images;
}
When i run php app/console doctrine:schema:create or update, it creates all of the needed join tables I specified above, but it also creates genre_genre
This table is always empty, and doesnt seem to do anything, and prevents me from running php app/console doctrine:schema:update's later, and its trying to add an index to it that already exists
Anyone see what I'm doing wrong?
Game->genres and Genre-game are inversed by each other, which is invalid - one needs to be owning. I believe there is a doctine:schema:validate command you would find useful.
Sir, I think you have made many to many relation(bidirectional) in those mapping classes. According to doctrine documentation that will create that table for relation of those Game and Genre like in the example.
You can create the db table then create the mapper class to verify with generate-entities. This way you can verify the schema and the mapping.

Categories