magentoコレクションに動的フィールドを追加するにはどうすればよいですか?


8

緯度経度からの距離を計算するために、このようなマゼンタコレクションを1つ作成しました。

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

しかし、SQLSTATE [42S22]エラーが発生します:列が見つかりません:1054 'having句'の列 'distance'が不明です。

コレクションオブジェクトを印刷すると距離計算が正しいです。それで問題は何でしたか?

私の問題はこの質問に似ていますMagentoコレクションで「持つ」を使用した問題

コレクションでページネーションを使用しています。ページネーションクラスを削除すると、完全に機能します。しかし、私は提供されたソリューションでは解決できません。これが私のページネーションコードです。

_prepareLayout()機能私はこれを置きます

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

この関数をブロックファイルにも追加する

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

そしてこれをphtmlファイルで次のように呼び出します <?php echo $this->getPagerHtml(); ?>

回答:


13

使ってみますaddExpressionFieldToSelect
メソッドはにありMage_Core_Model_Resource_Db_Collection_Abstractます。
あなたの場合、それはこのようなものでなければなりません:(これは単なる仮定であり、いくつかのエラーが発生する可能性がありますが、アイデアは大丈夫​​です)

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

addExpressionFieldToSelectこのように動作します:
最初のパラメータは式(仮想フィールド名)の別名です。
2番目のパラメーターは式です。フィールド名をラップされたプレースホルダーで置き換え{{...}}
ます3番目のパラメーターは、プレースホルダーの対応です(なし{{}})。あなたの場合、latitideプレースホルダーはlatitudeフィールドに対応するので、{{latitude}}に置き換えられlatitudeます。同じことが当てはまりますlongitude

[編集]このように
ページネーションを追加すると問題が発生する$collection

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

これは問題のバックトレースです。コレクションが読み込まれると、これが呼び出され_renderLimit()ます。メソッドはこのようになります

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

    return $this;
}

したがって、これは呼び出されますgetCurPage()Varien_Data_Collectionクラスを参照)。
getCurPageには、ページ番号が最大範囲を超えていないかどうかを確認する追加の検証があるため、でページの総数を計算しgetLastPageNumber()ます。
ここでの問題は、Magentoがコレクションサイズを計算するために選択内の列をリセットすることです。これVarien_Data_Collection_Db::getSelectCountSqlがあります:

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

列をリセットすることで、このSQLになります

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

これがエラーの原因です。

ここには2つのオプションがあります。

  1. コレクションクラスでメソッドgetSelectCountSql をオーバーライドし、列のリセットを削除します。

    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. getCurPage()メソッドをオーバーライドして、範囲の検証をスキップします。

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

[編集して編集]
残りのモジュールに影響を与えないようにするには、次のgetCurPageようにメソッドをオーバーライドします。

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

havingメソッドを使用したい場合は、これをコレクションに追加してください

$collection->setDirectCurPage(1);

このメソッドはまだ動作しないエラーが続きます。
Mufaddal 2013

havingステートメントを削除してコレクションをループするとどうなりますか?distanceアイテムデータに値が表示されていますか?
マリウス

はい、クルーゼを削除すると、距離アイテムの値が表示されます。
Mufaddal 2013

これは奇妙です。コアコレクションの概念実証としてテストしましたが、うまく機能します。$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');モジュールに問題がある可能性があります。
マリウス

1つは、コレクションでページネーションを使用しているため、ページネーションを削除すると問題が発生し、メソッドが正しく機能する
Mufaddal

3

代わりにこれを使ってみてください:

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

その動作しないnullオブジェクトを返します
Mufaddal 2013

0

ステートメントを使用しないので、where()代わりに試すことができhaving()ますJOIN

$collection->getSelect()->where('distance > ?', 10);

いいえ、それでもエラーが返されます 'where句の不明な列' distance '
Mufaddal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.