Hiệu suất: Thêm mức tồn kho trong danh sách sản phẩm list.phtml của tất cả các loại sản phẩm


12

TL; DR , Yêu cầu là có một mức tồn kho trong kho được hiển thị trên trang danh sách sản phẩm danh mục với ít truy vấn / bộ nhớ bổ sung với hiệu suất trong tâm trí tuân thủ khuôn khổ của Magento.


Sau khi đọc bài viết của Vinai Kopp về tải trước cho khả năng mở rộng .

Cách tốt nhất để bao gồm các mức tồn kho trong các trang liệt kê sản phẩm danh mục ( list.phtml ) với một vài truy vấn / tải bổ sung cho các mức hiệu suất là gì?

Tôi biết một vài cách tiếp cận:

afterLoad () dường như hoạt động tốt khimedia_galleryđưa vào mà không cần truy vấn bổ sung, tuy nhiên tôi đã không thực hiện thành công cách tiếp cận tương tự với hàng tồn kho.

$attributes = $_product->getTypeInstance(true)->getSetAttributes($_product);
$media_gallery = $attributes['media_gallery'];
$backend = $media_gallery->getBackend();
$backend->afterLoad($_product);

SQL trực tiếp để thu thập dữ liệu cần thiết song song với bộ sưu tập với một product_idkhóa chẳng hạn. Nhưng tìm kiếm nhiều hơn một phương tiện thông qua khuôn khổ.

Hiện tại tôi chỉ đơn giản là tải stock_itemđối tượng qua:

$_product->load('stock_item')->getTotalQty(); Cái nào hoạt động, nhưng tôi nhận thấy việc thêm nhiều truy vấn để lấy tổng số hàng tồn kho của tất cả các sản phẩm trong bộ sưu tập.

...

__EAV_LOAD_MODEL__ (Mage_Catalog_Model_Product, id: stock_item, attributes: NULL)
__EAV_LOAD_MODEL__ (Mage_Catalog_Model_Product, id: stock_item, attributes: NULL)
__EAV_LOAD_MODEL__ (Mage_Catalog_Model_Product, id: stock_item, attributes: NULL)

...

Thật kỳ lạ, điều này hoạt động. Phép thuật xảy ra trong Mage_Eav_Model_Entity_Abauge-> load ($ object, $ entityId, $ thuộc tính). Nếu các thuộc tính $ trống, nó sẽ gọi loadAllAttribution ($ object). Vì vậy, $ sản phẩm-> tải ('blah') sẽ tải tất cả các thuộc tính bị thiếu, bao gồm 'media_gallery' - William Tran ngày 19 tháng 11 '14 lúc 4:45

Thêm các giá trị cần thiết vào bộ sưu tập đã được tải.

Cách tiếp cận đơn giản rõ ràng của việc thêm dữ liệu cần thiết vào bộ sưu tập sản xuất cấp cao nhất trong lớp / bộ lọc, dường như là cách tiếp cận tốt nhất.

Tôi đã nhận thấy một người quan sát addInventoryDataToCollection () trong Mage_CatalogInventory_Model_Observer nghe có vẻ như sẽ đạt được điều đó, nhưng việc thêm phương thức vào một mô-đun tùy chỉnh mà người quan sát có vẻ không tương thích.

<events>
    <catalog_product_collection_load_after>
        <observers>
            <inventory>
                <class>cataloginventory/observer</class>
                <method>addInventoryDataToCollection</method>
            </inventory>
        </observers>
    </catalog_product_collection_load_after>
</events>

Kết quả nào trong:

Cảnh báo: Đối số không hợp lệ được cung cấp cho foreach () trong /app/code/core/Mage/CatalogInventory/Model/Resource/Stock/Item/Collection.php trên dòng 71


1
Câu hỏi hay về boomer
Amit Bera

Câu trả lời:


4

Vấn đề thực sự ở đây không phải là tải trước, đó là sự chính xác. Việc lấy số lượng cổ phiếu cho một bộ sản phẩm là tương đối dễ dàng:

$products = Mage::getModel('catalog/product')->getCollection()
    ->addCategoryFilter($_category);
$stockCollection = Mage::getModel('cataloginventory/stock_item')
    ->getCollection()
    ->addProductsFilter($products);

Bây giờ với hai truy vấn, bạn có tất cả thông tin bạn cần. Chúng chỉ khó liên quan với nhau, có thể được sửa bằng cách sử dụng một mảng kết hợp 'product_id' => 'stock'và viết một getter. Ngoài ra, add ProductsFilter có thể được tối ưu hóa:

