Búsqueda y ordenación en columnas personalizadas

Hola a todos,

estoy intentado añadir una columna a un cgridview. Esta columna es un campo calculado (que actualmente obtengo con un método get) sin embargo, de esta manera no puedo buscarlo ni ordenar por esa columna. ¿cómo sería la mejor manera de resolver este problema?

El cgridview se rellena con los datos de la tabla materiales

Y la columna que quiero añadir es la cantidad disponible de cada material(que se calcula sumando la cantidad de las entradas en almacén de ese material - la cantidad de salidas del almacén de ese material).

Datos de la bbdd:

Material(id, nombre)

Entrada(id, id_material, cantidad)

Salida(id, id_maerial, cantidad)

Saludos y gracias de antemano.

comprobar esta

http://www.yiiframework.com/forum/index.php/topic/21276-filter-in-cgridview-columns/page__p__104187__hl__CGridView+column#entry104187

comprobar esta

Hola, es en efecto un tanto complicado, apoyate de este tutorial http://www.javierblogs.com/busqueda-y-ordenamiento-de-campos-virtuales-en-yii-framework/

Saludos

Gracias por las respuesta,

entiendo el tutorial que me has pasado Javierlog pero me encuentro ante un problema. Mi campo calculado no se obtiene tan sencillamente como el del ejemplo que me pasas.

Para poder obtener el campo tengo que sumar la cantidad de las entradas en almacén de ese material y restar la cantidad de salidas del almacén de ese material (esto son dos subselects) que como veo en todos los tutoriales es complicado hacerlo con el criteria.

La consulta sería algo así:

select *, ((select sum(cantidad) from entradas where id_material=1)-(select sum(cantidad) from salidas where id_material=1)) from materiales where id=1;

¿Alguna idea?

Saludos.

No deberias hacerlo asi…

Existe un tipo de Query especial en lo que es el concepto de base de datos relacional llamado "Statical Query."

http://www.yiiframework.com/doc/guide/1.1/en/database.arr#statistical-query

Con eso puedes hacer cuentas de una cantidad de cualquier cosa relacionada entre tablas de la base de datos. Con eso ya seria mas

una vez creas una relacion estatica , puedes utlizarlas en tus consultas.

Por ejemplo si creaste un estático llamado "entradas" en tu modelo, podrias utilizarlo en tu metodo get de la siguiente manera




public function getTotal(){

    return $this->entradas - $this->salidas;

}



ya con esto puedes incluirla en tu busqueda de manera mas facil tambien

El sort de columnas si se mantiene igual.

Gracias Javierlog,

le echo un vistazo y os comento a ver que tal me ha ido.

Saludos.

Lo primero, gracias por la info sobre statistical queries me ha venido muy bien.

Por otro lado, no se muy bien como llamar desde CGridView a los campos de las relaciones statistical. ¿Cómo debería poner el asc y desc en el CGridView?

Pongo lo que he hecho:

En el modelo "material"




        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(

			'sumEntradasMateriales'=>array(self::STAT, 'entrada_material', 'id_material', 'select'=>'SUM(cantidad)'),

			'sumSalidasMateriales'=>array(self::STAT, 'salida_material', 'id_material', 'select'=>'SUM(cantidad)'),

			'entrada_materials' => array(self::HAS_MANY, 'entrada_material', 'id_material'),

			'id_ubicacion0' => array(self::BELONGS_TO, 'ubicacion', 'id_ubicacion'),

			'salida_materials' => array(self::HAS_MANY, 'salida_material', 'id_material'),

		);

	}

 

        public function getMaterialTotal(){

		return $this->sumEntradasMateriales - $this->sumSalidasMateriales;

	}




En la vista admin




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

	'id'=>'material-grid',

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

	'filter'=>$model,

	'columns'=>array(

		'nombre',

		'codigo',

		'numero_sn',

		'cantidad_minima_requerida',

		array('name'=>'ubicacion_search', 'value'=>'$data->id_ubicacion0->ubicacion','type'=>'text'),

		'sumEntradasMateriales',

		'sumSalidasMateriales',

		array('name'=>'material_total', 'value'=>'$data->getMaterialTotal()', ),

        array(

	        'class'=>'CButtonColumn',

		),

	),

));



