Doctrine 2 JOIN ON error - join

I try to execute this query in my CompanyRepository
$qb = $this->_em->createQueryBuilder();
$qb->select(array('c', 'ld'))
->from('Model\Entity\Company', 'c')
->leftJoin('c.legaldetails', 'ld', \Doctrine\ORM\Query\Expr\Join::ON, 'c.companyid=ld.companyid');
$query = $qb->getQuery();
echo($query->getSQL());
When I try to do it I having error:
Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message '[Syntax Error] line 0, col 69: Error: Expected end of string, got 'ON'' in /home/raccoon/web/freetopay.dev/www/class/new/library/Doctrine/ORM/Query/QueryException.php on line 42
These are my models:
<?php
namespace Model\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Company
*
* #ORM\Table(name="Company")
* #ORM\Entity(repositoryClass="\Model\Repository\CompanyRepository")
*/
class Company
{
/**
* #var integer $companyid
*
* #ORM\Column(name="CompanyID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $companyid;
/**
* #var \Model\Entity\LegalDetails $legaldetails
*
* #ORM\OneToOne(targetEntity="\Model\Entity\Legaldetails", mappedBy="companyid")
*/
private $legaldetails;
//other fields
public function __construct()
{
$this->legaldetails = new ArrayCollection();
}
//setters and getters
and legaldetails entity:
<?php
namespace Model\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Legaldetails
*
* #ORM\Table(name="LegalDetails")
* #ORM\Entity
*/
class Legaldetails
{
/**
* #var integer $legalid
*
* #ORM\Column(name="LegalID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $legalid;
/**
* #var \Model\Entity\Company $company
*
* #ORM\Column(name="CompanyID", type="integer", nullable=false)
* #ORM\OneToOne(targetEntity="\Model\Entity\Company", inversedBy="companyid")
* #ORM\JoinColumn(name="companyid", referencedColumnName="companyid")
*/
private $company;
What is wrong?

For those who came here with the question about "Expected end of string, got 'ON'", but could not find the right answer, as I couldn't (well, there is an answer, but not exactly about QueryBuilder). In general, yes, you don't need to specify the joining columns. But what if you need to add extra filtering. For example, I was looking to add an extra condition (to allow nulls in join).
The problem here is that even though the constant Join::ON exists (and comments in Join expression mention it as well), there is no ON in DQL. Instead, one should use WITH (Join::WITH).
Here is my usage example:
$qb->leftJoin('p.metadata', 'm', Join::WITH, "IFNULL(m.name, '') = 'email'");
P.S. Predicting questions about IFNULL() - it is a Benjamin Eberlei's Doctrine extension.

There's a pretty clear explanation about how JOIN's work with DQL here:
With DQL when you write a join, it can be a filtering join (similar to the concept of join in SQL used for limiting or aggregating results) or a fetch join (used to fetch related records and include them in the result of the main query). When you include fields from the joined entity in the SELECT clause you get a fetch join
this should be enough to get what you want (info about all companies with legal info loaded):
$query = $em->createQuery('SELECT c, ld FROM \Model\Entity\Company c JOIN c.legaldetails ld');
$companies = $query->getResult(); // array of Company objects with the legaldetails association loaded
EDIT:
i used a regular join in my query, so companies with no legal info won't be returned in the query. if you want ALL companies even though they have no legal info loaded you should try with the left join as you were doing

We both thought in terms of SQL. But in DQL WITH is used instead of ON. example
Edit:
If you know SQL, why you don't use query such as:
$query = $this->getEntityManager()->createQuery('
SELECT t...
');
Put there the SQL that you think should be there, check it. If it works - the problem is in Doctrine code, if not - the error is in SQL/DQL

Related

Order CollectionType in FormType with many-to-many relation

I have a relation many-to-many.
In Entity "Progetti" i have:
/**
*
* #var \Doctrine\Common\Collections\ArrayCollection $attivita
*
* #ORM\ManyToMany(targetEntity="Attivita", inversedBy="progetti",cascade={"persist", "remove" })
* #ORM\JoinTable(name="progetti_attivita",
* joinColumns={#ORM\JoinColumn(name="progetti_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="attivita_id", referencedColumnName="id")}
* )
*/
protected $attivita;
In Entity "Attività" i have:
/**
*
* #var \Doctrine\Common\Collections\ArrayCollection $progetti
* #ORM\ManyToMany(targetEntity="Progetti", mappedBy="attivita")
*/
protected $progetti;
Ok.
The JoinTable "progetti_attivita" has "attivita_id" and "progetti_id".
Now i added a new field to the JoinTable "progetti_attivita" and i called it "position". it's an integer.
I have the ProgettiType Form:
$builder
->add('nomeProgetto')
->add('descProgetto')
->add('noteProgetto')
->add('attivita', CollectionType::class, array(
'entry_type' => AttivitaType::class,
'allow_add' => true,
));
Ok.
I have the form that display all "attività" for "progetti".
My question is:
How can i say to Form to display "attivita" ordered by "position" ?
If you always want your collection to be ordered then you can add the OrderBy property to your Doctrine mapping:
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/ordered-associations.html
/**
* #ManyToMany(targetEntity="Attivita")
* #OrderBy({"position" = "ASC"})
**/
private $attivitas;
An alternative approach would be to add a getAttivitaOrdered method to your Progetti entity:
class Progetti
getAttivitaOrdered() // return ordered list
->add('attivitaOrdered', CollectionType::class ...
Not sure if you will need a setAttivitaOrdered method or not when you post.
And your question is actually a little bit confusing. Adding a property to your join table means that you need to use OneToMany and ManyToOne relations instead of ManyToMany. So a few more adjustments will be needed.

Doctrine manyToMany join, not working

My selection not working, why??? I see others posts, but don't solve this problem.
symfony2 doctrine join
Doctrine Join DQL
If i use join like this:
->join('User', 'u')
The result, is 4 values, where i expected 2...
Models:
class User
{
...
/**
* #ManyToMany(targetEntity="UserGroup", mappedBy="users", cascade={"all"})
* #JoinTable(name="users_user_group")
*/
protected $userGroups;
and
class UserGroup
{
...
/**
* #ManyToMany(targetEntity="User", inversedBy="userGroups", cascade={"all"})
* #JoinTable(name="users_user_group")
**/
public $users;
QueryBuilder:
$queryBuilder = $this->getController()->getRepository()
->createQueryBuilder('ug')
->select('ug, u')
->leftJoin('User', 'u', 'WITH', 'ug.id = u.userGroups')
->andWhere('u.id IN (:ids)')
->setParameter('ids', $usersId);
I receive this message:
[Semantical Error] line 0, col 63 near 'userGroups WHERE': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.
This SQL work, why DQL not?
SELECT
*
FROM
users_user_group ug
LEFT JOIN
user u ON ug.user_id = u.id
WHERE
ug.user_id IN (1 , 2)
I changed this line:
->leftJoin('User', 'u', 'WITH', 'ug.id = u.userGroups')
for it:
->join('User', 'u', 'WITH', 'ug.id = u.id')
\o/

Doctrine/Symfony2 get data from tables in relationship

I have an table Article that is in relationship with Steps (OneToMany) and Steps with Article ManyToOne.
I get Articles with:
$articles = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Article")
->findAll();
And with foreach I want to show all Articles and Steps:
foreach($articles as $article)
{
$steps = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Steps")
->createQueryBuilder('s')
->where('s.article = \''.$article.'\'')
->getQuery()
->execute();
echo "<b>".$article->getTitle()."</b><br />";
echo $article->getText()."<br />";
}
I don't know how to get data from table Steps usign the table Article and method getSteps() that is generated with Doctrine.
Please help me.
Thanks for the answer.
In table Article I have:
/**
* #ORM\OneToMany(targetEntity="Steps", mappedBy="Steps",cascade={"persist"})
* #ORM\JoinColumn(name="id", referencedColumnName="id_article")
*/
protected $steps;
In table Steps:
/**
* #ORM\ManyToOne(targetEntity="Article", inversedBy="steps")
*
*/
protected $article;
When I do:
$articles = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Article")
->findAll();
If I do:
foreach($articles as $article)
{
$steps = $article->getSteps();
I recieve error:
Notice: Undefined index: Steps in /var/www/design/vendor/doctrine/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1280
If I do that:
$articles = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Article")
->findAll();
foreach($articles as $article)
{
//Queries to DB
$steps = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Steps")
->findBy(array(
"article" => $article->getId()
));
$media = $this->getDoctrine()
->getRepository("IftodiDesignBundle:Media")
->findBy(array(
"step" => $steps[0]->getId()
));
I can obtain data that I need, but here are more interrogation to DB.
Delete #ORM\JoinColumn(name="id", referencedColumnName="id_article") from your annotation - doctrine will map your association into MySQL with sensible defaults.
Once you have deleted, regenerate your SQL: doctrine:schema:update --force
Furthermore if you are looping over your articles to get your steps, you are better off writing a custom method in your repository otherwise each time you call ->getSteps() Doctrine will make an SQL call (imagine looping over 100 articles - you would end up making 101 calls to the database!)
To avoid this you can put a method like so in your repository
public function all()
{
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$queryBuilder
->select('Article', 'Steps')
->from('IftodiDesignBundle:Article')
->leftJoin('Article.steps', 'Steps')
;
// consider using ->getArrayResult() to use less memory
return $queryBuilder->getQuery()->getResult();
}
I put together a few more best practices in a blog post
Well,
Assuming that you have the following relation in Article model:
/**
* #OneToMany(targetEntity="Step", mappedBy="article")
* #JoinColumn(name="id_article", referencedColumnName="id_article_in_step")
*/
protected $steps;
public function getSteps(){ return $this->steps; }
you will be able to do $article->getSteps();

magento join table collection

I'm customizing Magento FAQ extension for sort faq items by category.below collection is
used to get all items active faq items.
$collection = Mage :: getModel('flagbit_faq/faq')->getCollection()
->addStoreFilter(Mage :: app()->getStore())
->addIsActiveFilter();
there is relation table "faq_category_item"
Table structure:-
category_id faq_id
1 1
2 2
1 3
So I decide to join two tables.I unsuccess in that.
What i tried is below.
$tbl_faq_item = Mage::getSingleton('core/resource')->getTableName('faq_category_item');
$collection = Mage :: getModel('flagbit_faq/faq')->getCollection()
->getSelect()
->join(array('t2' => $tbl_faq_item),'main_table.faq_id = t2.faq_id','t2.category_id')
->addStoreFilter(Mage :: app()->getStore())
->addIsActiveFilter();
Whats wrong in this and how can i filter the particular category items.Please share some good links to learn Magento model collections.
Thanks in advance
The returned type from getSelect() and join() is a select object, not the collection that addStoreFilter() and addIsActiveFilter() belong to. The select part needs to occur later in the chain:
$collection = Mage :: getModel('flagbit_faq/faq')->getCollection()
->addStoreFilter(Mage :: app()->getStore())
->addIsActiveFilter();
// Cannot append getSelect right here because $collection will not be a collection
$collection->getSelect()
->join(array('t2' => $tbl_faq_item),'main_table.faq_id = t2.faq_id','t2.category_id');
Try this function from
Mage_Eav_Model_Entity_Collection_Abstract
/**
* Join a table
*
* #param string|array $table
* #param string $bind
* #param string|array $fields
* #param null|array $cond
* #param string $joinType
* #return Mage_Eav_Model_Entity_Collection_Abstract
*/
public function joinTable($table, $bind, $fields = null, $cond = null, $joinType = 'inner')
{
So to join tables you can do like this:
$collection->joinTable('table-to-join','left.id=right.id',array('alias'=>'field'),'some condition or null', joinType(left right inner));

doctrine 2 join associations not found

I am using Doctrine-2.0.4 with Zend 1.11. Php Mappers and Entities are generated from a MySQL DB. Now I am trying a query that joins two tables and only ever get
[Semantical Error] line 0, col 48 near 'e': Error: Class Entities\Users has no association named Accounts
Query:
$query = $em->createQueryBuilder()
->select('u')
->from('\Entities\Users', 'u')
->leftJoin('u.Accounts', 'a')
->getQuery();
$info = $query->getResult();
In my DB there are two tables: Users, Accounts
Users has fields id, accountId
Accounts has fields id, info
Users.accountId has a bidirectional one-to-one association to Accounts.id
<?php
namespace Entities;
/**
* Users
*
* #Table(name="users")
* #Entity
*/
class Users
{
/**
* #var integer $id
*
* #Column(name="id", type="integer", nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer $accountid
*
* #Column(name="accountId", type="integer", nullable=false)
* #OneToOne(targetEntity="accounts", inversedBy="id")
* #JoinColumn(name="accounts_id", referencedColumnName="id")
*/
private $accountid;
...
}
<?php
namespace Entities;
/**
* Accounts
*
* #Table(name="accounts")
* #Entity
*/
class Accounts
{
/**
* #var integer $id
*
* #Column(name="id", type="integer", nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
* #OneToOne(targetEntity="users", mappedBy="accountid")
*/
private $id;
...
}
You should change the $accountId property on the User entity to $accounts because it is not an integer it's an Accounts entity:
/**
* #var Accounts $accounts
*
* #Column(name="accountId", type="integer", nullable=false)
* #OneToOne(targetEntity="Accounts", inversedBy="id")
* #JoinColumn(name="accounts_id", referencedColumnName="id")
*/
private $accounts;
Your current query doesn't work because there is no Accounts property. If you make the above changes the following should work:
$query = $em->createQueryBuilder()
->select('u')
->from('\Entities\Users', 'u')
->leftJoin('u.accounts', 'a')
->getQuery();
$info = $query->getResult();
You can't use both #Column and #JoinColumn.
You should remove the #Column Line, and it should be works!:
/**
* #var Accounts $accounts
*
* #OneToOne(targetEntity="Accounts", inversedBy="id")
* #JoinColumn(name="accounts_id", referencedColumnName="id")
*/
private $accounts;

Resources