I stuck with getting ManyToMany relation. I have two entities Offer and OfferType.
I defined ManyToMany relation only on OfferEntity and it looks like saving offers with multiple OfferType works fine in database I see correct joining table.
OfferEntity.php
/**
* Offer Entity
*
* #ORM\Table(name="offer")
* #ORM\Entity(repositoryClass="ProjectBundle\Repository\OfferRepository")
*/
class Offer
{
/**
* #Assert\Count(
* min = "1",
* minMessage = "You must specify at least one offer type."
* )
* #ORM\ManyToMany(targetEntity="OfferType")
*/
private $types;
public function __construct()
{
$this->types = new ArrayCollection();
}
/**
* #return ArrayCollection
*/
public function getTypes()
{
return $this->types;
}
(...)
Right now, I would like to get all types assigned to the offer. I tried it like this:
// $offer is an Entity
$query = $em->createQueryBuilder()
->select('offer.types')
->from('ProjectBundle:Offer', 'offer')
->where('offer = :offer')
->setParameters([
'offer' => $offer
]);
Unfortunately I getting error:
[2/2] QueryException: [Semantical Error] line 0, col 13 near 'types FROM ProjectBundle:Offer': Error: Invalid PathExpression. Must be a **StateFieldPathExpression**.
[1/2] QueryException: SELECT offer.types FROM ProjectBundle:Offer offer WHERE offer = :offer
Based on StackOverflow answers for similar questions tried it also to use IDENTITY():
// $offer is an Entity
$query = $em->createQueryBuilder()
->select('IDENTITY(offer.types)')
->from('ProjectBundle:Offer', 'offer')
->where('offer = :offer')
->setParameters([
'offer' => $offer
]);
But then I have:
[2/2] QueryException: [Semantical Error] line 0, col 22 near 'types) FROM ProjectBundle:Offer': Error: Invalid PathExpression. Must be a SingleValuedAssociationField.
[1/2] QueryException: SELECT IDENTITY(offer.types) FROM ProjectBundle:Offer offer WHERE offer = :offer
I would really appreciate any hints about getting ManyToMany relation, maybe my approach for this is incorrect?
Your approach is not quite right. You need to join the entity you want to load. You should spend a bit more time reading the doctrine documentation on entity relations & querybuilder.
Like so.
$query = $em->createQueryBuilder()
->select('offer', 'types')
->from('ProjectBundle:Offer', 'offer')
->join('offer.types', 'types')
->where('offer = :offer')
->setParameters([
'offer' => $offer
]);
Then your result will contain what you want.
Note: you don't even have to join types to get types from an offer, you could also use
$offer->getTypes()
And types will lazy load in standard doctrine manner.
But querying it as above will load types in advance - so you avoid lazy loading. This may or may not be a better approach depending on requirements.
If you have your many to many mappings set up only on one side, you'll only be able to query for the Offer and then retrieve the types from it:
$builder = $em->createQueryBuilder()
->select('o', 't')
->from('ProjectBundle:Offer', 'o')
->join('o.types', 't')
->where('o.id = :offer')
->setParameter('offer', $offerId);
$offer = $builder->getQuery()->getOneOrNullResult();
$types = $offer->getTypes();
That was assuming you only had $offerId to work with. If you already have the whole Offer instance, you might just as well just call getTypes() on it and doctrine will take care of the rest.
If you were to define the inverse mappings on the OfferType entity like so:
class OfferType
{
/**
* #ORM\ManyToMany(targetEntity="Offer", mappedBy="types")
*/
private $offers;
}
You could make queries for just the types:
$builder = $em->createQueryBuilder()
->select('t')
->from('ProjectBundle:OfferType', 't')
->join('t.offers', 'o')
->where('o = :offer')
->setParameter('offer', $offer);
$types = $builder->getQuery()->getResult();
Related
I have 2 entities, MyItem and MyItemCategory. When I try to create a query with query builder I get the following error:
Error: Class App\Entity\MyItem has no
field or association named myitem_category_id (500 Internal Server Error)
This is the where part of my query builder:
$queryBuilder = $this->getDoctrine()
->getRepository('App\Entity\MyItem')
->createQueryBuilder('m');
// adds where for category_id:
$queryBuilder->where('m.myitem_category_id = :category_id')->setParameter('category_id',$category_id);
Here're first entities:
/**
* #ManyToOne(targetEntity="MyItemCategory")
* #JoinColumn(name="myitem_category_id", referencedColumnName="id")
*/
private $myItemCategory;
...and my category entity:
/**
* #ORM\OneToMany(targetEntity="MyItem", mappedBy="myItemCategory")
*/
private $myItemCategories;
The querybuilder actually doesn't care about database fields, but instead uses the object mapper, so there is no field my_item_category_id on your Entity, but instead a field myItemCategory
So, you can either do:
$querybuilder
->where('m.myItemCategory = :category')
->setParameter('category', $category) // <-- an actual MyItemCategory object
or you can join it in and check for the id:
$querybuilder
->leftJoin('m.myItemCategory', 'mic')
->where('mic.id = :micid')
->setParameter('micid', $category_id)
(I actually don't know if m.myItemCategory.id = :micid might work ........ you could try ;o))
I want to use the following mysql query: select * from x join y on x.y_id = y.id where x.a= 0
I tried to put it in my Symfony project with the following doctrine syntax.
$repositoryX->createQueryBuilder('x')
->add('select', 'x')
->add('from', 'AppBundle:X x')
->leftJoin('AppBundle:Y', 'y', 'WITH', 'x.y_id = y.id')
->where('x.a = :a')
->setParameter('a', 0)
->getQuery()
->getResult();
My problem is that I only see the results of table x, but I also want the results of table y (because of the join on). When I put an extra select, I get Neither the property "y_id" nor one of the methods "y_id()", "gety_id()"/"isy_id()" or "__call()" exist and have public access in class
The '*' doesn't workin within doctrine .
You are only selecting x change:
->add('select', 'x')
to
->add('select', 'x,y')
//The second param might accept and array i dont remember off hand
->add('select', ['x','y'])
Or written better:
$repository->createQueryBuilder()
->select(['x','y'])
->from('AppBundle:X','x')
->join('x.y','y') // This assumes you have the mapping defined for this property
->where('x.a = :a')
->setParameter('a', 0)
->getQuery()
->getResult();
If you are using annotation mapping it should look something like
//X entity
//...
class X {
//...
/**
* #ORM\OneToOne(targetEntity="Y")
* #ORM\JoinColumn(name="y_id", referencedColumnName="id")
*/
protected $y;
}
Good morning, as seen in the image below, I have some tables linked.
Using Doctrine (in Symfony2) I'm trying to get an array of Objects Issue which itself contains all IssueMessages and IssueStatusChanged objects but can not.
I have no idea how I can do to join two tables (IssueMessage and IssueStatusChanged) to through their identifiers.
The most we've done is get all Issue with an account of the messages that have:
$dql = 'SELECT x, COUNT(im.id) FROM PanelBundle:Issue x LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue';
Does anyone could give me a hand?
THANKS!
You want to use assication mapping; this will have Doctrine manage all the joins for you.
Once in place, $issue will always have the other associated models available automatically without you having to worry about joins.
For the example below (assuming you use annotation), to get messages for an issue just get the issue objects and then use $issue->getMessages();.
<?php
/** #Entity */
class issue
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
// ...
/**
* #OneToMany(targetEntity="issueMessages", mappedBy="issue")
*/
private $messages;
// ...
public function __construct()
{
$this->messages = new Doctrine\Common\Collections\ArrayCollection();
}
}
/** #Entity */
class issueMessages
{
// ...
/**
* #ManyToOne(targetEntity="issue", inversedBy="messages")
* #JoinColumn(name="issue_id", referencedColumnName="id")
*/
private $issue;
// ...
}
If you using yml format for schema orm files than
first you need to write schema and mention oneToMany, manyToOne relationship with table fields & generate entity, repository class.
Than you can use join with two or more tables as below example:
Example of repository class file function:
----------------------------------------------------
public function getReportInfo($idUserDetail)
{
$query = $this->createQueryBuilder('UR')
->select("UR.report_period_start_date, UR.report_period_end_date")
->leftJoin('UR.UserReportDetail', 'URD')
->andWhere('UR.id_user_detail = :id')
->setParameter('id', $id)
->orderBy('UR.report_year', 'DESC')
->addOrderBy('UR.report_month', 'DESC')
->setMaxResults(1);
$resultArray = $query->getQuery()->getArrayResult();
return $resultArray;
}
You can call this function from controller action as below:
-------------------------------------------------------------
public function getUserDetailAction($idUserDetail)
{
$em = $this->getDoctrine()->getManager();
$userDetail = $em->getRepository(
'DemoBundle:UserDetail')
->getReportInfo($idUserDetail);
return $userDetail;
}
I hope this would be useful to you.
I think the problem reside in the DQL syntax (+ missing inverse relation?).
By writing this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue
you are joining two "random" table based on the condition provided in the WITH clause. This should usually be ok, but it may confuse the Hydrator component.
In your case you should configure the OneToMany side of the relation in Issue entity, then write something like this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN x.issueMessages im
Hope it helps!
I have the following query:
$query = $em->createQueryBuilder()->select('p.id, p.name, p.price, p.cover')
->from("SiteMainBundle:Product", 'p')
->innerJoin('p.category', 'c')
->innerJoin('p.shop', 'shop')
;
And inside my product entity the cover is actually another entity, which looks like this:
/**
* #Accessor(getter="getCover")
*/
private $cover;
public function getCover()
{
if($this->pictures->count() > 0) {
return $this->pictures[0];
}
return new ProductPicture();
}
However when I do this it gives me an error:
"[Semantical Error] line 0, col 32 near 'cover FROM SiteMainBundle:Product': Error: Class Site\\MainBundle\\Entity\\Product has no field or association named cover"
I know this is because it is declared as private, but can I call the method getCover from the query builder?
If you want to load only specific fields, instead of the whole entity, you need to use the partial object syntax:
$em->createQueryBuilder()->select('p.{id,name,price,cover}')
This will select only the 4 specific columns you want.
It's not because of private visibility, but because cover is not defined as an entity field.
/**
* #ORM\Column(type="string")
*
* #Accessor(getter="getCover")
*/
private $cover;
I have 2 entities: author and person.
In the author entity, there is a person field which is in fact the person object:
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="submission_authors")
* #ORM\JoinColumn(name="person_id", referencedColumnName="id")
*/
protected $person;
Now, in the repository: AuthorRepository, I would like to search for some authors by their firstname. To do this, I need to access the person object for the corresponding author ans look on the person's firstname.
I tryed:
public function searchAuthors($q)
{
$authQB = $this->createQueryBuilder( 'a' )
->select('a')
->where("a.person.firstname LIKE '%".$q."%'");
return $authQB->getQuery()->getResult();
}
But the problem is that I am geting an error:
[Syntax Error] line 0, col 78: Error: Expected Doctrine\ORM\Query\Lexer::T_LIKE, got '.'
Coud you please help me on how to resolve that?
You'd have to access your person relation like this:
$authQB = $this->createQueryBuilder( 'a' )
->select('a')
->leftJoin('a.person', 'p')
//...
To learn a bit more about query builder and joint tables:
This SO post.
Try
$authQB = $this->createQueryBuilder( 'a' )
->select('a')
->innerJoin('a.person', 'p')
->where('p.firstname LIKE :myStuff')
->setParameter('myStuff', '%'.$q.'%');