I need to grab data from a symfony 2 db. The data looks like :
Parent-Element [id 15]
-> Child Element [id 20, parent ID 15]
--->Child Element [id 27, parent ID 20]
----->Child Element [id 34, Parent ID 27]
....
The Childs are assigned to each parent Element by a cathegory ID see [ ].
There might be more than one Child Elements per level.
In php it would be easy to grab this by a while loop. But in Symfony im stucking. Can anyone help me finding a solution? IS there a while loop in symfony?
Kind regdards
Philipp
EDIT: I mean, in "normal" php I would do a simple while or create an array with ids which I loop through by another while loop... In smyfony, I would use a queryBuilder like that
$query = $em->createQueryBuilder()
->select('d')
->from('PrUserBundle:Location', 'd')
->where('d.client_id = :client_id')
->setParameter('client_id', $this->clientId)
->getQuery();
$results=$query->getResult();
Where I don't see any possibility to grab any other Ids or sort it so that I can render a parent-child listing.
What about iterators:
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($iterator as $key => $value) {
echo "$key => $value\n";
}
Related
I have CLub model (clubs) hasMany with User model like
Club n-n User
and I have UserClub model with columns: id, club_id, user_id, etc
In Club model
public function getCountUsers()
{
return $this->hasMany(UserClub::className(), ['club_id'=>'id'])->count();
}
I wanna count all User on Club as code:
$query = Club::find()
->joinWith(['countUsers']);
// ->with('countUsers');
->all();
so it is not working and throwing an error
Club has no relation named \"countUsers\"."
Because it isn't a relation as it does not return a model object or an array of model objects, instead you are using ->count() that makes it return a string that contains the total count for the user against the club.
If you are looking to get a count for the users against all the Clubs you can use the currently defined relation like $club->countUser see below.
$clubs=Club::find()->all();
foreach($clubs as $club){
echo $club->countUser;
}
or change the relation to
public function getCountUser(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
and use it like
$clubs=Club::find()->all();
foreach($clubs as $club){
echo count($club->countUser);
}
or like below
$clubs=Club::find()->all();
foreach($clubs as $club){
echo $club->getCountUser()->count();
}
EDIT
You are actually trying to transform the following query using ActiveRecord as far as I understood from the discussion.
SELECT clubs.id, count(user_clubs.id) as total
FROM
clubs
left join user_clubs on clubs.id = user_clubs.club_id
group by clubs.id
if that is correct you can use the following
Clubs::find ()
->alias ( 'c' )
->select ( [ new \yii\db\Expression ( 'c.[[id]], count(uc.[[id]]) as total' ) ] )
->leftJoin ( '{{%user_clubs}} uc' , 'uc.club_id=c.id' )
->groupBy ( 'c.id' )
->all ();
Note : You have to do one more thing you have to add a public property $total inside your Club model and add it to safe rules, because you are selecting the count as an alias total and until unless you define it inside the model the result set won't show you the count, so add the following inside the Club model.
public $total;
under rules
[[other fields...,'total'] , 'safe' ] ,
EDIT2
For some reason, I have a feeling that you are trying to count by specifying a relation instead of specifying the ->leftJoin () with the table user_clubs in the query.
If that is so then you have to change your relation getUserCount() you should better give a meaningful name that describes it. i would rename it to getClubUsers()
public function getClubUsers(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
After this, you still have to declare a public property $total as I described before inside your Club model, and add it to safe rules.
Now you can write your query in the following way
Clubs::find ()
->alias ( 'c' )
->select ( [ new \yii\db\Expression ( 'c.[[id]], count(cu.[[id]]) as total' ) ] )
->joinWith( ['clubUsers cu'] )
->groupBy ( 'c.id' )
->all ();
You can do this with join, in my case i get users who have more than 0 referrals.
$users = User::find()->with('referrals')
->from(User::tableName() . ' t')
->join('left join',User::tableName().' r','r.Deeplink = t.ReferralID')
->select('t.*,count(r.ID) as ct')
->groupBy('t.ID')
->andFilterHaving(['>','ct',0])
->all();
Hi your relation is correct check you error Club has no relation named \"countUsers\"."
Means you are calling a relation which not exist :
change query like this, Relation name should be in Club Model
public function getCount(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
$clubs=Club::find()->all();
foreach($clubs as $club){
echo count($club->getCount);
}
$query = Club::find()
->joinWith(['count']);
// ->with('countusers');
->all();
If you want count just do like this .
Load the Club model .
$club_model = Club::find()
$count = club_model->count;
I'v got simple m2m relation (book -> book_mark <- mark). I want to find item(book) by 1-2-3... x-count of tags(marks). Example: Book1 got these tags: [Mark1, Mark2, Mark3], Book2 got these tags: [Mark1, Mark3, Mark4]. Search list is [Mark1, Mark2]. I want to find only items, which have ALL tags from Search list, i.e. only Book1 in this example.
I have tried many ways and spend much time google it, but didn't find the answer.
Closest that I have is this:
return $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm')
->andWhere(':marks_list MEMBER OF b.marks_list')
->setParameter('marks_list', $marksList)
->getQuery()->getArrayResult();
But it's looking for books which have at least 1of the parameters, not all of them together
Next, I'v decided that I'm absolutely wrong and start thinking this way:
public function findAllByMarksList(array $marksList)
{
$qb = $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm');
for ($i = 0; $i<count($marksList); $i++){
$qb->andWhere('m.id in (:mark'.$i.')')
->setParameter('mark'.$i, $marksList[$i]);
}
return $qb->getQuery()->getArrayResult();
}
But here I faced another problem: This code is checking only 1 mark and then always returns an empty set if the number of parameters is more than 1.
Best regards.
So, updated answer... It works (I have relation many to many between reviews and brands) it's the same situation, but for example if you have
Book 1 - mark1, mark2, mark3
Book 2 - mark1, mark2, mark3, mark4
with this code you will also find the book2, because all of it marks are in this list.
If you need to find book which haves only these 3 tags, you additionally need to add checking for count. (Count of tags = count of tagList)
public function test()
{
// just selecting for list for test
$brandsList = $this->_em->createQueryBuilder()
->select('b')
->from('ReviewsAdminBundle:Brands', 'b')
->where('b.id in (:brandIds)')
->setParameter('brandIds', [6,4])
->getQuery()
->getResult();
dump($brandsList);
// query part
$qb = $this->createQueryBuilder('r')
->select('r')
->leftJoin('r.brand', 'brands')
->where('r.published = 1');
foreach ($brandsList as $oneBrand) {
/** #var Brands $oneBrand */
$identifier = $oneBrand->getId();
$qb->andWhere(':brand'.$identifier.' MEMBER OF r.brand')
->setParameter('brand'.$identifier, $identifier);
}
dump($qb->getQuery()->getResult());
die;
}
ps. Additionally you can check doctrine2 queryBuilder must return only result matching with array values (ids): 0/Null and/or One and/or Many id(s) have to return One result (close to our situation)
And, I think there's not better way of accomplishing this. Either you use multiple andWheres to compare id OR use MEMBER OF
I have these two tables
I want to get all products(with all the children) that have at least one child with log_id = 13. Let's say I have the following rows in eorder_product_config table:
The function that retrieves the products looks like this:
public function getProducts($logId){
$q = $this
->createQueryBuilder('p')
->select('p', 'pc')
->where('pc.logisticStatus = :logId')
->setParameter('logId', $logId)
->getQuery();
return $q->getResult();
}
This will get the product(id = 18) with only 2 children(id = 46,48) in the productConfigs collection and I want have all 5 children if there is at least one that has log_id = 13.
I've found a workaround using subqueries:
public function getProducts($logId){
// search for configs that have log_id = 13
$subQuery = $this->createQueryBuilder('pp')
->select('DISTINCT pp.id')
->leftJoin('pp.productConfigs', 'ppc')
->leftJoin('ppc.logisticStatus', 'pls')
->where('ppc.logisticStatus = :logId');
//->andWhere('ppc.id = p.id'); // used for EXIST query method
// main query
$q = $this->createQueryBuilder('p');
$q->select('p', 'pc');
$q->leftJoin('p.productConfigs', 'pc')
// inject subquery, check to see if current product is in
// the subquery result
$q->where($q->expr()->in('p.id', $subQuery->getDQL()));
//$q->where($q->expr()->exists($subQuery->getDQL()))
$q->setParameter('logId', $logId);
return $q->getQuery()->getResult();
}
***I've seen that using the EXIST query does't work as it should that's why I choose the IN query. But in the raw sql query they both return same results.
I need to transcript this kind of request in doctrine under symfon:
SELECT node.name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.name = 'ELECTRONICS'
ORDER BY node.lft;
I try this, but it doesn't work:
$nodesDQL = $this->createQueryBuilder('childs')
->select('childs')
->from('AppBundle:NestedCategory', 'parent')
->join('AppBundle:NestedCategory', 'childs')
->where(new BetweenExpression('childs.lft', 'parent.lft', 'parent.right'))
->andWhere('parent = :parent')
->setParameter('parent', $node);
I can't join like this, any idea welcomes !
I think about subrequest but how in doctrine ?
Regards.
PS: I'm frenchy with english difficulties.
I don't think you need to join parent if each child has parent id already, it can just be a criteria.
E.g.
$qb = $this->createQueryBuilder('children');
$qb->select('children')
->from('AppBundle:NestedCategory', 'children')
->where($qb->expr()->between('children.lft', ':parentLft', ':parentRgt'))
->andWhere('children.parent = :parent')
->setParameter('parent', $node)
->setParameter('parentLft', $node->getLft()) // assuming you can get lft/rgt from parent
->setParameter('parentRgt', $node->getRgt())
->getQuery()
->getResult()
;
This would get you all the children of the parent node where child node left is between parent right/left.
I have a problem. I don't know how to show the exactly data I want.
My array is like this:
$races[$numRace][$finalPosition]
$races[1][1] = array ('stephan','1:27,895');
$races[1][2] = array ('george', '1:29,075');
$races[1][3] = array ('peter', '1:29,664');
$races[1][4] = array ('benson', '1:29,915');
$races[2][1] = array ('benson', '1:41,113');
$races[2][2] = array ('stephan','1:41,434');
$races[2][3] = array ('george', '1:43,654');
foreach ($races as $v1) {
foreach ($v1 as $v2) {
foreach ($v2 as $v3) {
echo "$v3\n";
}
}
}
This one shows me every data of $race array.
My question is: How can I do for showing just results for race 2?
Important: We don't know how many runners have participated on each race (So, we need a "foreach").
I would like a result like this:
benson
stephan
george
Simply iterate through only the relevant array. Based on your code your foreach should be:
foreach ($races[2] as $pos => $info){
echo $pos.': '.$info[0];
}
I've hard-coded the value 2 in the code but you could easily use a variable (foreach ($races[$raceNum]).
If you don't already know, => makes it possible for us to use both the key and the value as variables in our loop.