public function addProductIdsFilter(array $productIds)
{
    if(empty($productIds) {
        $this->_setIsLoaded(true);
    }
    $this->addFieldToFilter('main_table.product_id', array('in' => $productIds));
    return $this;
}

Điều này giúp bạn tiết kiệm kiểm tra loại và nhân bản mảng.

Vấn đề bây giờ là Chặn bộ đệm HTML. Trang danh mục này cần được thanh lọc khi bất kỳ cổ phiếu nào được cập nhật trên một sản phẩm có trong đó. Theo tôi biết, đây không phải là tiêu chuẩn, vì chỉ có thay đổi trạng thái chứng khoán thanh trừng một trang danh mục có chứa một sản phẩm (hay chính xác hơn là thay đổi mức độ hiển thị). Vì vậy, bạn sẽ cần phải quan sát ít nhất cataloginventory_stock_item_before_savevà có thể một vài người khác và xóa bộ đệm html (và bộ đệm FPC) cho trang danh mục đó.


Điểm cuối cùng của bạn là lý do chúng tôi đã yêu cầu bổ sung để lấy dữ liệu chứng khoán. Nếu bạn có danh mục với các sản phẩm di chuyển nhanh, bộ nhớ cache của bạn sẽ dành phần lớn thời gian để bị xóa / vô hiệu. lần duy nhất chúng ta cần xóa bộ đệm trang danh mục là nếu một sản phẩm bị xóa khỏi danh mục đó. Không có một giải pháp kỳ diệu nào bạn phải thực hiện để thực hiện hiệu quả nhất trong từng trường hợp. Nếu bạn muốn, bạn có thể lưu trữ dữ liệu chứng khoán để chỉ có thể được xây dựng lại sau khi xóa chứ không phải toàn bộ trang.
john-jh

Nếu bạn triển khai dữ liệu chứng khoán giống như cách bạn làm bây giờ, sử dụng dữ liệu JavaScript để cập nhật DOM, bạn có thể viết rằng sử dụng một khối có khóa bộ đệm riêng và chỉ làm mất hiệu lực dữ liệu chứng khoán. Đây là cách tôi sẽ làm điều đó cho tình huống của bạn và không sử dụng FPC dựa trên ESI, nhưng một FPC có thể tạo ra các cú đấm trong bộ xử lý yêu cầu. Không chỉ cho bit bộ định tuyến, mà còn chỉ yêu cầu một trình thông dịch php trên mỗi trang. Khi một máy chịu áp lực vì bất kỳ lý do gì, trình thông dịch php của bạn là tài nguyên chuyên sâu nhất về Cpu. Điều này đang bắt đầu nghe có vẻ giống như một dự án cuối tuần tốt đẹp ;-)
Melvyn

3
Đây là loại công cụ làm cho công việc thực sự thú vị, nơi bạn phải thực sự suy nghĩ về việc thực hiện và các vấn đề tiềm ẩn và tắc nghẽn. Tôi chắc chắn thấy bạn đến từ đâu với quy trình PHP duy nhất vào lúc này không phải là vấn đề đối với chúng tôi nhưng có thể thấy nó sẽ ảnh hưởng như thế nào khi bạn mở rộng quy mô. Các giá trị chứng khoán hiển thị trên trang không phải là chức năng quan trọng vì vậy chúng tôi tải nó dưới dạng tài nguyên thứ cấp sau khi tải mà không ảnh hưởng đến người dùng. Đó là một cổ phiếu đáng xấu hổ trong danh sách sản phẩm không phải là một tính năng mặc định.
john-jh

1
Vâng, tôi đang chơi với ý tưởng bây giờ để lấy nó trực tiếp từ Redis và cắt bỏ php. Có một số công việc thực sự thú vị ở đây của Yichun Zhang trên Resty mở .
Melvyn

2

Tôi thấy bây giờ bạn đã chấp nhận và không nghi ngờ gì đã triển khai một cái gì đó, tuy nhiên tôi muốn chỉ ra mức độ thân thiết của bạn addInventoryDataToCollection()nhưng có vẻ như bạn đã trích dẫn sai tệp cấu hình hoặc chúng tôi đang sử dụng các phiên bản magento rất khác nhau. Bản sao của tôi CatalogInventory/etc/config.xmlcó một phương pháp khác được gọi làcatalog_product_collection_load_after

 <catalog_product_collection_load_after>
    <observers>
        <inventory>
            <class>cataloginventory/observer</class>
            <method>addStockStatusToCollection</method>
        </inventory>
    </observers>
 </catalog_product_collection_load_after>

addInventoryDataToCollection() được gọi trong <sales_quote_item_collection_products_after_load>

Nguồn cho addStockStatusToCollection()là:

public function addStockStatusToCollection($observer)
{
    $productCollection = $observer->getEvent()->getCollection();
    if ($productCollection->hasFlag('require_stock_items')) {
        Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection);
    } else {
        Mage::getModel('cataloginventory/stock_status')->addStockStatusToProducts($productCollection);
    }
    return $this;
}

