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(); ?>

¿Fue útil?

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í.

  1. Anulas en tu clase de colección el método getSelectCountSqly 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;
    }
    
  2. 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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a magento.stackexchange
scroll top