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;
Related
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.
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/
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));
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
documento: {type: varchar, sqltype: enum, size:
"'F','DDT','RC','FOURTH_ELEMENT','PM','KV','VN','CMS'", required:
true, defaultValue: 'F', required: true}
I get the next error message (always with the fourth element, I mean
if i write 3 or less elements it doesn't give any error):
propel generating form classes
Cannot fetch TableMap for undefined
table: FOURTH_ELEMENT
[?php
/** * sfGuardUserProfile form base
class. * * #method
sfGuardUserProfile getObject() Returns
the current form's model object * *
#package ##PROJECT_NAME## *
#subpackage form * #author
AUTHOR_NAME * #version SVN: $Id: sfPropelFormGeneratedTemplate.php
24171 2009-11-19 16:37:50Z
Kris.Wallsmith $ */ abstract class
BasesfGuardUserProfileForm extends
BaseFormPropel { public function
setup() {
$this->setWidgets(array(
sf 1.4.
Javier
You should upgrade to Propel 1.6.3 in order to get the advanced columns feature (ENUM for instance): http://www.propelorm.org/cookbook/working-with-advanced-column-types.html#enum_columns.
William