Wie füge ich ein dynamisches Feld in die Magento-Sammlung ein?

8

Ich habe eine solche Magento-Sammlung erstellt, um die Entfernung von Lat Long zu berechnen.

$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);

Aber ich erhalte die Fehlermeldung SQLSTATE [42S22]: Spalte nicht gefunden: 1054 Unbekannte Spalte 'Entfernung' in 'Klausel haben'.

Wenn ich ein Sammlungsobjekt drucke, ist die Entfernungsberechnung richtig. Also, was war das Problem?

Mein Problem ist ähnlich wie bei dieser Frage. Problem mit "Haben" in der Magento-Sammlung

Ich verwende die Paginierung für die Sammlung. Wenn ich die Paginierungsklasse entferne, funktioniert sie perfekt. Aber ich kann nicht mit der bereitgestellten Lösung lösen. Hier ist mein Paginierungscode.

In _prepareLayout()Funktion setze ich das

$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;

Fügen Sie diese Funktion auch in die Blockdatei ein

  public function getPagerHtml()
  {
    return $this->getChildHtml('pager');
  }

und nennen Sie dies in der HTML-Datei als <?php echo $this->getPagerHtml(); ?>

Mufaddal
quelle

Antworten:

13

Ich kann versuchen zu verwenden addExpressionFieldToSelect.
Sie finden die Methode in Mage_Core_Model_Resource_Db_Collection_Abstract.
In Ihrem Fall sollte es ungefähr so ​​aussehen: (Dies ist nur eine Annahme, Sie könnten einige Fehler bekommen, aber die Idee ist in Ordnung)

$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');

Das addExpressionFieldToSelectfunktioniert so:
Der erste Parameter ist der Alias ​​des Ausdrucks (Name des virtuellen Feldes).
Der zweite Parameter ist der Ausdruck. Ersetzen Sie die Feldnamen durch umlaufende Platzhalter. {{...}}
Der dritte Parameter ist die Platzhalterkorrespondenz (ohne {{}}). In Ihrem Fall latitideentspricht der Platzhalter dem latitudeFeld und {{latitude}}wird durch ersetzt latitude. Gleiches gilt für longitude.

[EDIT]
Es gibt ein Problem beim Hinzufügen von Paginierung der $collectionwie folgt

$collection->setCurPage(1)->setPageSize(5);  

Hier ist die Rückverfolgung des Problems. Wenn die Sammlung geladen wird, wird dies aufgerufen _renderLimit(). Die Methode sieht so aus

protected function _renderLimit()
{
    if($this->_pageSize){
        $this->_select->limitPage($this->getCurPage(), $this->_pageSize);
    }

    return $this;
}

Das ruft also getCurPage()(siehe Varien_Data_CollectionKlasse).
getCurPagehat eine zusätzliche Überprüfung, um festzustellen, ob die Seitenzahl nicht außerhalb des maximalen Bereichs liegt, sodass die Gesamtzahl der Seiten in berechnet wird getLastPageNumber().
Das Problem hierbei ist, dass Magento die Spalten in der Auswahl zur Berechnung der Sammlungsgröße zurücksetzt. Darin Varien_Data_Collection_Db::getSelectCountSqlist folgendes:

$countSelect->reset(Zend_Db_Select::COLUMNS);

Durch Zurücksetzen der Spalten erhalten Sie diese SQL

SELECT COUNT(*) FROM `table_name_here` AS `main_table` HAVING (distance < 10)

Dies erzeugt den Fehler.

Ich sehe hier 2 Optionen.

  1. Sie überschreiben in Ihrer Auflistungsklasse die Methode getSelectCountSql und entfernen das Zurücksetzen der Spalte:

    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. Sie überschreiben die getCurPage()Methode zum Überspringen der Bereichsüberprüfung:

    public function getCurPage($displacement = 0){
        if (!empty($this->_curPage)){
            return $this->_curPage + $displacement;
        }
        return 1;
    }

[EDIT TO EDIT]
Um die übrigen Module nicht zu beeinträchtigen, können Sie die getCurPageMethode folgendermaßen überschreiben :

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;
}

Wenn Sie nun Ihre havingMethode verwenden möchten, fügen Sie diese einfach Ihrer Sammlung hinzu

$collection->setDirectCurPage(1);
Marius
quelle
Diese Methode funktioniert immer noch nicht Fehler weiter.
Mufaddal
Was passiert, wenn Sie die havingAnweisung entfernen und die Sammlung durchlaufen? Sehen Sie einen Wert für distancein den Artikeldaten?
Marius
Ja, ich kann einen Wert für das Entfernungselement sehen, wenn ich Cluase entferne.
Mufaddal
Das ist merkwürdig. Ich habe als Proof of Concept an einer Kernsammlung getestet und es funktioniert großartig. $collection = Mage::getModel('cms/block')->getCollection() ->addExpressionFieldToSelect('some_total', 'SUM({{is_active}})', array('is_active'=>'is_active')); $collection->getSelect()->having('some_total > 1')->order('some_total ASC');Vielleicht stimmt etwas mit Ihrem Modul nicht.
Marius
Eine Sache, ich verwende Paginierung für die Sammlung, so dass es Probleme verursacht, wenn ich die Paginierung entferne, dann funktionieren Ihre Methoden korrekt
Mufaddal
3

Versuchen Sie stattdessen Folgendes:

$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);
Daniel Kenney
quelle
es funktioniert nicht es gibt null Objekt zurück
Mufaddal
0

Sie könnten es where()stattdessen versuchen, having()da Sie keine JOINAnweisungen verwenden:

$collection->getSelect()->where('distance > ?', 10);
sebastianwagner
quelle
Nein, es wird immer noch ein Fehler zurückgegeben. Unbekannte Spalte 'Entfernung' in 'where-Klausel
Mufaddal