ordenar por un campo que no está en el modelo

Hola a todos,

Estoy haciendo un sistemita de tickets para aprender a usar el yii (de paso lo necesito en un cliente!!).

Tengo un gridview con los tickets, todo bien hasta ahí, se me ocurrió que sería interesante que aparezcan diferenciadas las filas con comentarios que el usuario activo no vio todavía, eso lo voy a dejar para otra iteración porque se me hace un poco difícil, lo que sí tengo ganas de hacer es mostrar una columna con la fecha del último comentario y su autor, hasta ahí bien, agregué un par de métodos al modelo ticket y todo aparece bien en el grid.

Lo que me gustaría hacer y para eso les pido una mano, es poder ordenar por esta columna, no solo es importante para este proyecto, sino que me parece un conocimiento interesante para tener :)

Si alguien puede darme un poco de dirección, ni que hablar de un poco de código!, si es así avisen y postéo el código que tengo hasta ahora (si hace falta)

Muchas gracias

Juan

Hola Juan, es muy sencillo en realidad lograr lo que tu buscas, lo malo es que no viene casi nada de documentación al respecto en el sitio de Yii.

Te dejo un ejemplo comentado:







class File extends CActiveRecord {


    public $category; // OJO: esta variable es el campo que deseamos utilizar en la ordenación y lo tomamos de otra tabla.


   //...


    public function rules() {

        return array(

            array('node_id, name', 'required'),

            array('node_id', 'length', 'max' => 10),

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

            array('description', 'length', 'max' => 1000),

            array('path', 'file', 'types' => 'jpg, png, gif, pdf, doc, docx, pps, ppsx, ppt, pptx, xls, xlsx'),

            array('node_id, name, description, path, category', 'safe', 'on' => 'search'), // Hay que poner nuestra variable category como safe.

        );

    }


    public function relations() {

        return array(

            'node' => array(self::BELONGS_TO, 'Node', 'node_id', 'with' => array('category')), // Nuestra relación con el otro modelo tambien debe de estar en nuestro codigo.

        );

    }


    public function behaviors() {

        return array('CAdvancedArBehavior',

            array('class' => 'ext.CAdvancedArBehavior')

        );

    }


    public function attributeLabels() {

        return array(

            'node_id' => Yii::t('app', 'Node'),

            'name' => Yii::t('app', 'Name'),

            'description' => Yii::t('app', 'Description'),

            'path' => Yii::t('app', 'Path'),

            'category' => Yii::t('app', 'Category'), // Aqui puedes cambiar el nombre de tu campo en el label de tu grid.

        );

    }

//....




/**

* Aqui viene la parte importante

*/


    public function search() {

        $criteria = new CDbCriteria;


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


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


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


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


        $criteria->compare('category.name', $this->category, true);  //Agregamos a $criteria nuestro nuevo campo, esto nos sirve para realizar búsquedas dentro del CGridView


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




        //Creamos un nuevo sort y añadimos nuestro campo relacionado


        $sort = new CSort();

        $sort->attributes = array(

                        'node_id',

                        'name',

                        'description',

                        'path',

                        'category' => array(   //<---------------- Aqui agregamos el campo relacionado

                            'asc'=>'category.name',

                            'desc'=>'category.name DESC',

                        ),

                );


        return new CActiveDataProvider(get_class($this), array(

            'criteria' => $criteria,

	    'sort' => $sort, // Pasamos la variable sort a nuestro [size=3]CActiveDataProvider[/size]

        ));

    }


}







Ahora solamente en nuestro CGridView tenemos que poner lo siguiente:








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

                'id'=>'file-grid',

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

                'filter'=>$model,

                'columns'=>array(

                		'node_id',

                    array('name'=>'category',

                            'value' => '$data->node->category->name'),

		'name',

		'description',

		'path',

                                array(

                                        'class'=>'CButtonColumn',

                                ),

                        ),

                )); ?>




Y listo, ya podemos hacer un sort con nuestro campo relacionado.

Espero te sirva, cualquier duda me avisas!

Saludos!

No había visto tu respuesta, ahora mismo la leo, pero desde ya MUCHAS gracias

Juan

Nancoder, gracias por tu código, hay algo que no se como hacer, en realidad, el campo por el que quiero buscar no forma parte del query, es un método de mi clase ($data->ultimoComentario->fecha). Lo que me gustaría es que forme parte del query y ahí si usar tu código.

Acá te dejo un query que representa mas o menos lo que quiero:


select t.*, e.texto as estado, p.texto as prioridad,

    (select fecha from comentario c where c.ticket_id = t.id order by fecha desc  limit 1) as ultimoComentarioFecha,

    (select u.username 

        from comentario c 

            inner join usuario u on u.id = c.usuario_id

            where c.ticket_id = t.id order by fecha desc  limit 1

    ) as ultimoComentarioPor

    from ticket t

        inner join estado e on e.id = t.estado_id

        inner join prioridad p on p.id = t.prioridad_id

    

Me gustaría lograr lo mismo pero sin los subselect, con inner joins y limit 1, pero eso puede esperar :) el paso ahora es lograr que el query tenga el campo por el que quiero ordenar

Alguna idea???

últimos avances :)

Agregué una relación en la clase ticket de esta manera:


  'ultimoComentario' => array(self::HAS_ONE, 'Comentario', 'id',

                    'with' => 'usuario',

                    'order' => 'fecha DESC'),

            ),

También un sort en el método search de la clase ticket:


    $sort = new CSort();

    $sort->attributes = array(

        ....

        'ultimoComentarioFecha' => array(

            'asc' => 'ultimoComentario.fecha',

            'desc' => 'ultimoComentario.fecha DESC',

        ),

        'ultimoComentarioPor' => array(

            'asc' => 'ultimoComentario.usuario.username',

            'desc' => 'ultimoComentario.usuario.username DESC',

        ),);

Por último, en las opciones de la llamada al CGridView agregué simplemente:


            array(

                'name' => 'ultimoComentarioFecha',

                'value' => '$data->ultimoComentario->fecha',

                'filter' => '',

                'cssClassExpression' => '$data->leido ? null:"leido"',

//                'htmlOptions' => array('width' => '70px'),

            ),

            array(

                'name' => 'ultimoComentarioPor',

                'value' => '$data->ultimoComentario->usuario->username',

                'filter' => '',

                'cssClassExpression' => '$data->leido ? null:"leido"',

                'htmlOptions' => array('width' => '50px'),

            ),

Ya está todo muuuucho mejor que antes, lo único que no funciona es el orden por "ultimoComentarioPor", me dice:


Column not found: 1054 Unknown column 'ultimoComentario.usuario.username' in 'order clause'</p>



A pesar que tengo un ‘with’ con usuario en la relación.

Alguna idea???

>>"ultimoComentarioPor", me dice:

>>Column not found: 1054 Unknown column ‘ultimoComentario.usuario.username’ in ‘order clause’</p>

>>A pesar que tengo un ‘with’ con usuario en la relación.

>>Alguna idea???

mi error, por supuesto, era usuario.username y no ultimoComentario.usuario.username

todo perfecto, que bien el yii!! lo amo jaja

Que bueno que te haya servido Juan!

Saludos!

Bastante útil el aporte nancoder, deberías agregarlo a la wiki. :rolleyes: