Wie füge ich am Anfang einen Gegenstand zur Magento-Sammlung hinzu?

7

Es ist möglich, der Sammlung als erstes Element ein Element hinzuzufügen, ähnlich wie bei dieser Methode, bei der am Ende ein Element hinzugefügt wird.

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

Antworten:

10

HAFTUNGSAUSSCHLUSS: Verwenden Sie die Datenbank nach Möglichkeit zum Sortieren. In einigen Fällen möchten Sie jedoch möglicherweise Elemente in einer Sammlung anordnen, die (noch) nicht in der Datenbank gespeichert sind, z. B. nachdem Sie dem Angebot während des Vorgangs dynamisch Elemente hinzugefügt haben collectTotals(). Dann ist dieser Ansatz nützlich.

Leider nicht, Varien_Data_Collectionist in dieser Hinsicht nicht sehr flexibel. Um Elemente in einer Sammlung neu zu ordnen, müssen Sie sie entfernen und in der gewünschten Reihenfolge erneut hinzufügen.

In Ihrem speziellen Fall:

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

Update: Leistung

Da es Einwände hinsichtlich der Leistung gibt, habe ich einen kleinen Benchmark für eine echte Produktdatenbank durchgeführt. Beachten Sie, dass das Laden einer Sammlung mit 20.000 Produkten etwas ist, das Sie eigentlich nie tun sollten. Dies soll jedoch nur beweisen, dass das zweimalige Durchlaufen der geladenen Arrays keinen signifikanten Overhead verursacht:

Testskript

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

Ausgabe

Geladene 20761 Produkte. Zeit: 3,70 s Speicher: 81.264.640

Elemente entfernt. Zeit 3,92 Speicher: 81.788.928

Elemente hinzugefügt. Zeit 4.31 Speicher: 81.788.928

Und mit einer realistischeren Menge von 100 geladenen Produkten:

100 Produkte geladen. Zeit: 0,11 s Speicher: 10.223.616

Elemente entfernt. Zeit 0,11 s Speicher: 10.223.616

Elemente hinzugefügt. Zeit 0,12 s Speicher: 11.272.192

Fabian Schmengler
quelle
Das ist eine schreckliche Antwort. Sie führen nicht nur einen, sondern zwei Vorgänge für eine Sammlung durch, bevor Sie sie laden. Dies wird für große Sammlungen ewig dauern und die Leistung erheblich verringern.
Mbalparda
Ich nahm an, die Sammlung ist bereits geladen. Ansonsten macht die Frage für mich nicht viel Sinn.
Fabian Schmengler
Es ist und ist klar, dass diese Idee ZWEI Foreachs über eine Sammlung hinzufügt. Dies ist nicht der Fall beim Laden in einen Foreach, aber wenn Sie die gesamte Sammlung zweimal durchlaufen, bevor Sie etwas anderes tun, wird jede Umgebung zerstört.
Mbalparda
1
@mbalparda ist richtig, das Bearbeiten von Sammlungen mit PHP ist wirklich sehr langsam. Lassen Sie den Datenbankserver die Arbeit immer nur mit PHP erledigen, wenn es absolut keine andere Option gibt - große Sammlungen würden mit PHP absolut zum Erliegen kommen.
Jonathan Hussey
2
@ JonathanHussey Ich stimme voll und ganz zu, dass Sie die Datenbank nach Möglichkeit das Sortieren durchführen lassen sollten. Aber da die Frage ohne Kontext war und ich Szenarien sehe, in denen dies ein legitimer Wunsch ist, habe ich eine Lösung gegeben.
Fabian Schmengler
3

Ein Auflistungsobjekt verfügt über ein Standardarray namens, _itemsdas alle resultierenden Modelle enthält, die von der Datenbankabfrage abgerufen werden. Die addItem()Methode existiert in der Klasse. Varien_Data_CollectionWenn Sie sie sich ansehen, müssen Sie lediglich einen Eintrag an das Ende des Arrays verschieben und unterliegen genau dem gleichen Verhalten wie 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;
}

Und die _addItem()Methode ist wie folgt:

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

Wenn Sie die addItem()Methode aufrufen , wird am Ende des Arrays lediglich ein neuer Eintrag mit der ID des Elements hinzugefügt, das Sie hinzufügen, wenn es als Schlüssel vorhanden ist. Andernfalls wird der nächste verfügbare Schlüsselwert für das automatische Inkrementieren verwendet (indem nicht definiert wird) ein Schlüssel).

Wenn Sie möchten, dass die Artikel auf eine bestimmte Weise bestellt werden, sollten Sie stattdessen sicherstellen, dass Ihre Datenbankabfrage die Ergebnisse korrekt ordnet, oder den gesamten Artikel getItems()mit PHP aus dem Sammlungsobjekt ziehen und dann mit PHP bestellen. Bei weitem am effizientesten ist es, sie in Ihrer Datenbankabfrage korrekt zu ordnen. Die Bearbeitung der Ergebnisse, die über PHP aus der Datenbank abgerufen wurden, ist unzählige Male langsamer.

Jonathan Hussey
quelle
1

Ich bekomme jede richtige Lösung. Die folgende Lösung kann funktionieren:

Neues Varien-Sammlungsobjekt erstellen:

 $collection- = new Varien_Data_Collection();


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

Weisen Sie das Produkt zu. Fügen Sie das erste Element hinzu:

 $collection->addItem($product);

Verwenden Sie die Schleife, um den Rest des Produkts zuzuweisen:

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

$productCollection=$collection;
Amit Bera
quelle
1
Diese Methode existiert nicht. Es gibt nurgetFirstItem()
Fabian Schmengler
Obwohl es für kleine Sammlungen in Ordnung ist, wird das Durchlaufen einer gesamten Produktionssammlung mit PHP immer langsam sein ...
Jonathan Hussey
Ja. Ich stimme Ihnen zu 100% zu
Amit Bera
1

Ich hatte die gleiche Aufgabe, der Sammlung ein Element hinzuzufügen wie das erste Element. Unten ist der Code, den ich implementiert habe und der perfekt für mich funktioniert.

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

Erläuterung

Im obigen Code $productwird als erstes Element eine Produktsammlung $collectionhinzugefügt $product, die dieser Sammlung hinzugefügt wurde .

Wenn Sie die $collection->getSelect()->order($expr);Position von zwangsweise sortieren verwenden $product, um sie als erste Position festzulegen, werden die restlichen Elemente nach sortiert$collection->addAttributeToSort( 'price', 'asc');

Hinweis - Es muss $collection->getSelect()->order($expr);vor jeder Sortierung nach Code aufgerufen werden.

AnandSingh
quelle