Saludos.

Remplaza esta linea

array(‘name’=>‘material_total’, ‘value’=>’$data->getMaterialTotal()’, ),

por

‘materialTotal’

Que quede asi




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

        'id'=>'material-grid',

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

        'filter'=>$model,

        'columns'=>array(

                'nombre',

                'codigo',

                'numero_sn',

                'cantidad_minima_requerida',

                array('name'=>'ubicacion_search', 'value'=>'$data->id_ubicacion0->ubicacion','type'=>'text'),

                'sumEntradasMateriales',

                'sumSalidasMateriales',

                'materialTotal',

                array(

                    'class'=>'CButtonColumn',

                ),

        ),

));






Luego si quieres ordenar por dar un ejemplo por el campo ‘materialTotal’

Te vas al dataprovider y configuras la propiedad sort como dice en mi ejemplo.

En tu caso seria asi

Primero supongamos que tienes una relación definida en el modelo desde tu tabla materiales hasta tu tabla entras y salidas… ya con eso podrias hacer algo como esto en tu criteria y en el dataprovider, con eso lograrias entonces ordenar tus campos




$criteria->select = "entradas.entrasTotal - salidas.salidasTotal as total";

$criteria->with = array(

       'entras' => array('select' => 'SUM(cantidad) as entrasTotal'),

       'salidas' => array('select' => 'SUM(cantidad) as salidasTotal'),

);


...............

return new CActiveDataProvider($this, array(

            'criteria'=>$criteria,

            'sort'=>array(

                'attributes'=>array(

                    'attributo1',

                    'attributo2',

                    'attributo3'

                    'materialTotal'=>array(

                        'asc'=>'total',

                        'desc'=>'total DESC'

                    ),

                ),

            )

        )); 



Tu problema es bastante complejo, :lol: jaja, pero tranquila, tiene solucion

Gracias por tu seguimiento Javierlog, pero sigo con problemas :( .

Entiendo que haciendo lo que me dices me queda esto:


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

	'id'=>'material-grid',

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

	'filter'=>$model,

	'columns'=>array(

		'nombre',

		'codigo',

		'numero_sn',

		'cantidad_minima_requerida',

		array('name'=>'ubicacion_search', 'value'=>'$data->id_ubicacion0->ubicacion','type'=>'text'),

		'sumEntradasMateriales',

		'sumSalidasMateriales',

		'materialTotal',array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>

Y en el modelo.




        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(

			'sumEntradasMateriales'=>array(self::STAT, 'entrada_material', 'id_material', 'select'=>'SUM(cantidad)'),

			'sumSalidasMateriales'=>array(self::STAT, 'salida_material', 'id_material', 'select'=>'SUM(cantidad)'),

			'entrada_materials' => array(self::HAS_MANY, 'entrada_material', 'id_material'),

			'id_ubicacion0' => array(self::BELONGS_TO, 'ubicacion', 'id_ubicacion'),

			'salida_materials' => array(self::HAS_MANY, 'salida_material', 'id_material'),

		);

	}



y esto




          public function relSearch(){

		$criteria=new CDbCriteria;

		$criteria->select ="(sumEntradasMateriales.entradasTotal - sumSalidasMateriales.salidasTotal) as materialTotal";

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

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

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

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

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

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

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

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

		$criteria->with=array('id_ubicacion0', 

		'sumEntradasMateriales' => array('select' => 'SUM(cantidad) as entradasTotal'),

		'sumSalidasMateriales' => array('select' => 'SUM(cantidad) as salidasTotal'),);

		return new CActiveDataProvider('material', array(

				'criteria'=>$criteria,

				'sort'=>array(

						'attributes'=>array(

								'materialTotal'=>array(

										'asc'=>'materialTotal',

										'desc'=>'materialTotal DESC'

								),

						),

				)

		));

	}



Pero me da este error:

CDbCommand falló al ejecutar la sentencia SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘sumEntradasMateriales.entradasTotal’ in ‘field list’. The SQL statement executed was: SELECT (sumEntradasMateriales.entradasTotal - sumSalidasMateriales.salidasTotal) as materialTotal, t.id AS t0_c0, id_ubicacion0.id AS t1_c0, id_ubicacion0.ubicacion AS t1_c1 FROM material t LEFT OUTER JOIN ubicacion id_ubicacion0 ON (t.id_ubicacion=id_ubicacion0.id) LIMIT 10

Por lo que veo estoy haciendo mal el cruce de tablas, pero he hecho diferentes pruebas y no acierto.

¿Alguna idea?

¡Gracias y saludos!

Lo interesante es que no se ve incluido en tu error los prefijos de las relaciones estaticas,

Intenta lo siguiente




public function relSearch(){

                $criteria=new CDbCriteria;

                $criteria->select ="(sumEntradasMateriales - sumSalidasMateriales) as materialTotal";

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

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

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

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

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

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

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

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

                $criteria->with=array('id_ubicacion0','sumEntradasMateriales','sumSalidasMateriales');

                return new CActiveDataProvider('material', array(

                                'criteria'=>$criteria,

                                'sort'=>array(

                                                'attributes'=>array(

                                                                'materialTotal'=>array(

                                                                                'asc'=>'materialTotal',

                                                                                'desc'=>'materialTotal DESC'

                                                                ),

                                                ),

                                )

                ));

        }



Tomalo con calma :lol: lo mas seguro es que ya estemos por encontrar la solución a tu problema

Me lo tomo con filosofía ;)

