[solved] CGridView search not working out of the box?

I used Gii’s CRUD generator and in general it worked well, but when I go to the “manage” page I can see the CGridView listing but searches do not work.

The model:




<?php

* The followings are the available columns in table 'shop_products':

 * @property integer $id

 * @property string $sku

 * @property double $price

 * @property integer $tax_rate_id

 * @property integer $manufacturer_id

 * @property string $photo

 * @property string $url

 * @property double $width

 * @property double $length

 * @property double $height

 * @property double $weight

 * @property integer $is_active

 * @property integer $mstamp

 * @property integer $cstamp

 */

class Product extends CActiveRecord

{


     //...


	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('tax_rate_id', 'required'),

			array('tax_rate_id, manufacturer_id, is_active, mstamp, cstamp', 'numerical', 'integerOnly'=>true),

			array('price, width, length, height, weight', 'numerical'),

			array('sku', 'length', 'max'=>45),

			array('photo', 'length', 'max'=>255),

			array('url', 'safe'),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('sku, price, manufacturer_id, is_active', 'safe', 'on'=>'search'),

		);

	}


	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'l10n' => array(self::HAS_ONE, 'ProductL10n', 'product_id', 'alias' => 'l10n', 'on' => 'l10n.lang_id="el"'),

			'categories' => array(self::MANY_MANY, 'Category', 'shop_category_products(product_id, category_id)'),

			'attributes' => array(self::HAS_MANY, 'ProductAttribute', 'product_id'),

			'types' => array(self::HAS_MANY, 'ProductType', 'product_id'),

			'taxRate' => array(self::BELONGS_TO, 'TaxRate', 'tax_rate_id'),

			'manufacturer' => array(self::BELONGS_TO, 'Manufacturer', 'manufacturer_id'),

		);

	}


     //...


	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('is_active',$this->is_active);

		$criteria->compare('sku',$this->sku,true);

		$criteria->compare('price',$this->price);

		$criteria->compare('manufacturer_id',$this->manufacturer_id);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

}



The view:




<?php $this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'product-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'is_active',

		'photo',

		array(

			'header' => 'Product name',

			'name' => 'id',

			'value' => '$data->l10n->caption',

		),

		'sku',

		'price',

		array(

			'header' => 'Manufacturer',

			'name' => 'manufacturer_id',

			'value' => '$data->manufacturer->l10n->caption',

		),


		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>



I have printed the $_REQUEST and everything is ok, searching for price=100 shows $_REQUEST has key of “price” with value “100”, but $this->price is null as var_dump reports in the model’s search() method, all after inspecting the response when searching.

Do you have those administrative pages in a dedicated module or in a sub directory other than the normal pages? And have you configured your urlManager to use the ‘path’ format? If so, then you would be better to check your urlManager rules.

For the moment, reset your ‘urlFormat’ to ‘get’ and check to see if the search works.

I have not configured urlManager yet, it is still commented out in config/main.php, but I still did give it a try with urlFormat=>‘get’, same thing.

The administration where search is not working is the one gii generated, where gii generated it, protected/views/product/admin.php.

Actually I generated the CRUD using gii twice just in case I had done something wrong the first time around.

Maybe I’m better off using




$criteria->compare('price',$_REQUEST['price']);



istead of




$criteria->compare('price',$this->price);



?

Um, it’s strange. I don’t know what’s wrong.

Which do you refer to, the inline filter of the grid or the advanced search form, when you say “the search doesn’t work”?

In gii generated actionAdmin, ‘price’ should come in the form of $_REQUEST[‘Product’][‘price’] and $_GET[‘Product’][‘price’].

Have you modified your _search.php form?

Both filters do not work.

Basically it turns out it doesn’t have to do with search as I cannot create new objects either, it’s like request data is not passed to the model’s properties. How is this normally handled? Where is $this->price set by $_REQUEST[‘Product’][‘price’]?

fyi I haven’t modified _search.php at all, I do not use advanced search, but it doesn’t seem to matter anyway

Hmmm … I really don’t know what’s wrong …

“$model->attributes=$_GET[‘Product’]” is the line where the model for the search will receive the search parameters.




      public function actionAdmin()

        {

                $model=new Product('search');

                $model->unsetAttributes();  // clear any default values

                if(isset($_GET['Product']))

                        $model->attributes=$_GET['Product'];  // <-- This is it !!

                $this->render('admin',array(

                        'model'=>$model,

                ));

        }



By the way, I think it’s worth noting that this model instance is not meant for the data to be retrieved and displayed. It is a holder of the search parameters that will eventually be passed to a CActiveDataProvider in the search() method. When I was new to Yii, I had spent some days with a hazy head before I realize it.

