Problema con filtros

Hola a todos les cuento un problema que me ha surgido con filtros en un CGridView, lo que pasa es que poseo tres tablas, una llamada tiene_tratamiento que se relaciona con pieza_paciente y esta se relaciona con pieza, lo que hice ha sido mostrar en el CGridView el número de pieza que ha sido tratada, cosa que logré hacer, pero el problema me ha surgido a la hora de intentar filtrar ya que no pasa nada y no he podido solucionarlo ya que ha diferencia de otras veces debo recorrer más tablas para hacerlo.

Los datos en el CGridView los cargo de la siguiente manera.


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

    'id' => 'PiezasAfectadas',

    'dataProvider' => $modelTieneTratamiento->searchByTratamientoRealizado($model->id_realizado),

    'filter' => $modelTieneTratamiento,

    'columns' => array(

        'comentario',

        array(

                        'name'=>'pieza',

                        'value'=>'$data->idPiezaPaciente->idPieza->nombre_pieza', 

                        'type'=>'text',

                ),

    ),

));

Espero que alguien pueda ayudarme ya que llevo un rato pegado con esto, saludos y gracias desde ya.

Esto lo he conseguido siguiendo algún post que no encuentro…

Pero basta con buscar en google "filter related yii" y te sale un montón de ayuda.

si estás usando yii 1 estos tienen buena pinta: http://www.yiiframework.com/forum/index.php/topic/16095-cgridview-filtering-related-tables/

y http://www.codeinphp.com/frameworks/yii/using-filters-yii-cgridview-relations/

si estás usando yii 2: este otro:

http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/

Gracias por responder, pero no lo he podido solucionar, lo que pasa es que si puedo crear filtros cuando las tablas se relacionan directamente, pero lo que me complica en este caso es que debo filtrar un atributo que no está directamente relacionado con la tabla en cuestión (tiene_tratamiento), ya que no se bien si debo modificar el model en este caso, ni como debería hacerlo.

En tu model principal donde esta lo que quieres mostrar, debes de indicar en RULES lo que deseas buscar, antes debes de indicar la propiedad, ¿como se indica?, dentro de tu model, dentro de clase, pon las propiedades de las tablas que quieras relacionar, ejemplo tengo mi tabla persona, y mi tabla tratamiento, la que voy a relacionar es la de tratamiento entonces quiero saber que medicamento le corresponde a una persona para eso se pone así.




class Persona extends AuditColumnRecord

{

  public $tratamiento;


  //en rules debes de indicar que vas a filtrar por tratamiento, ¿donde?, busca esta linea y agrega tu propiedad.

  array('nombre, apellido, ciudad, tratamiento', 'safe', 'on'=>'search'),


  //con eso ya podemos indicarle a yii que también filtre por ese campo, pero ahi no termina

}



Ahora tienes dos opciones, para mostrar ese dato en tu grid, ¿cuales?, la que pones usando las relaciones de tu modelo en el grid




array(

  'name'=>'tratamiento', // esto ya lo puedo usar asi, porque indica la propiedad en el model

  'value'=>$model->tratamiento->nombre,

)



esa es una opción o usar el $data como lo usas, o la otra hagas tu SQL con todas las relaciones que creas convenientes y sopas!!!, las muestra en el grid, ¿como las hago?

en tu método search dentro de tu model principal, en este ejemplo persona, indico mi sql, antes como hago un sql unión?




select p.nombre, p.apellido, t.nombre from persona p inner join tratamiento t on t.id_pk = p.id_pk_relacion



con eso ya sacas la relación pero ahora viene lo bueno, chun chun chunnnn!!!!




$criteria->sql = "select p.nombre, p.apellido, t.nombre  from Persona p"

$criteria->join = "inner join tratamiento t t.id_pk on = p.id_pk_relacion"


//recuerda que las llamadas a compare $criteria->compare pertenen a los where entonces ahí pondras


$criteria->compare('p.nombre',$this->nombre);

$criteria->compare('p.apellido',$this->apellido);

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


//recuerda que si en el compare le pones al final ,true osea $criteria->compare('t.nombre',$this->tratamiento,true); 

//eso te indica que será una búsqueda por LIKE, sino es una busqueda en especifico.



y listo !!!

Gracias por responder! he tratado de llevarlo a mi código pero no me resultó xD lo que me complica mucho es que cargo el modelo de la tabla tiene_tratamiento y esta se relaciona con pieza_paciente, no tengo problemas para mostrar y filtrar los datos de pieza_paciente en el modelo de tiene_tratamiento, pero a la hora de sacar datos de la tabla Pieza, que no se relaciona directamente con tiene_tratamiento no me funcionó, trate de utilizar tus indicaciones pero no lo conseguí.

