Cgridview On Mssql Not Work For Me.

Hello,

I have a problem for implimentation cgridview.

I use pdo mssql driver to connect with sql server (sql server 2008r2). I had tried to implement cgridview with relation table function on mysql it’s work.

But I use the code on mssql just edit part of connection with database the data not update when change page on pagination.

but the sort column does available but it error if click another page number on pagination after click sort column.

many thanks.

I think this is the same bug as http://code.google.com/p/yii/issues/detail?id=997 ,because I try it with mysql with no error.

Thanks you very much.

I use this code from link https://code.google.com/p/yii/source/browse/trunk/framework/db/schema/mssql/CMssqlCommandBuilder.php?spec=svn2821&r=2821

and replace function applyLimit

public function applyLimit($sql, $limit, $offset)

{


	$limit = $limit!==null ? intval($limit) : -1;


	$offset = $offset!==null ? intval($offset) : -1;


	if ($limit > 0 && $offset <= 0) //just limit


		$sql = preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',"\\1SELECT\\2 TOP $limit", $sql);


	


	else if($limit > 0 && $offset > 0)


	{


		$sql = preg_replace(


        '/^SELECT\s+(DISTINCT\s)?/i',


        'SELECT $1TOP ' . ($limit+$offset) . ' ',


        $sql


        );





		$orderBy = stristr($sql, 'ORDER BY');


		&#036;over = substr(&#036;orderBy, <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />;


		&#036;newSql = substr(&#036;sql, 0, strripos(&#036;sql, 'ORDER BY'));


		//echo &#036;newSql;


		&#036;from = strrpos(&#036;sql, 'FROM');


		//&#036;first=substr(&#036;newSql,0);


		&#036;newSql = substr(&#036;newSql, 0, &#036;from) . &quot; , ROW_NUMBER() OVER (ORDER BY &#036;over) as yiinumber &quot; . substr(&#036;newSql, &#036;from);


		//echo &#036;newSql = substr_replace(&#036;newSql,&quot; , ROW_NUMBER() OVER (ORDER BY &#036;over) as yiinumber &quot;,substr(&#036;newSql, 0, &#036;from),0);





		&#036;sql = &quot;SELECT * FROM (


				&#036;newSql ) AS __innertable__ WHERE yiinumber &gt; {&#036;offset}&quot;;


		//echo &#036;qsql;


	}





    return &#036;sql;


}

it work when click sort column first but it’s not work when click pagination first

Here is display error when click pagination first when the page load success.

the code in CMssqlCommandBuilder.php I get from the link above which I try it the code is below.

<?php

/**

  • CMsCommandBuilder class file.

*/

/**

  • CMssqlCommandBuilder provides basic methods to create query commands for tables for Mssql Servers.

*/

class CMssqlCommandBuilder extends CDbCommandBuilder

{

    /**


     * Creates a COUNT(*) command for a single table.


     * Override parent implementation to remove the order clause of criteria if it exists


     * @param CDbTableSchema &#036;table the table metadata


     * @param CDbCriteria &#036;criteria the query criteria


     * @param string &#036;alias the alias name of the primary table. Defaults to 't'.


     * @return CDbCommand query command.


     */


