¿Cómo agregar campo dinámico en la colección Magento?
-
16-10-2019 - |
Pregunta
He creado una colección Magento como esta para calcular la distancia desde Lat Long.
$collection = Mage::getModel('module/module')->getCollection()->addFieldToFilter('status',1);
$collection->getSelect()->columns(array('distance' => new Zend_Db_Expr("( 6371 * acos( cos( radians(23.0130648) ) * cos( radians( latitude ) ) * cos( radians( longitude) - radians(72.4909026) ) + sin( radians(23.0130648) ) * sin( radians( latitude ) ) ) )")))
->having('distance <10')
->order('distance ' . Varien_Db_Select::SQL_ASC);
Pero estoy recibiendo error sqlstate [42S22]: columna no encontrada: 1054 columna desconocida 'distancia' en 'tener cláusula'.
Cuando imprimo el cálculo de distancia del objeto de recolección es correcto. ¿Entonces, Cual fue el problema?
Mi problema es similar como esta pregunta Problema de usar "tener" en la colección Magento
Estoy usando Pagination On Collection, si elimino la clase de paginación, entonces funciona perfecto. Pero no puedo resolver con la solución proporcionada. Aquí está mi código de paginación.
En _prepareLayout()
función que puse esto
$pager = $this->getLayout()->createBlock('page/html_pager', 'pager');
$pager->setAvailableLimit(array(5=>5,10=>10,20=>20,'all'=>'all'));
$pager->setCollection($this->getCollection());
$this->setChild('pager', $pager);
$this->getCollection()->load();
return $this;
Agregue esta función también en el archivo de bloque
public function getPagerHtml()
{
return $this->getChildHtml('pager');
}
y llame a esto en el archivo phtml como <?php echo $this->getPagerHtml(); ?>
Solución
Puedo intentar usar addExpressionFieldToSelect
.
Puedes encontrar el método en Mage_Core_Model_Resource_Db_Collection_Abstract
.
En su caso, debería ser algo como esto: (esto es solo una suposición, puede recibir algunos errores, pero la idea está bien)
$collection = Mage::getModel('module/module')->getCollection()->addFieldToFilter('status',1);
$collection->addExpressionFieldToSelect('distance', '( 6371 * acos( cos( radians(23.0130648) ) * cos( radians( {{latitude}}) ) * cos( radians( {{longitude}}) - radians(72.4909026) ) + sin( radians(23.0130648) ) * sin( radians( {{latitude}}) ) ) )', array('latitude'=>'latitude', 'longitude'=>'longitude'));
$collection->getSelect()->having('distance > 10');
los addExpressionFieldToSelect
Funciona así:
El primer parámetro es el alias de la expresión (nombre del campo virtual).
El segundo parámetro es la expresión. Reemplace los nombres de campo con los marcadores de posición envueltos Arround {{...}}
El tercer parámetro es la correspondencia del marcador de posición (sin {{}}
). En tu caso latitide
el marcador de posición corresponde a latitude
campo así {{latitude}}
será reemplazado con latitude
. Lo mismo ocurre con longitude
.
EDITAR
Hay un problema al agregar paginación al $collection
como esto
$collection->setCurPage(1)->setPageSize(5);
Aquí está el camino backtrace del problema. Cuando se carga la colección se llama _renderLimit()
. El método se ve así
protected function _renderLimit()
{
if($this->_pageSize){
$this->_select->limitPage($this->getCurPage(), $this->_pageSize);
}
return $this;
}
Entonces esto llama getCurPage()
(ver Varien_Data_Collection
clase).
getCurPage
tiene una verificación adicional para ver si el número de página no está fuera del rango máximo, por lo que calcula el número total de páginas en getLastPageNumber()
.
El problema aquí es que Magento restablece las columnas en la selección para calcular el tamaño de la colección. En Varien_Data_Collection_Db::getSelectCountSql
Ahí está esto:
$countSelect->reset(Zend_Db_Select::COLUMNS);
Al restablecer las columnas, termina con este SQL
SELECT COUNT(*) FROM `table_name_here` AS `main_table` HAVING (distance < 10)
Esto es lo que genera el error.
Veo 2 opciones aquí.
Anulas en tu clase de colección el método
getSelectCountSql
y retire el reinicio de la columna:public function getSelectCountSql() { $this->_renderFilters(); $countSelect = clone $this->getSelect(); $countSelect->reset(Zend_Db_Select::ORDER); $countSelect->reset(Zend_Db_Select::LIMIT_COUNT); $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET); //$countSelect->reset(Zend_Db_Select::COLUMNS);//comment this line $countSelect->columns('COUNT(*)'); return $countSelect; }
Anulas el
getCurPage()
Método para omitir la validación de rango:public function getCurPage($displacement = 0){ if (!empty($this->_curPage)){ return $this->_curPage + $displacement; } return 1; }
Editar para editar
Para evitar afectar el resto de los módulos, puede anular el getCurPage
Método como este:
public function getCurPage($displacement = 0){
if (!$this->getDirectCurPage()){//if a specific flag is not set behave as default
return parent::getCurPage($displacement);
}
if (!empty($this->_curPage)){
return $this->_curPage + $displacement;
}
return 1;
}
Ahora cuando quieres usar tu having
Método simplemente agregue esto a su colección
$collection->setDirectCurPage(1);
Otros consejos
Intente usar esto en su lugar:
$collection = Mage::getModel('module/module')->getCollection()->addFieldToFilter('status',1);
$collection->getSelect()->columns(array('distance' => new Zend_Db_Expr("( 6371 * acos( cos( radians(23.0130648) ) * cos( radians( latitude ) ) * cos( radians( longitude) - radians(72.4909026) ) + sin( radians(23.0130648) ) * sin( radians( latitude ) ) ) )")))
->addAttributeHaving('distance <10')
->addAttributeToSort('distance', Varien_Db_Select::SQL_ASC);
Tu podrías intentar where()
en vez de having()
Como no usas ninguno JOIN
declaraciones:
$collection->getSelect()->where('distance > ?', 10);