Gracias de todas formas, adjunto mi código por si acaso.

PD: Aunque no es algo tan grave en mi proyecto me gustaría saber como hacerlo (soy muy novato en esto de yii).

El encabezado y las rules


class TieneTratamiento extends CActiveRecord

{

        public $pieza;

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tiene_tratamiento';

	}


	/**

	 * @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('id_realizado, id_pieza_paciente, comentario', 'required'),

			array('id_realizado, id_pieza_paciente', 'numerical', 'integerOnly'=>true),

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

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

			array('id_realizado, id_tiene_tratamiento, id_pieza_paciente, comentario, pieza', 'safe', 'on'=>'search'),

		);

	}

El método search


public function searchByTratamientoRealizado($id)

	{

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


		$criteria=new CDbCriteria;

                $criteria->compare('t.id_realizado',$id);

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

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

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

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

		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

Las relaciones


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(

			'idRealizado' => array(self::BELONGS_TO, 'TratamientoRealizado', 'id_realizado'),

			'idPiezaPaciente' => array(self::BELONGS_TO, 'PiezaPaciente', 'id_pieza_paciente'),

		);

	}

El mantenedor


$pieza = new Pieza();

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

    'id' => 'PiezasAfectadas',

    'dataProvider' => $modelTieneTratamiento->searchByTratamientoRealizado($model->id_realizado),

    'filter' => $modelTieneTratamiento,

    'columns' => array(

        'comentario',

        array(

                        'name'=>'pieza',

                        'value'=>'$data->idPiezaPaciente->idPieza->nombre_pieza', 

                        'type'=>'text',

                ),

    ),

));

El action que carga la view


public function actionView($id) {

        $modelTieneTratamiento = new TieneTratamiento('search');

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

            $modelTieneTratamiento->attributes = $_GET ['TieneTratamiento'];

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

            'model' => $this->loadModel($id),

            'modelTieneTratamiento' => $modelTieneTratamiento,

        ));

    }

Te explico.

Tu puedes usar campos personalizados en los modelos, para ello debes definir los metodos set y get en los cuales asignas y obtienes el valor del campo personalizado respectivamente. En tu caso el campo personalizado se llama pieza que es el nombre de la pieza relacionada, entonces debes tener lo siguiente.


class TieneTratamiento extends CActiveRecord

{

        private $_pieza;//<------El campo personalizado

        ...

        ...

         public function rules()

        {

                return array(

                       ...

                       ...

                        array('..., pieza', 'safe', 'on'=>'search'),//<-----Esto para poder usarlo como filtro

                );

        }

        ...

        ...

        public function search() {		

		$criteria = new CDbCriteria ();

                $criteria->with=array("idPiezaPaciente.idPieza");//<--------Agregas la relación

		$criteria->compare ( 'idPieza.nombre', $this->pieza, true );//<---------Aqui haces el filtro			

                ...

                ...		

		$sort=new CSort();

		$sort->attributes=array(

			'pieza'=>array(//<--------------Creas un sort para poder utilizar el campo personalizado para ordenar

					'asc'=>'idPieza.nombre ASC',

					'desc'=>'idPieza.nombre DESC',

			),

			'*',

		);		

		return new CActiveDataProvider ( $this, array (

				'criteria' => $criteria,

				'sort'=>$sort,//<-----Agregas el sort

		) );

	}

        ...

        ...

        public function getPieza(){//<-------La funcion get

            if(!isset($this->_pieza)){

                if(isset($this->idPiezaPaciente)){

                    if(isset($this->idPiezaPaciente->idPieza)){

                        $this->pieza=$this->idPiezaPaciente->idPieza->nombre_pieza;

                    }

                }

            }

            return $this->_pieza

        }

        public function setPieza($pieza){//<----------La funcion set

            $this->pieza=$pieza;        

        }

        ...

        ...

}

Y para agregarlo al gridview lo haces como todos los demas campos


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

    'id' => 'PiezasAfectadas',

    'dataProvider' => $modelTieneTratamiento->search(),//<----Llamas a la función search

    'filter' => $modelTieneTratamiento,

    'columns' => array(

        ...

        ...

        array(

           'name'=>'pieza',                        

        ),

        ...

        ...

    ),

));

Y eso es todo, te lo expliqué de forma general, solo tienes que hacer ajustes minimos para aplicarlo en tu proyecto.

Muchas gracias, funcionó perfecto, había intentado algo parecido pero me faltaba agregar la relación en el lugar correcto, ya que trataba de modificar la funcion relations, gracias nuevamente, saludos.


 $criteria->with=array("idPiezaPaciente.idPieza");