Ran into a weird bug that I can’t quite understand why things are happening the way they are. I’m fairly new to Yii (3 months) and have just started really getting into using CGridview with my latest project.
As part of this project, I tried to combine what I learned of scopes with CGridView and CDbCriteria. Relevant to my issue, here are the methods in my CActiveRecord model that I use (OrderProductTask).
public function for_order($order_id){
if($order_id){
$this->getDbCriteria()->mergeWith(array(
'condition'=>'order_product.order_id=:order_id',
'params'=>array(':order_id'=>$order_id),
'together'=>true,
'with'=>array('order_product'),
));
}
return $this;
}
public function with_criteria($criteria){
$this->getDbCriteria()->mergeWith($criteria);
return $this;
}
The issue I am having is with the custom method with_criteria(). I followed the model of how named scopes work, and created with_criteria() to take a custom CDbCriteria to give me better flexibility in creating dataProviders for CGridView, without having to define a scope for every little thing I may want to look up.
The issue I am having is that the criteria I pass in this way seems to be added onto previous criteria on the page, resulting in only the first CGridView to have any results, in many cases.
<?php
foreach(Order::model()->findAll() as $order){
/*
$criteria = new CDbCriteria();
$criteria->compare('order_product.order_id', 0);
$dataProvider = new CActiveDataProvider(OrderProductTask::model()->together()->with(array(
'order_product',
))->with_criteria($criteria)
);
*/
echo '<h2>'.$order->order_id.'</h2>';
$criteria = new CDbCriteria;
$criteria->compare('order_product.order_id', $order->order_id);
$dataProvider = new CActiveDataProvider(OrderProductTask::model()->together()->with(array(
'order_product',
))->with_criteria($criteria)
);
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'task_id',
'order_product.order_id',
),
));
}
?>
In the logs I am seeing the following queries:
and…
The WHERE clause continues to grow and grow with each loop:
etc, etc…
If I uncomment the block of code at the top (where I set the order_id = 0), then not even the first result displays anything, as it is looking for an order_id of 0 for all the CGridViews. If I change the uncommented code to use for_order($order->order_id) instead of with_criteria($criteria), the problem vanishes as long as the ‘order_id=0’ code at the top remains commented out. If it is not commented, then still, no results are displayed for any table.
Since both $criteria and $dataProvider are being overwritten with each pass of the loop, I don’t understand why the criteria is compounding like it is.
Update:
Apparently the issue isn’t with my with_criteria() scope at all. Using the following code I get correct CGridViews for each order_id in the loop, but the additional table at the end, which queries different aspects of OrderProductTask, has no results if the loop executes first.
<?php
foreach(Order::model()->findAll() as $order){
echo '<h2>'.$order->order_id.'</h2>';
$criteria = new CDbCriteria;
$criteria->compare('order_product.order_id', $order->order_id);
$dataProvider = new CActiveDataProvider(OrderProductTask::model()->together()->with(array(
'order_product',
))->for_order($order->order_id)//->with_criteria($criteria)
);
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'task_id',
'order_product.order_id',
),
));
}
$dataProvider = new CActiveDataProvider(OrderProductTask::model()->for_order_product(53));
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'task_id',
'order_product_id',
),
));
?>
The WHERE clause of the query for the last table is:
which, as you can see includes a constraint on the order_id, despite nothing in the scope for_order_product() having any reference to the order id.
public function for_order_product($op_id){
if($op_id){
$this->getDbCriteria()->mergeWith(array(
'condition'=>'t.order_product_id = :op_id',
'params'=>array(':op_id'=>$op_id),
));
}
return $this;
}
(Yes, I verified that if I comment out the foreachloop at the start that order_product_id 53 does populate the last table with results.)
Using Yii 1.1.10
Am I seriously misunderstanding how this is supposed to work, or is something broken?