最初にMagentoコレクションにアイテムを追加する方法は?


7

要素を最後に追加するこのメソッドと同様に、最初の要素としてコレクションに要素を追加することは可能ですか?

$product = Mage::getModel('catalog/product')->load(15879);
$productCollection->addItem($product);

回答:


10

免責事項:可能な限り、並べ替えの目的でデータベースを使用してください。ただし、場合によっては、データベースに格納されていないコレクションのアイテムを(まだ)整理する必要がありますcollectTotals()。たとえば、中にアイテムを見積もりに動的に追加した後などです。次に、このアプローチが役立ちます。

残念ながらVarien_Data_Collection、この点では非常に柔軟ではありません。コレクション内のアイテムを並べ替えるには、アイテムを削除して、目的の順序で再度追加する必要があります。

あなたの特定のケースでは:

// remove previous items, keep them in $items
$items = $productCollection->getItems();
foreach ($productCollection as $key => $item) {
    $collection->removeItemByKey($key);
}

// add new item
$productCollection->addItem($product);

// re-add $items
foreach ($items as $item) {
    $productCollection->addItem($item);
}

更新:パフォーマンス

パフォーマンスに異論があるため、実際の製品データベースで少しベンチマークを行いました。20Kの製品でコレクションをロードすることは絶対にしてはいけないことですが、これはロードされた配列を2回繰り返しても重要なオーバーヘッドが追加されないことを証明するためです。

テストスクリプト

$startTime = microtime(true);
$productCollection = Mage::getResourceModel('catalog/product_collection')->load();

printf("Loaded %d products. Time: %.2fs Memory: %s\n",
    $productCollection->count(), microtime(true)-$startTime, number_format(memory_get_usage(true)));

// remove previous items, keep them in $items
$items = $productCollection->getItems();
foreach ($productCollection as $key => $item) {
    $productCollection->removeItemByKey($key);
}

printf("Removed items. Time %.2fs Memory: %s\n",
    microtime(true)-$startTime, number_format(memory_get_usage(true)));

// add new item
$productCollection->addItem(Mage::getModel('catalog/product'));

// re-add $items
foreach ($items as $item) {
    $productCollection->addItem($item);
}

printf("Added items. Time %.2fs Memory: %s\n",
    microtime(true)-$startTime, number_format(memory_get_usage(true)));

出力

20761製品をロードしました。時間:3.70秒メモリ:81,264,640

削除されたアイテム。時間3.92メモリ:81,788,928

追加されたアイテム。時間4.31メモリ:81,788,928

そして、より現実的な量の100個のロードされた製品で:

100個の商品を読み込みました。時間:0.11秒メモリ:10,223,616

削除されたアイテム。時間0.11秒メモリ:10,223,616

追加されたアイテム。時間0.12秒メモリ:11,272,192


これはひどい答えです。ロードする前に、コレクションに対して1つではなく2つのforeachを実行しています。これは、大規模なコレクションの場合は永遠にかかり、パフォーマンスが大幅に低下します。
mbalparda 2015

コレクションはすでにロードされていると思いました。そうでなければ、質問は私にはあまり意味がありません。
Fabian Schmengler、2015

確かにありますが、このアイデアはコレクションに2つのforeachsを追加します。これは、foreach内にロードする場合ではありませんが、他のことをする前にコレクション全体を2回トラフすると、環境が破壊されます。
mbalparda 2015

1
@mbalpardaは正しいです。PHPを使用してコレクションを操作するのは非常に時間がかかります。データベースサーバーにPHPを使用して作業を実行させるのは、他に選択肢がない場合に限ります。大きなコレクションはPHPで完全に停止します。
Jonathan Hussey、2015

2
@JonathanHussey私は、可能であれば、データベースにソートの大仕事をさせるべきであることに心から同意します。しかし、問題は文脈なしであり、これが正当な欲望であるシナリオを見るので、私は解決策を与えました。
Fabian Schmengler、2015

3

コレクションオブジェクトには_items、データベースクエリによって取得されたすべての結果モデルを含む、という標準配列があります。addItem()メソッドは、クラス内に存在Varien_Data_Collectionし、あなたはそれをすべてを見れば、それは配列の最後にエントリをプッシュしているし、全く同じ動作が適用されないarray_push

public function addItem(Varien_Object $item)
{
    $itemId = $this->_getItemId($item);

    if (!is_null($itemId)) {
        if (isset($this->_items[$itemId])) {
            throw new Exception('Item ('.get_class($item).') with the same id "'.$item->getId().'" already exist');
        }
        $this->_items[$itemId] = $item;
    } else {
        $this->_addItem($item);
    }
    return $this;
}

そして、_addItem()方法は次のとおりです:

protected function _addItem($item)
{
    $this->_items[] = $item;
    return $this;
}

したがって、addItem()メソッドを呼び出すときに発生するのは、キーとして存在する場合は追加する項目のIDを使用して新しいエントリが配列の最後に追加され、それ以外の場合は次に利用可能な自動インクリメントキー値を使用することです(定義しないことにより)かぎ)。

アイテムを特定の方法でgetItems()並べ替える必要がある場合は、代わりにデータベースクエリが結果を正しく並べ替えるか、コレクションオブジェクトからすべてのアイテムをプルしてからPHPを使用して並べ替える必要があります。FARによる最も効率的な方法は、データベースクエリでそれらを正しく順序付けることです。PHPを介してデータベースから取得した結果の操作は、数え切れないほど時間がかかります。


1

私は適切な解決策を手に入れます。

新しいバリアンコレクションオブジェクトを作成します。

 $collection- = new Varien_Data_Collection();


 $product = Mage::getModel('catalog/product')->load(15879);

product add first elementを割り当てます。

 $collection->addItem($product);

残りの製品のループ割り当てを使用する:

foreach($productCollection as $eachProd):
    $collection->addItem($eachProd); 
    endforeach;

$productCollection=$collection;

1
このメソッドは存在しません。ありますgetFirstItem()
ファビアンシュメングラー2015

小規模なコレクションでは問題ありませんが、PHPを使用してプロダクションコレクション全体を反復することは常に遅くなります...
Jonathan Hussey、2015

はい。私はあなたに100%同意します
Amit Bera

1

最初の要素としてコレクションに要素を追加するのと同じタスクがありました。以下は、私が実装したコードで、完全に機能します。

$product = Mage::Model('catalog/product')->load(product_id);// product/element to add as first element

$collection = Mage::Model('catalog/product')->getCollection();

$collection->addAttributeToSelect.... // general code to select attributes

$collection->addAttributeToFilter.... // general code to apply filter

if($product && $product->getId()){ **// product to add as first element**

   $collection->addItem($product); // added product to collection

   $expr = new Zend_Db_Expr("`e`.`entity_id` = {$product->getId()} desc"); 

   $collection->getSelect()->order($expr); **// $product will be order by     DESC to set as first element**  

}

$collection->addAttributeToSort( 'price', 'asc'); // this sorting will apply on remaining elements in the collection.

説明

上記のコードで$productは、最初の要素として追加する必要があり$collection$productそのコレクションに追加された製品コレクションを作成しました。

$collection->getSelect()->order($expr);強制ソート位置を使用して$product、最初の位置として設定し、残りの要素を次の順序で並べます。$collection->addAttributeToSort( 'price', 'asc');

- $collection->getSelect()->order($expr);コードによる並べ替えの前に呼び出す必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.