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));
Related
I need to get array of orders, with first and last OrderItem in it.
Table order_item:
id
order_id
status
1
1
0
2
1
1
3
1
0
4
1
1
5
1
0
Order entity
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
/**
* Order
*
* #ORM\Entity
* #ORM\Table(name="orders")
*/
class Order
{
/**
* #var int
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #Serializer\Groups(groups="order_list")
*/
private $id;
/**
* #var string
* #ORM\Column(name="title", type="string", nullable=false)
* #Serializer\Groups(groups={"order_list"})
*/
private $title;
/**
* #var Collection
* #ORM\OneToOne(targetEntity="OrderItem", mappedBy="orderFirst")
* #Serializer\Groups(groups={"order_list"})
*/
private $orderItemFirst;
/**
* #var Collection
* #ORM\OneToOne(targetEntity="OrderItem", mappedBy="orderLast")
* #Serializer\Groups(groups={"order_list"})
*/
private $orderItemLast;
/**
* #var Collection|OrderItem[]
* #ORM\OneToMany(targetEntity="OrderItem", mappedBy="order")
* #Serializer\Groups(groups={"order_list"})
*/
private $items;
public function __construct()
{
$this->items = new ArrayCollection();
}
// getters and setters ...
}
OrderItem entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
/**
* Order
*
* #ORM\Entity
* #ORM\Table(name="order_item")
*/
class OrderItem
{
/**
* #var int
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #Serializer\Groups(groups="order_list")
*/
private $id;
/**
* #var Order|null
* #ORM\OneToOne(targetEntity="Order", inversedBy="orderItemFirst")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="order_id", referencedColumnName="id")
* })
*/
private $orderFirst;
/**
* #var Order|null
* #ORM\OneToOne(targetEntity="Order", inversedBy="orderItemLast")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="order_id", referencedColumnName="id")
* })
*/
private $orderLast;
/**
* #var Order|null
* #ORM\ManyToOne(targetEntity="Order", inversedBy="items")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="order_id", referencedColumnName="id")
* })
*/
private $order;
/**
* #var bool
* #ORM\Column(type="boolean", nullable=false)
* #Serializer\Groups(groups="order_list")
*/
private $status;
// getters and setters...
}
Code in service
$repository = $em->getRepository(\App\Entity\Order::class);
$qb = $repository->createQueryBuilder('t');
$qb
->leftJoin('t.orderItemFirst', 'oi', \Doctrine\ORM\Query\Expr\Join::WITH, 'oi.status = :status')
->leftJoin('t.orderItemFirst', 'oi2', \Doctrine\ORM\Query\Expr\Join::WITH, 'oi2.status = :status AND oi2.id > oi.id')
->leftJoin('t.orderItemLast', 'oi3', \Doctrine\ORM\Query\Expr\Join::WITH, 'oi3.status = :status')
->leftJoin('t.orderItemLast', 'oi4', \Doctrine\ORM\Query\Expr\Join::WITH, 'oi4.status = :status AND oi4.id < oi3.id')
->setParameter('status', true)
->addSelect('oi')
->addSelect('oi3')
->where('oi2.id IS NULL')
->andWhere('oi4.id IS NULL')
->groupBy('t.id')
;
$query = $qb->getQuery();
$query->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true);
/*
* This returns
* "orderItemFirst": {"id": 4}
* "orderItemLast": {"id": 4}
*/
$result = $query->getResult();
But getArrayResult() returns correct data:
"orderItemFirst": {
"id": 2,
"status": true
},
"orderItemLast": {
"id": 4,
"status": true
}
And even if I call getArrayResult() at first, getResult() starts to hydrate correctly. What a strange behavior? Can it be done without double executing query?
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;
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.
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.
I am trying to model the following table structure in Symfony 2.0 using annotations.
State
PK Code
Name
County
PK State_Code -> FK State.Code
PK Code
Name
Muni
PK State_Code -> FK.State.Code
PK County_Code -> FK County.Code
PK Code
Name
Modeling the fields and the state - county relationship is simple enough, but I cannot determine how to define the relationship for the Muni table.
States have one or more counties.
Counties have one or more Munis.
Munis belong to one or more Counties.
The table structure is legacy and cannot be modified.
Here you go. Tested with Symfony 2.0.5 (Doctrine 2.1):
State.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* State
*
* #ORM\Entity
*/
class State
{
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="County", mappedBy="state_code")
*/
private $counties;
/**
* #ORM\OneToMany(targetEntity="Muni", mappedBy="state_code")
*/
private $munis;
}
County.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* County
*
* #ORM\Entity()
*/
class County
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="State", inversedBy="counties")
* #ORM\JoinColumn(name="State_Code", referencedColumnName="Code")
*/
private $state_code;
/**
* #ORM\OneToMany(targetEntity="Muni", mappedBy="county_code")
*/
private $munis;
}
Muni.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Muni
*
* #ORM\Entity
*/
class Muni
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="County", inversedBy="munis")
* #ORM\JoinColumn(name="County_Code", referencedColumnName="Code")
*/
private $county_code;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="State", inversedBy="munis")
* #ORM\JoinColumn(name="State_Code", referencedColumnName="Code")
*/
private $state_code;
}
Don't forget to generate getters/setters. All relationships are bi-directional.