Cgridview And Relation Queries

Greetings, i started studying Yii few days ago. I didn’t face many major difficulties until i tried to use CGridView. Probably questions that i`ll mention were asked many times before me, but even after searching and trying numerous solutions i couldn’t make working code.

My situation: There is MSSQL database with 4 tables. Main table - ‘table1’ which is related to ‘table2’ which is also relater to 2 other tables ‘table3’ and ‘table4’.

With usage of GII i have created 4 models of those tables and added CRUD for ‘table1’.

With CGridView i need to display data from all 4 table (table1.table1id, table2.table2id, table3.table3name, table4.table4name).

How can i force first way to work? How can i add search filters to second?

How can i bind parameters to both queries?Which way is more preferable to use?

1) way With usage of models and eager loading(with) i couldn’t even achieve displaying data from table2. Error text - “Undefined property table1.table2id”. Here is code sample that i have tried:

Model of table1




    public function relations()

    {return array(

            'table2s' => array(self::HAS_MANY, 'table2', 'table1id'),    );


    public function search()

    {

        $criteria=new CDbCriteria;

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

        $criteria->with=array('table2s');

        $criteria->compare('table2s.table2id', $this->table2s->table2id, true);


    return new CActiveDataProvider($this, array(

            'criteria'=>$criteria,

            'pagination' => array(

                'pageSize' => 10000000,

            ),

        ));

    }




cGridView


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

    'id'=>'table1-grid',

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

    'enablePagination' => false,

    'filter'=>$model,


    'columns'=>array(

        'table1id',

        array(

            'name'=>'table2id',

            'value'=>'$data->table2s->table2id',

            'sortable'=>true,

        ),

    ),

)); 



2) way Second way was with usage of CSqlDataProvider. This time i managed to display all needed data, but couldn’t display search filters above CGridView table.

Model of table1




 public function searchTableDisc()

    {


         $sql = 'SELECT  table1.table1id AS t1id,

                table2.table2id as t2id,

                table3.Name as t3name,

                table4.Name as t4name

                FROM table1

                INNER JOIN table2 ON

                table1.table1id=table2.table1id

                INNER JOIN table3 ON

                table2.table3id=table3.table3id

                INNER JOIN table4 ON

                table2.table4id=table4.table4id';


        $rawData = Yii::app()->db->createCommand($sql); 

        $count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM (' . $sql . ') as count_alias')->queryScalar(); //the count


        return $ProperData = new CSqlDataProvider($rawData, array( 

            'keyField' => 't1id',

            'totalItemCount' => $count,


            //if the command above use PDO parameters

            //'params'=>array(

            //':param'=>$param,

            //),


            'sort' => array(

                'attributes' => array(

                    't1id','t2id', 't3name','t4name',

                ),

                'defaultOrder' => array(

                    't1id' => CSort::SORT_ASC, //default sort value

                ),

            ),

            'pagination' => array(

                'pageSize' => 100000,

            ),

        ));

    }

 

cGridView


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

    'id'=>'table1-grid',

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

    'ajaxUpdate' => true,

    'enablePagination' => false,

    //'filter'=>$model,


    'columns'=>array(

        't1id',

        't2id',

        't3name',

        't4name',

      ),


));

 

ad 1) it should be:




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

    'id'=>'table1-grid',

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

    'enablePagination' => false,

    'filter'=>$model,


    'columns'=>array(

        'table1id',

        'table2s.table2id'

    ),

));



to make it sortable/searchable read: http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview/

Now there is no error, but no data in this column either.

I just noticed… you define relation as HAS_MANY. HAS_MANY return always array of objects (even if there is only one), and you cannot use such relation that simple. try:




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

    'id'=>'table1-grid',

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

    'enablePagination' => false,

    'filter'=>$model,


    'columns'=>array(

        'table1id',

        array(

            'header'=>'Column header',

            'value'=>'implode(", ", CHtml::listData( $data->table2s, "table2id", "table2id" ) )',

        ),

    ),

)); 



or something like this…

Now it works, not in the way i wanted to see it, but will work for now. Thanks!

How can i bind parameters to this and 2nd way queries?

Obviously there was commented part for using parameters.

My queries are working perfectly when i am passing $_POST variable there, but whenever i am trying to use this code with parameters - all script fails.

Any ideas?


//if the command above use PDO parameters

           'params'=>array(

           ':param'=>$_POST['somevar'],

            ),



Also this one works fine for generation of GridView, but doesnt work on filtering etc and results in failing to provide any data.




$rawData->bindParam(':param', $_POST['somevar'], PDO::PARAM_INT);



Fail with what? is there any error message? what it says? Is there anything in log file?

Actually there is. seems like SELECT COUNT(*) query can’t be completed.

Here is error message from application.log file.




2014/09/30 21:02:22 [error] [system.db.CDbCommand] CDbCommand::fetchColumn() failed: SQLSTATE[07002]: [Microsoft][SQL Server Native Client 10.0]COUNT field incorrect or syntax error. The SQL statement executed was: SELECT COUNT(*) FROM ([i]MY LONG QUERY THAT WORKS WITHOUT PARAMS[/i]) as count_alias.


014/09/30 21:02:22 [error] [exception.CDbException] exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[07002]: [Microsoft][SQL Server Native Client 10.0]COUNT field incorrect or syntax error. The SQL statement executed was: SELECT COUNT(*) FROM ([i]MY LONG QUERY THAT WORKS WITHOUT PARAMS[/i]) as count_alias.



I bypassed this error by using next construction(binding params for $count separately and assigning $_POST[‘suv’] 2 times to different parameters). But this seems to me like a bad construction, is there any better way to do it?




 $rawData = Yii::app()->db->createCommand($sql); //or use ->queryAll(); in CArrayDataProvider

        $count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM (' . $sql . ') as count_alias'); //the count


        $count->bindParam(':suv', $_POST['suv'], PDO::PARAM_INT);

        $count->bindParam(':suvd', $_POST['suv'], PDO::PARAM_INT);

        $count->bindParam(':pr', $_POST['pr'], PDO::PARAM_INT);

        $count->queryScalar();


        return $ProperData = new CSqlDataProvider($rawData, array( //or $model=new CArrayDataProvider($rawData, array(... //using with querAll...

            'keyField' => 'discid',

            'totalItemCount' => $count,


            'params'=>array(   //if the command above use PDO parameters

            ':suv'=>$_POST['suv'],

            ':suvd'=>$_POST['suv'],

            ':pr' => $_POST['pr'],

             ),

...



you use same query for count and return data, and there are params in that query (you pass them to CSqlDataProvider). You need to pass them also to queryScalar when fetching count(*):




$countCommand = Yii::app()->db->createCommand('SELECT COUNT(*) FROM (' . $sql . ') as count_alias'); //the count


$count = $countCommand->queryScalar( array(

            ':suv'=>$_POST['suv'],

            ':suvd'=>$_POST['suv'],

            ':pr' => $_POST['pr'],

             ));



I am really grateful for your support, Redguy. Thanks for helping me out.