    public function createCountCommand(&#036;table,&#036;criteria,&#036;alias='t')


    {


            &#036;criteria-&gt;order='';


            return parent::createCountCommand(&#036;table, &#036;criteria,&#036;alias);


    }





    /**


     * Creates a SELECT command for a single table.


     * Override parent implementation to check if an orderby clause if specified when querying with an offset


     * @param CDbTableSchema &#036;table the table metadata


     * @param CDbCriteria &#036;criteria the query criteria


     * @param string &#036;alias the alias name of the primary table. Defaults to 't'.


     * @return CDbCommand query command.


     */


    public function createFindCommand(&#036;table,&#036;criteria,&#036;alias='t')


    {


            &#036;criteria=&#036;this-&gt;checkCriteria(&#036;table,&#036;criteria);


            return parent::createFindCommand(&#036;table,&#036;criteria,&#036;alias);





    }





    /**


     * Creates an UPDATE command.


     * Override parent implementation because mssql don't want to update an identity column


     * @param CDbTableSchema &#036;table the table metadata


     * @param array &#036;data list of columns to be updated (name=&gt;value)


     * @param CDbCriteria &#036;criteria the query criteria


     * @return CDbCommand update command.


     */


    public function createUpdateCommand(&#036;table,&#036;data,&#036;criteria)


    {


            &#036;criteria=&#036;this-&gt;checkCriteria(&#036;table,&#036;criteria);


            &#036;fields=array();


            &#036;values=array();


            &#036;bindByPosition=isset(&#036;criteria-&gt;params[0]);


            &#036;i=0;


            foreach(&#036;data as &#036;name=&gt;&#036;value)


            {


                    if((&#036;column=&#036;table-&gt;getColumn(&#036;name))&#33;==null)


                    {


                            if (&#036;table-&gt;sequenceName &#33;== null &amp;&amp; &#036;column-&gt;isPrimaryKey === true) continue;


                            if (&#036;column-&gt;dbType === 'timestamp') continue;


                            if(&#036;value instanceof CDbExpression)


                                    &#036;fields[]=&#036;column-&gt;rawName.'='.&#036;value-&gt;expression;


                            else if(&#036;bindByPosition)


                            {


                                    &#036;fields[]=&#036;column-&gt;rawName.'=?';


                                    &#036;values[]=&#036;column-&gt;typecast(&#036;value);


                            }


                            else


                            {


                                    &#036;fields[]=&#036;column-&gt;rawName.'='.self::PARAM_PREFIX.&#036;i;


                                    &#036;values[self::PARAM_PREFIX.&#036;i]=&#036;column-&gt;typecast(&#036;value);


                                    &#036;i++;


                            }


                    }


            }


            if(&#036;fields===array())


                    throw new CDbException(Yii::t('yii','No columns are being updated for table &quot;{table}&quot;.',


                            array('{table}'=&gt;&#036;table-&gt;name)));


            &#036;sql=&quot;UPDATE {&#036;table-&gt;rawName} SET &quot;.implode(', ',&#036;fields);


            &#036;sql=&#036;this-&gt;applyJoin(&#036;sql,&#036;criteria-&gt;join);


            &#036;sql=&#036;this-&gt;applyCondition(&#036;sql,&#036;criteria-&gt;condition);


            &#036;sql=&#036;this-&gt;applyOrder(&#036;sql,&#036;criteria-&gt;order);


            &#036;sql=&#036;this-&gt;applyLimit(&#036;sql,&#036;criteria-&gt;limit,&#036;criteria-&gt;offset);





            &#036;command=&#036;this-&gt;getDbConnection()-&gt;createCommand(&#036;sql);


            &#036;this-&gt;bindValues(&#036;command,array_merge(&#036;values,&#036;criteria-&gt;params));





            return &#036;command;


    }





    /**


     * Creates a DELETE command.


     * Override parent implementation to check if an orderby clause if specified when querying with an offset


     * @param CDbTableSchema &#036;table the table metadata


     * @param CDbCriteria &#036;criteria the query criteria


     * @return CDbCommand delete command.


     */


    public function createDeleteCommand(&#036;table,&#036;criteria)


    {


            &#036;criteria=&#036;this-&gt;checkCriteria(&#036;table, &#036;criteria);


            return parent::createDeleteCommand(&#036;table, &#036;criteria);


    }





    /**


     * Creates an UPDATE command that increments/decrements certain columns.


     * Override parent implementation to check if an orderby clause if specified when querying with an offset


     * @param CDbTableSchema &#036;table the table metadata


     * @param CDbCriteria &#036;counters the query criteria


     * @param array &#036;criteria counters to be updated (counter increments/decrements indexed by column names.)


     * @return CDbCommand the created command


     * @throws CException if no counter is specified


     */


    public function createUpdateCounterCommand(&#036;table,&#036;counters,&#036;criteria)


    {


            &#036;criteria=&#036;this-&gt;checkCriteria(&#036;table, &#036;criteria);


            return parent::createUpdateCounterCommand(&#036;table, &#036;counters, &#036;criteria);


    }





    /**


     * This is a port from Prado Framework.


     *


     * Overrides parent implementation. Alters the sql to apply &#036;limit and &#036;offset.


     * The idea for limit with offset is done by modifying the sql on the fly


     * with numerous assumptions on the structure of the sql string.


     * The modification is done with reference to the notes from


     * http://troels.arvin.dk/db/rdbms/#select-limit-offset


     *


     * &lt;code&gt;


     * SELECT * FROM (


     *  SELECT TOP n * FROM (


     *    SELECT TOP z columns      -- (z=n+skip)


     *    FROM tablename


     *    ORDER BY key ASC


     *  ) AS FOO ORDER BY key DESC -- ('FOO' may be anything)


     * ) AS BAR ORDER BY key ASC    -- ('BAR' may be anything)


     * &lt;/code&gt;


     *


     * &lt;b&gt;Regular expressions are used to alter the SQL query. The resulting SQL query


     * may be malformed for complex queries.&lt;/b&gt; The following restrictions apply


     *


     * &lt;ul&gt;


     *   &lt;li&gt;


     * In particular, &lt;b&gt;commas&lt;/b&gt; should &lt;b&gt;NOT&lt;/b&gt;


     * be used as part of the ordering expression or identifier. Commas must only be


     * used for separating the ordering clauses.


     *  &lt;/li&gt;


     *  &lt;li&gt;


     * In the ORDER BY clause, the column name should NOT be be qualified


     * with a table name or view name. Alias the column names or use column index.


     * &lt;/li&gt;


     * &lt;li&gt;


     * No clauses should follow the ORDER BY clause, e.g. no COMPUTE or FOR clauses.


     * &lt;/li&gt;


     *


     * @param string &#036;sql SQL query string.


     * @param integer &#036;limit maximum number of rows, -1 to ignore limit.


     * @param integer &#036;offset row offset, -1 to ignore offset.


     * @return string SQL with limit and offset.


     *


     * @author Wei Zhuo &lt;weizhuo[at]gmail[dot]com&gt;


     */


   /* public function applyLimit(&#036;sql, &#036;limit, &#036;offset)


    {


            &#036;limit = &#036;limit&#33;==null ? intval(&#036;limit) : -1;


            &#036;offset = &#036;offset&#33;==null ? intval(&#036;offset) : -1;


            if (&#036;limit &gt; 0 &amp;&amp; &#036;offset &lt;= 0) //just limit


                    &#036;sql = preg_replace('/^([&#092;s(])*SELECT( DISTINCT)?(?&#33;&#092;s*TOP&#092;s*&#092;()/i',&quot;&#092;&#092;1SELECT&#092;&#092;2 TOP &#036;limit&quot;, &#036;sql);


            else if(&#036;limit &gt; 0 &amp;&amp; &#036;offset &gt; 0)


                    &#036;sql = &#036;this-&gt;rewriteLimitOffsetSql(&#036;sql, &#036;limit,&#036;offset);


            return &#036;sql;


    } */


    public function applyLimit(&#036;sql, &#036;limit, &#036;offset)


{


	&#036;limit = &#036;limit&#33;==null ? intval(&#036;limit) : -1;


	&#036;offset = &#036;offset&#33;==null ? intval(&#036;offset) : -1;


	if (&#036;limit &gt; 0 &amp;&amp; &#036;offset &lt;= 0) //just limit


		&#036;sql = preg_replace('/^([&#092;s(])*SELECT( DISTINCT)?(?&#33;&#092;s*TOP&#092;s*&#092;()/i',&quot;&#092;&#092;1SELECT&#092;&#092;2 TOP &#036;limit&quot;, &#036;sql);


	


	else if(&#036;limit &gt; 0 &amp;&amp; &#036;offset &gt; 0)


	{


		&#036;sql = preg_replace(


        '/^SELECT&#092;s+(DISTINCT&#092;s)?/i',


        'SELECT &#036;1TOP ' . (&#036;limit+&#036;offset) . ' ',


        &#036;sql


        );





		&#036;orderBy = stristr(&#036;sql, 'ORDER BY');


		&#036;over = substr(&#036;orderBy, <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />;


		&#036;newSql = substr(&#036;sql, 0, strripos(&#036;sql, 'ORDER BY'));


		//echo &#036;newSql;


		&#036;from = strrpos(&#036;sql, 'FROM');


		//&#036;first=substr(&#036;newSql,0);


		&#036;newSql = substr(&#036;newSql, 0, &#036;from) . &quot; , ROW_NUMBER() OVER (ORDER BY &#036;over) as yiinumber &quot; . substr(&#036;newSql, &#036;from);


		//echo &#036;newSql = substr_replace(&#036;newSql,&quot; , ROW_NUMBER() OVER (ORDER BY &#036;over) as yiinumber &quot;,substr(&#036;newSql, 0, &#036;from),0);





		&#036;sql = &quot;SELECT * FROM (


				&#036;newSql ) AS __innertable__ WHERE yiinumber &gt; {&#036;offset}&quot;;


		//echo &#036;qsql;


	}





    return &#036;sql;


}





    /**


     * Rewrite sql to apply &#036;limit &gt; and &#036;offset &gt; 0 for MSSQL database.


     * See http://troels.arvin.dk/db/rdbms/#select-limit-offset


     * @param string &#036;sql sql query


     * @param integer &#036;limit &#036;limit &gt; 0


     * @param integer &#036;offset &#036;offset &gt; 0


     * @return sql modified sql query applied with limit and offset.


     *


     * @author Wei Zhuo &lt;weizhuo[at]gmail[dot]com&gt;


     */


    protected function rewriteLimitOffsetSql(&#036;sql, &#036;limit, &#036;offset)


    {


        


            &#036;fetch = &#036;limit+&#036;offset;


            &#036;sql = preg_replace('/^([&#092;s(])*SELECT( DISTINCT)?(?&#33;&#092;s*TOP&#092;s*&#092;()/i',&quot;&#092;&#092;1SELECT&#092;&#092;2 TOP &#036;fetch&quot;, &#036;sql);


            &#036;ordering = &#036;this-&gt;findOrdering(&#036;sql);


            &#036;orginalOrdering = &#036;this-&gt;joinOrdering(&#036;ordering, '[__outer__]');


            &#036;reverseOrdering = &#036;this-&gt;joinOrdering(&#036;this-&gt;reverseDirection(&#036;ordering), '[__inner__]');


            &#036;sql = &quot;SELECT * FROM (SELECT TOP {&#036;limit} * FROM (&#036;sql) as [__inner__] {&#036;reverseOrdering}) as [__outer__] {&#036;orginalOrdering}&quot;;


            return &#036;sql;


    }





    /**


     * Base on simplified syntax http://msdn2.microsoft.com/en-us/library/aa259187(SQL.80).aspx


     *


     * @param string &#036;sql &#036;sql


     * @return array ordering expression as key and ordering direction as value


     *


     * @author Wei Zhuo &lt;weizhuo[at]gmail[dot]com&gt;


     */


    protected function findOrdering(&#036;sql)


    {


            if(&#33;preg_match('/ORDER BY/i', &#036;sql))


                    return array();


            &#036;matches=array();


            &#036;ordering=array();


            preg_match_all('/(ORDER BY)[&#092;s&quot;&#092;[](.*)(ASC|DESC)?(?:[&#092;s&quot;&#092;[]|&#036;|COMPUTE|FOR)/i', &#036;sql, &#036;matches);


            if(count(&#036;matches)&gt;1 &amp;&amp; count(&#036;matches[2]) &gt; 0)


            {


                    &#036;parts = explode(',', &#036;matches[2][0]);


                    foreach(&#036;parts as &#036;part)


                    {


                            &#036;subs=array();


                            if(preg_match_all('/(.*)[&#092;s&quot;&#092;]](ASC|DESC)&#036;/i', trim(&#036;part), &#036;subs))


                            {


                                    if(count(&#036;subs) &gt; 1 &amp;&amp; count(&#036;subs[2]) &gt; 0)


                                    {


                                            &#036;name='';


                                            foreach(explode('.', &#036;subs[1][0]) as &#036;p)


                                            {


                                                    if(&#036;name&#33;=='')


                                                            &#036;name.='.';


                                                    &#036;name.='[' . trim(&#036;p, '[]') . ']';


                                            }


                                            &#036;ordering[&#036;name] = &#036;subs[2][0];


                                    }


                                    //else what?


                            }


                            else


                                    &#036;ordering[trim(&#036;part)] = 'ASC';


                    }


            }





            // replacing column names with their alias names


            foreach(&#036;ordering as &#036;name =&gt; &#036;direction)


            {


                    &#036;matches = array();


                    &#036;pattern = '/&#092;s+'.str_replace(array('[',']'), array('&#092;[','&#092;]'), &#036;name).'&#092;s+AS&#092;s+(&#092;[[^&#092;]]+&#092;])/i';


                    preg_match(&#036;pattern, &#036;sql, &#036;matches);


                    if(isset(&#036;matches[1]))


                    {


                            &#036;ordering[&#036;matches[1]] = &#036;ordering[&#036;name];


                            unset(&#036;ordering[&#036;name]);


                    }


            }





            return &#036;ordering;


    }





    /**


     * @param array &#036;orders ordering obtained from findOrdering()


     * @param string &#036;newPrefix new table prefix to the ordering columns


     * @return string concat the orderings


     *


     * @author Wei Zhuo &lt;weizhuo[at]gmail[dot]com&gt;


     */


    protected function joinOrdering(&#036;orders, &#036;newPrefix)


    {


            if(count(&#036;orders)&gt;0)


            {


                    &#036;str=array();


                    foreach(&#036;orders as &#036;column =&gt; &#036;direction)


                            &#036;str[] = &#036;column.' '.&#036;direction;


                    &#036;orderBy = 'ORDER BY '.implode(', ', &#036;str);


                    return preg_replace('/&#092;s+&#092;[[^&#092;]]+&#092;]&#092;.(&#092;[[^&#092;]]+&#092;])/i', ' '.&#036;newPrefix.'.&#092;1', &#036;orderBy);


            }


    }





    /**


     * @param array &#036;orders original ordering


     * @return array ordering with reversed direction.


     *


     * @author Wei Zhuo &lt;weizhuo[at]gmail[dot]com&gt;


     */


    protected function reverseDirection(&#036;orders)


    {


            foreach(&#036;orders as &#036;column =&gt; &#036;direction)


                    &#036;orders[&#036;column] = strtolower(trim(&#036;direction))==='desc' ? 'ASC' : 'DESC';


            return &#036;orders;


    }








    /**


     * Checks if the criteria has an order by clause when using offset/limit.


     * Override parent implementation to check if an orderby clause if specified when querying with an offset


     * If not, order it by pk.


     * @param CMssqlTableSchema &#036;table table schema


     * @param CDbCriteria &#036;criteria criteria


     * @return CDbCrireria the modified criteria


     */


    protected function checkCriteria(&#036;table, &#036;criteria)


    {


            if (&#036;criteria-&gt;offset &gt; 0 &amp;&amp; &#036;criteria-&gt;order==='')


            {


                    &#036;criteria-&gt;order=is_array(&#036;table-&gt;primaryKey)?implode(',',&#036;table-&gt;primaryKey):&#036;table-&gt;primaryKey;


            }


            return &#036;criteria;


    }





    /**


     * Generates the expression for selecting rows with specified composite key values.


     * @param CDbTableSchema &#036;table the table schema


     * @param array &#036;values list of primary key values to be selected within


     * @param string &#036;prefix column prefix (ended with dot)


     * @return string the expression for selection


     * @since 1.0.4


     */


    protected function createCompositeInCondition(&#036;table,&#036;values,&#036;prefix)


    {


            &#036;vs=array();


            foreach(&#036;values as &#036;value)


            {


                    &#036;c=array();


                    foreach(&#036;value as &#036;k=&gt;&#036;v)


                            &#036;c[]=&#036;prefix.&#036;table-&gt;columns[&#036;k]-&gt;rawName.'='.&#036;v;


                    &#036;vs[]='('.implode(' AND ',&#036;c).')';


            }


            return '('.implode(' OR ',&#036;vs).')';


    }

}

and I have error when I filter by datetime.

I don’t know if this solution is up to date or not,but it works for me.

1.in mssqlcommandbuilder use the patch from http://code.google.com/p/yii/issues/detail?id=2923

2.in cpagination ,the function applyLimit should look like this(read more about this at https://code.google.com/p/yii/issues/detail?id=3211)




         /**

	 * Applies LIMIT and OFFSET to the specified query criteria.

	 * @param CDbCriteria $criteria the query criteria that should be applied with the limit

	 */

	public function applyLimit($criteria)

	{

	    $limit=$this->getLimit();

	    $offset=$this->getOffset();

	    $itemcount=$this->getItemCount();


	    if($itemcount!=0 && ($limit+$offset)>$itemcount) {

	        $limit=max(0,$itemcount-$offset);

	    }

		$criteria->limit=$limit;

		$criteria->offset=$offset;

	}



3.set default order for csort




$sort->defaultOrder = array('field_to_sort' => CSort::SORT_ASC);



Thank a lot Mr. Nakarin,

I try it but it still error.

I don’t find out the source of best solution with mssql on cgridview with relation table.

Now I use a trick. I take criteria->order

$criteria->order = "field_to_criteria sort"

begin declare $var = new CSort();

It does work but can not take the field_to_criteria to be sorting column.

in model




<?php


/**

 * This is the model class for table "tblObjective".

 *

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

 * @property integer $ObjectiveId

 * @property string $ObjectNumber

 * @property string $Description

 * @property integer $DivisionId

 */

class Objective extends CActiveRecord {


    /**

     * @return string the associated database table name

     */

    public function tableName() {

        return 'tblObjective';

    }


    /**

     * @return array validation rules for model attributes.

     */

    public function rules() {

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

        // will receive user inputs.

        return array(

            array('DivisionId', 'numerical', 'integerOnly' => true),

            array('ObjectNumber', 'length', 'max' => 20),

            array('Description', 'safe'),

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

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

            array('ObjectiveId, ObjectNumber, Description, DivisionId, division', 'safe', 'on' => 'search'),

        );

    }


    /**

     * @return array relational rules.

     */

    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(

            'division' => array(self::BELONGS_TO, 'Division', 'DivisionId'),

        );

    }


    /**

     * @return array customized attribute labels (name=>label)

     */

    public function attributeLabels() {

        return array(

            'ObjectiveId' => 'Objective',

            'ObjectNumber' => 'Object Number',

            'Description' => 'Description',

            'DivisionId' => 'Division',

        );

    }


    /**

     * Retrieves a list of models based on the current search/filter conditions.

     *

     * Typical usecase:

     * - Initialize the model fields with values from filter form.

     * - Execute this method to get CActiveDataProvider instance which will filter

     * models according to data in model fields.

     * - Pass data provider to CGridView, CListView or any similar widget.

     *

     * @return CActiveDataProvider the data provider that can return the models

     * based on the search/filter conditions.

     */

    public function search() {

        // @todo Please modify the following code to remove attributes that should not be searched.


        $criteria = new CDbCriteria;


        $criteria->with = array('division' => array('alias' => 'x'));

        $criteria->together = true;

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

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

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

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


        $criteria->compare('x.DivisionNumber', $this->division, true);

        $criteria->compare('x.Description', $this->division, true, "OR");




        $sort = new CSort;

        $sort->attributes = array(

            'division' => array(

                'asc' => 'x.DivisionNumber',

                'desc' => 'x.DivisionNumber DESC',

            ),

            '*',

        );


        $sort->defaultOrder = array('ObjectiveId' => CSort::SORT_ASC,);


        return new CActiveDataProvider($this, array(

            'sort' => $sort,

            'criteria' => $criteria,

        ));

    }


    /**

     * Returns the static model of the specified AR class.

     * Please note that you should have this exact method in all your CActiveRecord descendants!

     * @param string $className active record class name.

     * @return Objective the static model class

     */

    public static function model($className = __CLASS__) {

        return parent::model($className);

    }


}




in view




<?php

$this->breadcrumbs = array(

    'Objectives' => array('index'),

    'Manage',

);


$this->menu = array(

    array('label' => 'List Objective', 'url' => array('index')),

    array('label' => 'Create Objective', 'url' => array('create')),

);


Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

$('.search-form').toggle();

return false;

});

$('.search-form form').submit(function(){

$.fn.yiiGridView.update('objective-grid', {

data: $(this).serialize()

});

return false;

});

");


?>


<h1>Manage Objectives</h1>


<p>

    You may optionally enter a comparison operator (<b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>, <b>

        &lt;&gt;</b>

    or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.

</p>


<?php echo CHtml::link('Advanced Search', '#', array('class' => 'search-button btn')); ?>

<div class="search-form" style="display:none">

    <?php

    $this->renderPartial('_search', array(

        'model' => $model,

    ));

    ?>

</div><!-- search-form -->


<?php

$this->widget('bootstrap.widgets.TbGridView', array(

    'id' => 'objective-grid',

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

    'filter' => $model,

    'columns' => array(

        'ObjectiveId',

        'ObjectNumber',

        'Description',

//        'DivisionId',

        array(

            'name' => 'division',

            'value' => '$data->division->DivisionNumber." ".$data->division->Description',

            'htmlOptions' => array('width' => '200'),

        ),

        array(

            'class' => 'bootstrap.widgets.TbButtonColumn',

            'htmlOptions' => array('width' => '100'),

        ),

    ),

));

?>




Check how sorting works with my RelatedSearchBehavior extension (my fix for pagination is already mentionned, see also http://www.yiiframework.com/forum/index.php/topic/40054-mssql-sorting-problem/page__view__findpost__p__193772 ).