I wrote this query.
$query = $this->getEntityManager()->createQueryBuilder();
$query->select(['cart','subscriptions', 'member'])
->from('ComitiUserBundle:Cart', 'cart')
->leftJoin('cart.subscriptions', 'subscriptions')
->leftJoin('subscriptions.member', 'member')
->where('cart.club = :club_id')
->andWhere('subscriptions.clubSeason = :season_id')
->setParameter('club_id', $club)
->setParameter('season_id', $season);
if($section != null && !is_array($section)){
$query->andWhere('subscriptions.section = :section_id')
->setParameter('section_id', $section);
} elseif($section != null && is_array($section)){
$query->andWhere('subscriptions.section IN :section_ids')
->setParameter('section_ids', $section);
}
$query->orderBy('cart.transaction_date','DESC');
return $query->getQuery()->getResult();
I've got this error in return :
[Syntax Error] line 0, col 28: Error: Expected IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression, got 'member'
In fact I try to hydrate my result collection with members in it. Member is manyToOne property in my Subscription entity. It is defined like this :
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\UserComiti", inversedBy="subscriptions", cascade={"persist"})
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
So I ran into the exact same error when trying to join a category group for a category entity. See the code below:
$qb = $this->entityManager->createQueryBuilder()
->select('c')
->from(Category::class, 'c');
if (isset($fields['categoryGroup'])) {
$qb = $qb->join('c.categoryGroup', 'group')
->addSelect('group');
}
$qb = $qb->getQuery()
->getArrayResult();
This resulted in the exact same error as the OP, only with 'group'. My guess is that you cannot use database reserved words in the query, like group and member.
For me, changing the alias to something like cg worked just fine.
Related
I have 2 entities :
LinkServInfra
Serv
LinkServInfra entity :
id
serv (relation OneToOne to Serv)
infra (ManyToOne to another entity)
Now, I'd like to get a list of Serv based on infra.
So I tried in LinkServInfraRepository :
$qb = $this->createQueryBuilder('s')
->select('DISTINCT s.serv')
->where('s.infra = :infra')
->setParameter('infra', $infra);
return $qb->getQuery()->getResult();
And I get an error :
[Semantical Error] near 'serv FROM': Error: InvalidPathExpression.
Must be a StateFieldPathExpression.
(I tried first without DISTINCT and tried with it based on answer found here).
The query seems to be good because it's :
SELECT DISTINCT s.serv
FROM MyBundle\Entity\LinkServInfra s
WHERE s.infra = :infra
How would you do?
Thanks!
Since the relation is ONLY in LinkServInfra and not in Serv :
I used the relation in LinkServInfra to do it...
public function filter($type, $etat, $infra){
$qb = $this->createQueryBuilder('l');
$qb->where(' l.infra = :infra ')
->setParameter('infra', $infra);
if( $type || $etat ){
$qb->join('l.serv', 's')
//where & setParameter for type
//where & setParameter for detail
}
And then where I call the function filter :
$entities = $em->getRepository('linkServInfra')->filter(//...
$servs = array();
foreach($entities as $entity){
$servs[] = $entity->getServ();
}
I guess it's not the cleanest solution but it's working...
I think you can not use DISTINCT on a relation, only for the root entity alias.
You should use Serv entity as root and join with LinkServInfra and infra entity through the 2nd. Something like:
$qb = $this->getDoctrine()
->getRepository(Serv::class)->createQueryBuilder('s')
->select('DISTINCT s')
->leftJoin("s.linkServInfra", "lsi")
->leftJoin("lsi.infra", "infra")
->where('infra.id = :infra')
->setParameter('infra', 1);
Alternatively, if the relation is unidirectional and you do not want to make it bidirectional, you can use a custom join:
use Doctrine\ORM\Query\Expr\Join;
$qb = $this->getDoctrine()
->getRepository(Serv::class)->createQueryBuilder('s')
->select('DISTINCT s')
->leftJoin(LinkServInfra::class, "lsi", Join::WITH, 'lsi.serv = s')
->leftJoin("lsi.infra", "infra")
->where('infra.id = :infra')
->setParameter('infra', 1);
References
How to JOIN without a relationship in Doctrine?
I would like to understand why my DQL request doesn't work. I've to entity : books(ouvrages) and authors(auteurs), there is many to many relation, so in my database a join table is create books_authors (ouvrages_auteurs) with reference "id" of each other. I would like to use this join table for have all informations of my two entity books and authors.
I've make many request in my BooksRepository but it's doesn't work :
public function getOuvrageTradeByAuteur(array $autor){
$query = $this->getEntityManager()->createQuery("SELECT o,a FROM SBMainBundle:Ouvrages o JOIN ouvrages_auteurs oa JOIN SBMainBundle:Auteurs a WHERE o.is_trade = true AND o.id = oa.ouvrages_id AND oa.auteurs_id = a.id AND a.nom_auteur = :autor")
->setParameter('autor',$autor);
return $query->getResult();
}
public function getBooksTradeByAutor(array $autor){
//requete DQL pour un many to many
$query = $this->createQueryBuilder('o');
$query->join('o.auteur','auteurs')
->where($query->expr()->in('auteurs.nomAuteur',$autor))
->andWhere('o.isTrade = true')
->orderBy('o.id','desc')
->addSelect('o,auteurs');
return $query->getQuery()->getResult();
}
public function getBooksSellByAutor(array $autor){
//requete DQL pour un many to many
$query = $this->createQueryBuilder('o');
$query->join('o.auteur','auteurs')
->where($query->expr()->in('auteurs.nomAuteur',$autor))
->andWhere('o.isSell = true')
->orderBy('o.id','desc')
->addSelect('o,auteurs');
return $query->getQuery()->getResult();
}
public function getOuvragesEchangesByAutor($auteurs){
//requete en DQL 2eme partie
$query = $this->createQueryBuilder('o')->where('o.auteur = :autor')
->andWhere('o.isTrade = true')
->join('o.auteur','a')
->setParameter('autor',$auteurs)
->orderBy('o.id','desc')
->addSelect('a');
return $query->getQuery()->getResult();
}
public function getOuvragesVentesByAutor($auteurs){
//requete en DQL 2eme partie
$query = $this->createQueryBuilder('o')->where('o.auteur = :autor')
->andWhere('o.isSell = true')
->join('o.auteur','a')
->setParameter('autor',$auteurs)
->orderBy('o.id','desc')
->addSelect('a');
return $query->getQuery()->getResult();
}
Edit for error message :
[Semantical Error] line 0, col 45 near 'ouvrages_auteurs': Error: Class 'ouvrages_auteurs' is not defined.
500 Internal Server Error - QueryException
1 linked Exception:
QueryException »
[2/2] QueryException: [Semantical Error] line 0, col 45 near 'ouvrages_auteurs': Error: Class 'ouvrages_auteurs' is not defined.
[1/2] QueryException: SELECT o,a FROM SBMainBundle:Ouvrages o JOIN ouvrages_auteurs oa JOIN SBMainBundle:Auteurs a WHERE o.is_trade = true AND o.id = oa.ouvrages_id AND oa.auteurs_id = a.id AND a.nom_auteur = :autor
Edit for the Nnew issue :
[Semantical Error] line 0, col 79 near 'auteur = :autor': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.
500 Internal Server Error - QueryException
1 linked Exception:
QueryException »
[2/2] QueryException: [Semantical Error] line 0, col 79 near 'auteur = :autor': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.
[1/2] QueryException: SELECT o, a FROM SB\MainBundle\Entity\Ouvrages o INNER JOIN o.auteur a WHERE o.auteur = :autor AND o.isSell = true ORDER BY o.id desc
I've use this request :
public function getOuvragesEchangesByAutor($auteurs){
//requete en DQL 2eme partie
$query = $this->createQueryBuilder('o')->where('o.auteur = :autor')
->andWhere('o.isTrade = true')
->join('o.auteur','a')
->setParameter('autor',$auteurs)
->orderBy('o.id','desc')
->addSelect('a');
return $query->getQuery()->getResult();
}
Thanks for your help ! :D
That error informs that the problem probably is in your entity definition. ouvrages_auteurs must exist like an association property in your Ouvrages entity, but it is more simple call it as auteurs like this:
// Ouvrage Entity definitions...
/**
* #ORM\ManyToMany(targetEntity="Auteurs", inversedBy="ouvrages")
* #ORM\JoinTable(name="ouvrages_auteurs",
* joinColumns={#ORM\JoinColumn(name="ouvrage_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="auteur_id", referencedColumnName="id")}
* )
*/
private $auteurs;
/*
* Constructor
*/
public function __construct()
{
$this->auteurs = new \Doctrine\Common\Collections\ArrayCollection();
}
Later in your query you should create dql JOIN clauses like this type:
SELECT o, a
FROM SBMainBundle:Ouvrages o
JOIN o.auteurs a
WHERE o.is_trade = true
all related auteurs with selected ouvrages will be returned in result, clause: o.id = oa.ouvrages_id is not necessary.
More info about Doctrine mapping here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-unidirectional
EDIT for new issue:
I think problem is that if autors info are in auteurs then:
$query = $this->createQueryBuilder('o')->where('a.id = :autor')
->andWhere('o.isTrade = true')
->join('o.auteur','a')
->setParameter('autor',$auteurs)
->orderBy('o.id','desc')
->addSelect('a');
I am really new at Symfony and I am trying to get used to query builder. At the moment I am trying to join three tables and the following MySQL query gives me the results I need when I run it in PhpMyAdmin
SELECT * FROM pe_users u
LEFT JOIN pe_apply a ON u.id = a.user
LEFT JOIN pe_offer o ON a.id = o.application
However when I move this inside a Symfony Repository method
namespace Ache\AdminBundle\Repository;
use Doctrine\ORM\EntityRepository;
class AdminRepository extends EntityRepository{
public function findAllAppByStatus(){
$query = $this->getEntityManager()->createQuery(
'SELECT * FROM pe_users u
LEFT JOIN pe_apply a ON u.id = a.user
LEFT JOIN pe_offer o ON a.id = o.application
');
try {
return $query->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
}
I get the error
[Syntax Error] line 0, col 7: Error: Expected IdentificationVariable |
ScalarExpression | AggregateExpression | FunctionDeclaration |
PartialObjectExpression | "(" Subselect ")" | CaseExpression, got '*'
What does this error mean? what am I doing wrong?
UPDATE
The three entities I have are as following
UserBundle:User
CoreBundle:Apply
AdminBundle:Offer
User.id links with Apply.user and Offer.application links with Apply.id
You can still use raw sql with Symfony if you are comfortable with that
$conn = $this->getEntityManager()->getConnection();
$sql = "SELECT * FROM pe_users u LEFT JOIN pe_apply a ON u.id = a.user LEFT JOIN pe_offer o ON a.id = o.application WHERE u.id = a.user";
$stmt = $conn->prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
I would do :
public function findAllAppByStatus(){
$qb = $this->createQueryBuilder('u')
->leftJoin('CoreBundle:Apply', 'a', 'WITH', 'a.user = u')
->leftJoin('AdminBundle:Offer', 'o', 'WITH', 'o.application = a')
->setMaxResults(1); // if you return only 1 result, you want to be sure only one (or none) result is fetched
return $qb->getQuery()->getOneOrNullResult();
if you want to return possibly many results, as the 'All' in the method name suggests, get rid of the ->setMaxResults() and use $qb->getQuery()->getResult();
see how the queryBuilder works with objects, not tables. Joins are built on entities and properties, not tables and field names.
I have an entity named 'tile', with a manyToMany relationship with another entity named 'coins'.
/**
* #ORM\ManyToMany(targetEntity="Coin")
* #ORM\JoinTable(name="coin",
* joinColumns={#ORM\JoinColumn(name="tile_id", referencedColumnName="tile_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="coin_id", referencedColumnName="coin_id")}
* )
**/
protected $coins;
I have a page that lists tiles and all of their associated coins. There can be a lot of coins and tiles on a page and using lazy loading can put 100-300 database queries on a single page. I am trying to avoid this by using a leftJoin.
public function getUserTiles($id)
{
$qb = $this->createQueryBuilder('b')
->select('b', 'z')
->leftJoin('b.coins', 'z')
->leftJoin('z.userInfo', 'u')
->add('where', "b.userId = ".$id." AND b.status = 'COMPLETED'")
->add('orderBy', "b.checkinDate DESC");
return $qb->getQuery()
->getResult();
}
This gives me the following error:
*[2/2] DBALException: An exception occurred while executing '
SELECT t0_.tile_id AS tile_id0, t0_.quilt_id AS quilt_id1, t0_.user_id AS user_id2, t0_.comment AS comment3, t0_.checkout_date AS checkout_date4, t0_.checkin_date AS checkin_date5, t0_.x AS x6, t0_.y AS y7, t0_.status AS status8, t0_.completed_neighbors AS completed_neighbors9, t0_.required_completed_neighbors AS required_completed_neighbors10, t0_.visible AS visible11, t0_.visible_date AS visible_date12, t0_.count_towards_coins AS count_towards_coins13, c1_.coin_id AS coin_id14, c1_.user_id AS user_id15, c1_.tile_id AS tile_id16, c1_.comment AS comment17, c1_.date_given AS date_given18, c1_.status AS status19, c1_.origin AS origin20, t0_.quilt_id AS quilt_id21, t0_.user_id AS user_id22, c1_.tile_id AS tile_id23, c1_.user_id AS user_id24
FROM tile t0_ **LEFT JOIN coin *c1_* ON t0_.tile_id = c1_.tile_id
LEFT JOIN coin *c1_* ON c1_.coin_id = c1_.coin_id**
LEFT JOIN user_info u2_ ON c1_.user_id = u2_.user_id
WHERE t0_.user_id = 14 AND t0_.status = 'COMPLETED'
ORDER BY t0_.checkin_date DESC':
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'c1_'*
As you can see, it is trying to join the coin table twice, using the same alias. What am I doing wrong?
Try:
$this->createQueryBuilder('b')
->select('b')
->addSelect('z')
->leftJoin('b.coins', 'z')
->leftJoin('z.userInfo', 'u')
->where("b.userId = :id AND b.status = 'COMPLETED'")
->orderBy('b.checkinDate', 'DESC')
->setParameter('id', $id)
->getQuery('b.checkinDate DESC')
->getSingleResult();
I fixed this problem by changing the ManyToMany relationship to OneToMany as it should have been in the first place.
I have query with two MtM relations:
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb
->select('o')
->from('UserBundle:User', 'o')
;
$qb->join('o.organisations', 'org')
->where('org.id = :organisation')
->setParameter('organisation', $filterData['organisation'])
;
$qb
->join('o.scientificDirections', 'd')
->where('d.id IN (:directionIds)')
->setParameter('directionIds', $directionIds)
->orderBy('o.surname')
;
return $qb->getQuery();
But it gives me error: Invalid parameter number: number of bound variables does not match number of tokens.
Can anybody explain me what is wrong?
Relation in User model:
/**
* #ORM\ManyToMany(targetEntity="\StrangeBundle\Entity\ScientificDirection")
*
*/
protected $scientificDirections;
/**
* #ORM\ManyToMany(targetEntity="\StrangeBundle\Entity\Organisation", mappedBy="workers")
*/
protected $organisations;
I think the reason is because you used where twice. That overwrites the first where, which is why it is giving you the parameters number error.
Use andWhere