Bạn có thể đặt cờ require_stock_itemstrên bộ sưu tập trước khi được tải, có thể không dễ dàng cho khối phía sau danh sách danh mục hoặc bạn có thể gọi Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection)thủ công trên bộ sưu tập, sau khi đã tải xong. addItemsToProducts()lấy tất cả StockItems cho bạn và đính kèm chúng vào ProductCollection của bạn

public function addItemsToProducts($productCollection)
{
    $items = $this->getItemCollection()
        ->addProductsFilter($productCollection)
        ->joinStockStatus($productCollection->getStoreId())
        ->load();
    $stockItems = array();
    foreach ($items as $item) {
        $stockItems[$item->getProductId()] = $item;
    }
    foreach ($productCollection as $product) {
        if (isset($stockItems[$product->getId()])) {
            $stockItems[$product->getId()]->assignProduct($product);
        }
    }
    return $this;
}

1

Bạn có đang sử dụng Varnish hoặc FPC không, hoặc dự định trong tương lai?

Chúng tôi đã tìm thấy với số lượng lỗ bấm / yêu cầu ESI được yêu cầu trong danh sách sản phẩm, hầu như không đáng để đặt bộ nhớ đệm vào vị trí nên đã chọn cách tiếp cận khác.

Chúng tôi đã triển khai một giải pháp trên một trang web sử dụng yêu cầu AJAX cho bộ điều khiển tùy chỉnh để truy xuất dữ liệu chứng khoán cho các sản phẩm và javascript xử lý các bản cập nhật DOM. Yêu cầu bổ sung cho dữ liệu chứng khoán mất ~ 100ms, điều này không ảnh hưởng đến thời gian tải trang tổng thể (hiển thị). Kết hợp với FPC được mồi sẵn, giảm yêu cầu trang xuống dưới 100ms, bạn có một trang web nhanh với chi phí hiệu suất thấp để hiển thị dữ liệu chứng khoán trên danh sách sản phẩm.

Tất cả những gì bạn cần làm là khôn ngoan mẫu là thêm sản phẩmId vào mỗi gói sản phẩm html để javascript của bạn biết dữ liệu chứng khoán nào sẽ áp dụng cho mỗi sản phẩm.

Nếu bạn xem xét các kỹ thuật lưu trữ bổ sung cho dữ liệu chứng khoán thực tế, bạn có thể giảm xuống dưới 100ms bằng cách không phải khởi tạo Mage / nhấn cơ sở dữ liệu theo từng yêu cầu.

Xin lỗi nếu điều này không phù hợp với những gì bạn đang tìm kiếm nhưng chúng tôi thấy đó là cách tiếp cận tốt nhất cho khả năng mở rộng và hiệu suất so với yêu cầu của chúng tôi.


2
Triển khai khỉ hỗn loạn và xem điều gì sẽ xảy ra khi bộ nhớ cache của bạn bị đổ. Câu hỏi đặc biệt đề cập đến việc không dựa vào bộ nhớ cache. Chính những câu trả lời như thế này khiến công việc của chúng tôi thuyết phục khách hàng rằng FPC sẽ không khắc phục khuôn mẫu BuildIn / MomsBasement của họ khó khăn hơn nhiều.
Melvyn

Bạn thực sự hiểu sai câu trả lời của tôi nếu bạn nghĩ rằng tôi đang đề xuất FPC / Varnish cho hiệu suất và là giải pháp. Tôi đã tuyên bố NẾU họ đang sử dụng hoặc xem xét FPC / Vanish, họ nên điều tra phương pháp này để giảm các cú đấm lỗ / yêu cầu ESI. Chúng tôi đang nhận được dữ liệu chứng khoán mà chúng tôi yêu cầu trong vòng dưới 100ms mà không cần lưu trữ bộ đệm.
john-jh 24/2/2015

Và bạn sẽ nhận được cùng một dữ liệu trong cùng một lúc bằng ESI. Cách tiếp cận của bạn với ESI về cơ bản là khác nhau. Và do đó, không có bất kỳ bộ đệm nào, bạn vẫn có thể nhận được cùng một dữ liệu, trong thời gian ngắn hơn. Thay vì đi qua một bộ định tuyến khác để gửi lại JSON, bạn viết một mảng stock bằng JavaScript cập nhật DOM, v.v. Hell, đặt nó vào JSON nếu bạn muốn, chỉ cần cắt bỏ bộ định tuyến.
Melvyn

1
Bộ nhớ đệm sẽ được sử dụng nhưng câu hỏi là nhiều hơn về các tối ưu hóa hiệu suất. Một số nền tảng: magento.stackexchange.com/questions/13957/ cường (không có bộ nhớ cache / hầu như không) Cảm ơn bạn đã trả lời, tuy nhiên, đánh giá cao đầu vào!
B00mer

Không chắc chắn liệu có cách "thực hành tốt nhất" nào trong M2 hay không, nhưng giải pháp của bạn là cách chúng tôi luôn thực hiện nó kể từ Magento 1.x.
thdoan
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.