Làm thế nào để thêm mục vào bộ sưu tập Magento vào đầu?


7

Có thể thêm phần tử vào bộ sưu tập làm phần tử đầu tiên, tương tự như phương thức này có thêm phần tử vào cuối không?

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

Câu trả lời:


10

TUYÊN BỐ TỪ CHỐI: Sử dụng cơ sở dữ liệu cho các mục đích sắp xếp bất cứ khi nào có thể. Tuy nhiên, trong một số trường hợp, bạn có thể muốn sắp xếp các mục trong bộ sưu tập chưa được lưu trữ trong cơ sở dữ liệu (ví dụ) sau khi tự động thêm các mục vào báo giá trong thời gian collectTotals(). Sau đó, phương pháp này sẽ hữu ích.

Thật không may, Varien_Data_Collectionkhông linh hoạt về mặt này. Để sắp xếp lại các mục trong bộ sưu tập, bạn cần xóa chúng và thêm lại chúng theo thứ tự mong muốn.

Trong trường hợp cụ thể của bạn:

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

Cập nhật: Hiệu suất

Vì có sự phản đối về hiệu suất, tôi đã làm một điểm chuẩn nhỏ trên cơ sở dữ liệu sản phẩm thực sự. Lưu ý rằng việc tải bộ sưu tập với các sản phẩm 20K là điều bạn không bao giờ thực sự nên làm nhưng điều này chỉ để chứng minh điểm lặp đi lặp lại trên các mảng được tải hai lần không thêm chi phí đáng kể:

Kiểm tra tập lệnh

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

Đầu ra

Đã tải 20761 sản phẩm. Thời gian: 3,70 giây Bộ nhớ: 81,264,640

Các mục bị loại bỏ. Thời gian 3,92 Bộ nhớ: 81,788,928

Đã thêm mục. Bộ nhớ thời gian 4.31: 81.788.928

Và với số lượng thực tế hơn 100 sản phẩm được tải:

Đã tải 100 sản phẩm. Thời gian: 0.11s Bộ nhớ: 10.223.616

Các mục bị loại bỏ. Bộ nhớ thời gian 0.11s: 10.223.616

Đã thêm mục. Bộ nhớ thời gian 0,12s: 11,272,192


Đây là một câu trả lời khủng khiếp. Bạn đang làm không chỉ một mà là hai lời thuyết minh về một bộ sưu tập trước khi tải nó. Điều này sẽ mất mãi mãi cho các bộ sưu tập lớn và sẽ giảm hiệu suất rất nhiều.
mbalparda

Tôi giả sử, bộ sưu tập đã được tải. Nếu không, câu hỏi không có nhiều ý nghĩa với tôi.
Fabian Schmengler

Rõ ràng là và vẫn còn, ý tưởng này thêm TWO thuyết minh về một bộ sưu tập. Đây không phải là trường hợp tải bên trong một foreach, nhưng đi qua toàn bộ bộ sưu tập hai lần trước khi làm bất cứ điều gì khác sẽ phá hủy bất kỳ môi trường nào.
mbalparda

1
@mbalparda đã đúng, thao tác các bộ sưu tập bằng PHP thực sự rất chậm, luôn khiến máy chủ cơ sở dữ liệu thực hiện công việc chỉ bằng PHP nếu hoàn toàn không có tùy chọn nào khác - các bộ sưu tập lớn sẽ hoàn toàn dừng lại với PHP.
Jonathan Hussey

2
@JonathanHussey Tôi hoàn toàn đồng ý rằng bạn nên để cơ sở dữ liệu thực hiện việc phân loại nếu có thể. Nhưng vì câu hỏi không có ngữ cảnh và tôi thấy các kịch bản mà đây là mong muốn chính đáng, tôi đã đưa ra một giải pháp.
Fabian Schmengler 10/2/2015

3

Một đối tượng bộ sưu tập có một mảng tiêu chuẩn được gọi là _itemschứa tất cả các mô hình kết quả được truy vấn bởi cơ sở dữ liệu. Các addItem()phương pháp tồn tại trong lớp Varien_Data_Collectionvà nếu bạn nhìn vào nó tất cả nó là đẩy một mục vào cuối mảng và có thể chính xác hành vi tương tự như 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()phương pháp như sau:

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

Do đó, tất cả những gì xảy ra khi gọi addItem()phương thức là một mục nhập mới được thêm vào cuối mảng bằng cách sử dụng id của mục bạn đang thêm nếu nó tồn tại dưới dạng khóa, nếu không sử dụng giá trị khóa tăng tự động có sẵn tiếp theo (bằng cách không xác định một chìa khóa).

Nếu bạn cần phải sắp xếp các mục theo một cách cụ thể, thay vào đó, bạn nên đảm bảo truy vấn cơ sở dữ liệu của mình sắp xếp kết quả chính xác hoặc kéo tất cả các mục từ đối tượng bộ sưu tập bằng cách sử dụng getItems()và sau đó đặt hàng bằng PHP. Bởi FAR hiệu quả nhất là sắp xếp chúng một cách chính xác trong truy vấn cơ sở dữ liệu của bạn, thao tác các kết quả một khi được kéo từ cơ sở dữ liệu qua PHP chậm hơn vô số lần.


1

Tôi nhận được bất kỳ giải pháp thích hợp. Giải pháp tốt có thể làm việc:

Tạo đối tượng bộ sưu tập varien mới:

 $collection- = new Varien_Data_Collection();


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

Chỉ định sản phẩm thêm phần tử đầu tiên:

 $collection->addItem($product);

sử dụng vòng lặp gán phần còn lại của sản phẩm:

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

$productCollection=$collection;

1
Phương pháp này không tồn tại. Chỉ có mộtgetFirstItem()
Fabian Schmengler 10/2/2015

Mặc dù ok đối với các bộ sưu tập nhỏ, việc lặp lại toàn bộ bộ sưu tập sản xuất bằng PHP luôn bị chậm ...
Jonathan Hussey

Đúng. tôi đồng ý với bạn 100%
Amit Bera

1

Tôi đã có cùng một nhiệm vụ để thêm phần tử vào bộ sưu tập như phần tử đầu tiên. Phần mềm là mã tôi đã triển khai và hoạt động hoàn hảo cho tôi.

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

Giải trình

Trong đoạn mã trên, $productcần thiết để thêm làm phần tử đầu tiên, tạo bộ sưu tập sản phẩm $collection, thêm vào $productbộ sưu tập đó.

Sử dụng $collection->getSelect()->order($expr);vị trí sắp xếp mạnh mẽ $productđể đặt làm vị trí đầu tiên và phần còn lại của các yếu tố sẽ được sắp xếp theo$collection->addAttributeToSort( 'price', 'asc');

Lưu ý - Phải gọi $collection->getSelect()->order($expr);trước khi sắp xếp theo mã.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.