Anyway, in order to send the search parameters in the format of $_GET[‘ModelName’][‘attribute_name’], admin controller will produce a HTML code in which each input fields will have the ‘name’ attribute in the format of ‘ModelName[attribute_name]’.

For example, in the advanced search form:




<div class="row">

<label for="Product_price">Price</label>

<input size="20" maxlength="20" name="Product[price]" id="Product_price" type="text" />

</div>



Or, in the inline header filter of the CGridView:




<td><input name="Product[price]" type="text" /></td>



What do they look like in the HTML code of your admin page?

And, it’s only a guess, but is there any ‘Product’ class beside this model class?

There is only one Product class defined, extends CActiveRecord, all good.

The html looks good too, and after looking into it a bit more I tried.




	public function actionAdmin()

	{

		$model=new Product('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Product']))

			$model->attributes=$_GET['Product'];

print_r($_GET);

print_r($model->attributes);

		$this->render('admin',array(

			'model'=>$model,

		));



Both these prints work as expected, all data is there.

Also, when printing $this->attributes inside Product::search() everything is good, the problem is that even though $this->attributes[‘price’] is fine $this->price is null and the same applies to all fields.

The same thing happens in actionCreate() too, everything is good for $_POST and $model->attributes but $model->save() fails, saying that required fields are missing.

Ah, then it seems like the model validation doesn’t work at all.

Commenting out the validation rules of the model line by line would make some difference.

Product model:




class Product extends CActiveRecord

{

	public $caption;

	public $manufacturer_caption;







	public function rules()

	{

		return array(

			array('sku, price, is_active, caption, manufacturer_caption', 'safe', 'on'=>'search'),

		);

	}






	public function search()

	{

/*		$this->is_active = empty($_REQUEST['Product']['is_active']) ? null : $_REQUEST['Product']['is_active'];

		$this->caption = empty($_REQUEST['Product']['caption']) ? null : $_REQUEST['Product']['caption'];

		$this->price = empty($_REQUEST['Product']['price']) ? null : $_REQUEST['Product']['price'];

		$this->manufacturer_caption = empty($_REQUEST['Product']['manufacturer_caption']) ? null : $_REQUEST['Product']['manufacturer_caption'];

		$this->sku = empty($_REQUEST['Product']['sku']) ? null : $_REQUEST['Product']['sku'];

*/

		$criteria = new CDbCriteria;


		$criteria->with = array('l10n', 'manufacturer');


		$criteria->join = "LEFT JOIN shop_manufacturers_l10n as mf_l10n ON t.manufacturer_id=mf_l10n.manufacturer_id AND mf_l10n.lang_id='el'";

		$criteria->compare('mf_l10n.caption',$this->manufacturer_caption, true);


		$criteria->compare('l10n.caption',$this->caption, true);

		$criteria->compare('t.is_active',$this->is_active,false);

		$criteria->compare('t.sku',$this->sku,true);

		$criteria->compare('t.price',$this->price,false);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}



Product controller:




	public function actionAdmin()

	{

		$model=new Product('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Product']))

			$model->attributes=$_GET['Product'];

print_r($_GET);

print_r($model->attributes);

echo "|".$model->price."|\n\n";

		$this->render('admin',array(

			'model'=>$model,

		));

	}



Results:




Array

(

    [r] => product/admin

    [Product] => Array

        (

            [is_active] => 

            [photo] => 

            [caption] => 

            [sku] => 

            [price] => 123

            [manufacturer_caption] => 

        )


    [Product_page] => 1

    [ajax] => product-grid

)

Array

(

    [is_active] => 

    [photo] => 

    [caption] => 

    [sku] => 

    [price] => 123

    [manufacturer_caption] => 

)

||



Could it be something stupid I’ve done? It’s driving me nuts… I haven’t done any heavy modding anywhere, all I’ve done is generate models and crud with gii.

Looking at this wiki post I found that $model->attributes = array(); actually calls CModel::setAttributes(). I tried to print data in there and it looks like this function is not even called.

Ahhhh! OK, I’ve got it at last !!!

There’s a relation named ‘attributes’ !!




        public function relations()

        {

                return array(

                        ...

                        'attributes' => array(self::HAS_MANY, 'ProductAttribute', 'product_id'),

                        ...

                );

        }



Rename it at once.

Oh boy… I wouldn’t have realized it soon, can’t thank you enough, thanks!

Yeah, it has already been there in your first post.

I have overlooked it and forced you to walk a long way around. I guess someone else could have got it much more quick.

Anyway, let’s make a toast. Cheers!

cheers mate, thanks again!