He intentado tu solución pero lanza el error:

CDbCommand falló al ejecutar la sentencia SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘sumEntradasMateriales’ in ‘field list’. The SQL statement executed was: SELECT (sumEntradasMateriales - sumSalidasMateriales) as materialTotal, t.id AS t0_c0, id_ubicacion0.id AS t1_c0, id_ubicacion0.ubicacion AS t1_c1 FROM material t LEFT OUTER JOIN ubicacion id_ubicacion0 ON (t.id_ubicacion=id_ubicacion0.id) LIMIT 10

Parece que no está cruzando las tablas adecuadamente.

A ver si sigo investigando y descubro algo.

También he intentado hacerlo de otra manera




	public function relSearch(){

		$criteria=new CDbCriteria;

		$criteria->select =array('(entradasTotal - salidasTotal) as materialTotal');

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

		$criteria->with=array('entrada_materials' => array('select' => 'SUM(entrada_materials.cantidad) as entradasTotal',),

				 				'salida_materials'=> array('select' => 'SUM(salida_materials.cantidad) as salidasTotal'),);

		$criteria->together = true;


		return new CActiveDataProvider('material', array(

			'criteria'=>$criteria,

				'sort'=>array(

						'attributes'=>array(

								'materialTotal'=>array(

										'asc'=>'materialTotal',

										'desc'=>'materialTotal DESC'

								),

						),

				)

		));

	}



para intentar cruzar las tablas, pero me sale:

CDbCommand falló al ejecutar la sentencia SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘entradasTotal’ in ‘field list’. The SQL statement executed was: SELECT (entradasTotal - salidasTotal) as materialTotal, t.id AS t0_c0, SUM(entrada_materials.cantidad) as entradasTotal, entrada_materials.id AS t1_c0, SUM(salida_materials.cantidad) as salidasTotal, salida_materials.id AS t2_c0 FROM material t LEFT OUTER JOIN entrada_material entrada_materials ON (entrada_materials.id_material=t.id) LEFT OUTER JOIN salida_material salida_materials ON (salida_materials.id_material=t.id) LIMIT 10

¿A nadie se le ocurre alguna alternativa?