how to set more than one condition in doctrine ManyToMany ..
model
/**
* #ORM\ManyToMany(targetEntity="users",inversedBy="friends",cascade={"ALL"})
* #ORM\JoinTable(name="friends",
* joinColumns={#ORM\JoinColumn(name="friend_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")}
* )
*/
private $groupsa;
public function getusersre() {
return $this->groupsa;
}
output
SELECT
t0.id AS id_1,
t0.email AS email_2,
t0.username AS username_3,
t0.password AS password_4,
t0.first_name AS first_name_5,
t0.last_name AS last_name_6,
t0.location AS location_7,
t0.remember_token AS remember_token_8,
t0.created_at AS created_at_9,
t0.updated_at AS updated_at_10
FROM
users t0
INNER JOIN friends ON t0.id = friends.user_id
WHERE
friends.friend_id = ?
i want that it be like this
WHERE
friends.friend_id = ?
or friends.xxxx_id = ?
wait for a reponse , thanks for all ....
You can do as #SergioIvanuzzo suggests, but if you want to do this inside your entity you can also use the doctrine Doctrine\Common\Collections\Criteria class for this. You can read all about it in the documentation chapter 8.8. Filtering Collections.
public function getFriends(){
$id = 1; // ...the id you want to use for filtering
$criteria = Criteria::create()
->where(Criteria::expr()->eq("xxxx_id", $id));
return $this->friends->matching($criteria);
}
Related
I'm trying to make a many to many join with a Doctrine findBy()
$articles = $entityManager->getRepository(Articles::class)
->findBy(['rubriquesrubriques'=>$id],['idarticles'=>"ASC"]);
But I get
An exception occurred while executing
'SELECT t0.idarticles AS idarticles_1,
t0.thetitle AS thetitle_2, t0.theslug AS theslug_3, t0.thedescription AS
thedescription_4, t0.thedate AS thedate_5, t0.users_idusers AS users_idusers_6
FROM articles t0 WHERE
articles_has_rubriques.rubriques_idrubriques = ?
ORDER BY t0.idarticles ASC' with params ["2"]:
SQLSTATE[42S22]: Column not found: 1054 Champ
'articles_has_rubriques.rubriques_idrubriques' inconnu dans where clause
The column articles_has_rubriques.rubriques_idrubriques exists in my DB,
but I don't see the INNER JOIN !
When I make my many to many with a simple Find():
$articles = $entityManager->getRepository(Articles::class)->find($id);
The query is correct!
SELECT t0.idrubriques AS idrubriques_1,
t0.thertitle AS thertitle_2
FROM
rubriques t0
INNER JOIN articles_has_rubriques ON t0.idrubriques =
articles_has_rubriques.rubriques_idrubriques
WHERE articles_has_rubriques.articles_idarticles = ?
is it impossible to perform my many2many query with a findBy in the 4.1.6 version of Symfony???
This is my ORM relation:
In entity Rubriques.php:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Articles", mappedBy="rubriquesrubriques")
*/
private $articlesarticles;
In entity Articles.php
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Rubriques", inversedBy="articlesarticles")
* #ORM\JoinTable(name="articles_has_rubriques",
* joinColumns={
* #ORM\JoinColumn(name="articles_idarticles", referencedColumnName="idarticles")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="rubriques_idrubriques", referencedColumnName="idrubriques")
* }
* )
*/
private $rubriquesrubriques;
Thank you so much
My question was stupid :
I'have an easy way to do that:
$rubriqueActu = $entityManager->getRepository(Rubriques::class)->find($id);
$articles = $rubriqueActu->getArticlesarticles();
SQL:
SELECT t0.idarticles AS idarticles_1, t0.thetitle AS thetitle_2,
t0.theslug AS theslug_3, t0.thedescription AS thedescription_4,
t0.thedate AS thedate_5, t0.users_idusers AS users_idusers_6
FROM articles t0 INNER JOIN articles_has_rubriques
ON t0.idarticles = articles_has_rubriques.articles_idarticles
WHERE articles_has_rubriques.rubriques_idrubriques = ?
Building a query to select M entities that have no corresponding N entities returns an error with the following query:
return $this->getEntityManager()
->createQuery(
'SELECT p FROM VolVolBundle:Opportunity p '
. 'LEFT JOIN VolVolBundle:Volunteer v'
. 'WHERE v.id is null '
. 'ORDER BY p.organization ASC'
);
returns the error:
Expected Doctrine\ORM\Query\Lexer::T_WITH, got 'v'
Yet the following SQL statement returns a non-empty resultset:
select o.id from opportunity o
left outer join opportunity_volunteer ov on o.id = ov.opportunity_id
left outer join volunteer v on ov.volunteer_id = v.id
where ov.id is null;
where opportunity_volunteer is the linking table
Opportunity entity relationship definition
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Volunteer", inversedBy="opportunities", cascade={"persist"})
* #ORM\JoinTable(name="opportunity_volunteer",
* joinColumns={#ORM\JoinColumn(name="opportunity_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="volunteer_id", referencedColumnName="id")}
* ))
*/
protected $volunteers;
public function addVolunteer(\Vol\VolBundle\Entity\Volunteer $volunteer) {
$volunteer->addOpportunity($this);
array_push($volunteers, $volunteer);
}
public function getVolunteers() {
return $this->volunteers;
}
Volunteer entity relationship definition
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Opportunity", mappedBy="volunteers")
*/
protected $opportunities;
public function addOpportunity(\Vol\VolBundle\Entity\Opportunity $opportunity) {
array_push($opportunities, $opportunity);
}
public function getOpportunities() {
return $this->opportunities;
}
Reading from the DQL docs, you should use WITH instead of WHERE to limit the join. Search for the code snippet "Restricting a JOIN clause by additional conditions" in the docs. I guess it should be something like:
return $this->getEntityManager()
->createQuery(
'SELECT p FROM VolVolBundle:Opportunity p '
. 'LEFT JOIN VolVolBundle:Volunteer v'
. 'WITH v.id IS null '
. 'ORDER BY p.organization ASC'
);
This is not tested, though.
The eventual solution was to create a 1:n:1 relationship, eliminating the "invisible" entity in the middle. This enabled adding fields to the relationship. So in addition to assuring each line ended with a space character before concatenation the query needed to be rewritten. It now finds the null results as desired:
return $this->getEntityManager()
->createQuery(
'SELECT p FROM VolVolBundle:Opportunity p '
. 'LEFT JOIN VolVolBundle:OpportunityVolunteerEmail e '
. 'with p = e.opportunity '
. 'where e.opportunity is null'
. 'ORDER BY p.organization ASC'
)->getResult();
I have an issue to find an alternative way to count Users who suffer a pathology (a count with a group by)
the issue is I prefer not to make a for loop on pathologies to count that, and I'de like if I could get your advice.
here's some pieces of code I have :
User Entity :
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="user")
*/
private $hospitalisations;
Hospitalisation Entity:
/**
* #ORM\ManyToOne(targetEntity="Pathologie", inversedBy="hospitalisations")
*/
private $pathologie;
Pathology Entity:
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="pathologie")
*/
private $hospitalisations;
What I have to do is to count how many users suffers of each pathologie in the database.
Thank you :)
Create a custom repository class PathologieRepository
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
Add this (not tested):
public function countUsers($pathologieID)
{
$result = $this->getEntityManager()
->createQuery("
SELECT COUNT(u) as c FROM YourMainBundle:Users u
JOIN u.hospitalisations h
JOIN h.pathologies p
WHERE
p.id = :pathologie
")
->setParameter('pathologie', $pathologieID)
->setMaxResults(1)
->getSingleResult();
return $result['c'];
}
If you want do this in twig like (pseudo):
for pathologie as p
print p.countUsers(p.id)
You have to create a method in your pathologie entity class. But you cannot use entity manager in entity classes (you can by using a hack but this is not recommended). So you have to use loops to count the users.
public function getUserCount()
{
$hospitalisations = $this->getHospitalisations();
$counter = 0;
foreach ($hospitalisations as $h)
{
$counter += count($h->getUsers());
}
return $counter;
}
I solved the issue.
Here's the solution i've come up with:
$result = $this->getEntityManager()
->createQuery("
SELECT p.id, p.nom, COUNT(DISTINCT u) as nbUsers , COUNT(DISTINCT i) as nbImported
FROM AcmeDemoBundlePathologie p
left JOIN p.importedUsers i
left JOIN p.hospitalisations h
left JOIN h.user u
GROUP BY p.id, p.nom
")
->getArrayResult();
I'm trying to convert this SQL into either DQL or whatever the query builder variant would look like.
select *
from project_release r
where (select s.title as status_name
from release_status_log l
left join release_status s
on l.release_status_id = s.id
where l.release_id = r.id
order by l.created_at desc
limit 1
) not in ('Complete', 'Closed')
;
From inside the repository class for the Release entity, I've tried this
return $this->getEntityManager()->createQuery("
select r.*
from MyBundle:Release r
where (select s.title
from MyBundle:ReleaseStatusLog l
join l.status s
where l.release = r
order by l.createdAt desc
limit 1
) IN ('Complete','Closed')
order by r.release_date ASC
limit 10
")->getArrayResult();
Which gives the error
[Syntax Error] line 0, col 265: Error: Expected
Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got 'limit'
Which is referring to the limit 1 in the subquery.
So then I tried this
return $this
->createQueryBuilder('r')
->select('r.*')
->where("(select s.title
from MyBundle:ReleaseStatusLog l
join l.status s
where l.release = r
order by l.created_at desc
limit 1
) $inClause ('Complete', 'Closed')
")
->setMaxResults( $limit )
->orderBy('release_date', 'ASC')
->getQuery()
->getArrayResult()
;
Which gives the same error. How can I execute a subquery limited to 1 row per row in the parent query?
Symfony 2.0.15
Doctrine 2.1.7
PHP 5.3.3
MySQL 5.1.52
I have a solution for this now. I ended up falling back on the native query system with the result set mapping from the entity in questions.
It's not a great solution, but it works and until I see another solution, it's the only option with this type of WHERE clause.
Here's what my finder method looks like now
/**
* Finds Releases by their current status
*
* #param array $statuses White-list of status names
* #param boolean $blackList Treat $statuses as a black-list
* #param integer $limit Limit the number of results returned
* #param string $order Sort order, ASC or DESC
*
* #throws \InvalidArgumentException
*
* #return array <Release>
*/
public function findByCurrentStatus( array $statuses, $blackList=false, $limit=null, $order='ASC' )
{
if ( empty( $statuses ) )
{
throw new \InvalidArgumentException( "Must provide at least one status" );
}
$inClause = $blackList ? 'not in' : 'in';
$rsm = new ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata('MyBundle:Release', 'r');
$SQL = "
select *
from project_release r
where (select s.title as status_name
from release_status_log l
left join release_status s
on l.release_status_id = s.id
where l.release_id = r.id
order by l.created_at desc
limit 1
) $inClause ('" . implode( "','", $statuses ) . "')
order by r.release_date $order
";
if ( $limit )
{
$SQL .= " limit $limit";
}
return $this
->getEntityManager()
->createNativeQuery( $SQL, $rsm )
->getResult()
;
}
I kind of loathed going back to building a query as a string, but oh well. Oh, and for you eagle-eyes, $statuses does not come from user data, so no SQL injection vulnerabilities here ;)
In addition to your Native SQL solution, you can create two queries using DQL within a single repository method.
Some adjustment may be required but you could try this:
public function findCompletedReleases()
{
$em = $this->getEntityManager();
$dqlSubQuery = <<<SQL
SELECT
s.title status_name
FROM
Acme\MyBundle\Entity\ReleaseStatus s,
Acme\MyBundle\Entity\ReleaseStatusLog l,
Acme\MyBundle\Entity\Release r
WHERE
l.release = r.id AND
l.status = s.id
ORDER BY l.createdAt DESC
SQL;
$statusName = $em->createQuery($dqlSubQuery)
->setMaxResults(1)
->getSingleScalarResult();
$dql = <<<SQL
SELECT
r
FROM
Acme\MyBundle\Entity\Release r
WHERE
:status_name IN ('Complete','Closed')
ORDER BY r.release_date ASC
SQL;
$q = $em->createQuery($dql)
->setParameters(array('status_name' => $statusName))
->setMaxResults(10);
return $q->getArrayResult();
}
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