Kinerja: Tambahkan Tingkat Stok Persediaan di daftar listing produk. Php dari semua jenis produk

12

TL; DR , Persyaratannya adalah memiliki tingkat persediaan persediaan ditampilkan pada halaman daftar produk kategori dengan sedikit pertanyaan tambahan / memori dengan kinerja dalam pikiran yang mematuhi kerangka kerja Magento.


Setelah membaca artikel Vinai Kopp tentang preloading untuk skalabilitas .

Apa cara terbaik untuk memasukkan level persediaan inventaris pada halaman daftar produk kategori ( list.phtml ) dengan sedikit pertanyaan / beban tambahan untuk kinerja?

Saya mengetahui beberapa pendekatan:

afterLoad () tampaknya berfungsi dengan baik denganmedia_gallerypenyertaan tanpa permintaan tambahan, namun saya belum berhasil menerapkan pendekatan yang sama dengan inventaris.

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

SQL langsung untuk mengumpulkan data yang diperlukan secara paralel dengan pengumpulan dengan product_idkunci misalnya. Tetapi mencari lebih banyak sarana melalui kerangka kerja.

Saat ini saya hanya memuat stock_itemobjek melalui:

$_product->load('stock_item')->getTotalQty(); Yang berhasil, tapi saya perhatikan penambahan lebih banyak permintaan untuk mendapatkan total stok persediaan dari semua produk dalam koleksi.

...

__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)

...

anehnya, ini berhasil. Keajaiban terjadi di Mage_Eav_Model_Entity_Abstract-> memuat ($ objek, $ entitasId, $ atribut). Jika $ atribut kosong itu akan memanggil loadAllAttribute ($ objek). Jadi $ product-> load ('blah') akan memuat semua atribut yang hilang, termasuk 'media_gallery' - William Tran 19 Nov 14 pada jam 4:45

Tambahkan nilai yang diperlukan ke koleksi yang sudah dimuat.

Pendekatan sederhana yang jelas untuk menambahkan data yang diperlukan ke koleksi produksi tingkat atas di lapisan / filter, tampaknya akan menjadi pendekatan terbaik.

Saya memang melihat pengamat addInventoryDataToCollection () di Mage_CatalogInventory_Model_Observer yang kedengarannya akan mencapai itu, tetapi menambahkan metode ke pengamat modul khusus tampaknya tidak kompatibel.

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

Yang mengakibatkan:

Peringatan: Argumen tidak valid diberikan untuk foreach () di /app/code/core/Mage/CatalogInventory/Model/Resource/Stock/Item/Collection.php on line 71

B00MER
sumber
1
Boomer pertanyaan bagus
Amit Bera

Jawaban:

4

Masalah sebenarnya di sini bukan preloading, ini akurasinya. Ini relatif mudah untuk mendapatkan jumlah stok untuk koleksi produk:

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

Sekarang dengan dua pertanyaan, Anda memiliki semua informasi yang Anda butuhkan. Mereka hanya sulit untuk berhubungan satu sama lain, yang dapat diperbaiki dengan menggunakan array asosiatif 'product_id' => 'stock'dan menulis pengambil. Juga, addProductsFilter dapat dioptimalkan:

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

Ini menghemat jenis cek dan array kloning.

Masalahnya sekarang adalah Blok HTML cache. Halaman kategori ini perlu dibersihkan ketika stok apa pun diperbarui pada produk yang terkandung di dalamnya. Sejauh yang saya tahu, ini bukan standar, karena hanya perubahan status stok membersihkan halaman kategori yang berisi produk (atau lebih tepatnya, perubahan visibilitas). Jadi, Anda harus mengamati setidaknya cataloginventory_stock_item_before_savedan mungkin beberapa orang lain dan membersihkan blok html cache (dan FPC cache) untuk halaman kategori itu.

Melvyn
sumber
Poin terakhir Anda adalah alasan kami meminta tambahan permintaan untuk mengambil data stok. Jika Anda memiliki kategori dengan produk yang bergerak cepat, cache Anda akan menghabiskan sebagian besar waktunya untuk dihapus / tidak valid. satu-satunya waktu kita perlu membersihkan cache halaman kategori adalah jika suatu produk dihapus dari kategori itu. Tidak ada satu solusi ajaib yang harus Anda selesaikan dengan implementasi yang paling efisien berdasarkan kasus per kasus. Jika Anda mau, Anda bisa menyimpan data stok sehingga hanya yang harus dibangun kembali setelah dibilas daripada seluruh halaman.
john-jh
Jika Anda menerapkan data stok dengan cara yang sama seperti yang Anda lakukan sekarang, menggunakan data JavaScript untuk memperbarui DOM, Anda dapat menulisnya menggunakan blok dengan kunci cache sendiri dan hanya membatalkan data stok. Ini adalah bagaimana saya akan melakukannya untuk situasi Anda dan tidak menggunakan FPC berbasis ESI, tetapi yang dapat melubangi blok di prosesor permintaan. Tidak hanya untuk bit router, tetapi juga untuk hanya membutuhkan satu penerjemah php per halaman. Ketika sebuah mesin mendapat tekanan karena alasan apa pun, penerjemah php Anda adalah sumber daya paling intensif Cpu. Ini mulai terdengar semakin seperti proyek akhir pekan yang menyenangkan ;-)
Melvyn
3
Ini adalah jenis barang yang membuat pekerjaan itu sangat menarik di mana Anda harus benar-benar memikirkan implementasi dan potensi masalah serta hambatannya. Saya menantang melihat dari mana Anda berasal dengan proses PHP tunggal ini saat ini bukan masalah bagi kami tetapi dapat melihat bagaimana hal itu akan berdampak pada skala Anda. Nilai stok yang ditampilkan pada halaman bukanlah fungsi yang kritis sehingga kami memuatnya sebagai sumber daya sekunder setelah dimuat tanpa memengaruhi pengguna. Ini memalukan stok pada daftar produk bukan fitur default.
john-jh
1
Ya, saya bermain dengan ide sekarang untuk mengambil ini dari Redis secara langsung dan memotong php. Ada beberapa karya yang sangat menarik di sini oleh Yichun Zhang di Resty terbuka .
Melvyn
2

Saya melihat Anda sudah menerima dan sudah pasti mengimplementasikan sesuatu sekarang, namun saya ingin menunjukkan seberapa dekat Anda dengan addInventoryDataToCollection()tetapi sepertinya Anda salah mengutip file konfigurasi atau kami menggunakan versi magento yang sangat berbeda. Salinan saya CatalogInventory/etc/config.xmlmemiliki metode berbeda yang diperlukancatalog_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() dipanggil <sales_quote_item_collection_products_after_load>

Sumbernya addStockStatusToCollection()adalah:

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

Anda bisa mengatur bendera require_stock_itemspada koleksi sebelum dimuat, mungkin tidak mudah untuk blok di belakang daftar kategori, atau Anda dapat memanggil Mage::getModel('cataloginventory/stock')->addItemsToProducts($productCollection)secara manual pada koleksi, setelah sudah dimuat. addItemsToProducts()dapatkan semua StockItems untuk Anda dan tempelkan ke ProductCollection Anda

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;
}
Richard
sumber
1

Apakah Anda menggunakan Varnish atau FPC sama sekali, atau berencana untuk di masa depan?

Kami menemukan dengan jumlah permintaan hole punch / ESI yang diperlukan pada daftar produk, hampir tidak ada gunanya melakukan caching sehingga memilih pendekatan yang berbeda.

Kami menerapkan solusi pada satu situs web yang menggunakan permintaan AJAX ke pengontrol khusus untuk mengambil data stok untuk produk dan javascript menangani pembaruan DOM. Permintaan tambahan untuk data stok membutuhkan ~ 100 ms yang tidak berdampak pada keseluruhan waktu pemuatan halaman (terlihat). Pasangan yang dengan FPC prima menjatuhkan permintaan halaman ke bawah di bawah 100 ms, Anda memiliki satu situs cepat dengan overhead kinerja rendah untuk menampilkan data stok pada daftar produk.

Yang perlu Anda lakukan template bijaksana adalah menambahkan productId ke setiap produk html pembungkus sehingga javascript Anda tahu data stok mana yang berlaku untuk setiap produk.

Jika Anda melihat teknik caching tambahan untuk data stok aktual Anda bisa menjatuhkan yang jauh di bawah 100 ms dengan tidak harus init Mage / tekan database pada setiap permintaan.

Maaf jika ini tidak sesuai dengan apa yang Anda cari, tetapi kami menemukan itu sebagai pendekatan terbaik untuk skalabilitas dan kinerja terhadap persyaratan kami.

john-jh
sumber
2
Menyebarkan kekacauan monyet dan melihat apa yang terjadi ketika penyimpanan cache Anda jatuh. Pertanyaannya secara khusus menyebutkan untuk tidak bergantung pada cache. Jawaban seperti ini yang membuat pekerjaan kami meyakinkan klien bahwa FPC tidak akan memperbaiki templat BuiltIn / MomsBasement mereka jauh lebih sulit.
Melvyn
Anda benar-benar salah mengerti jawaban saya jika Anda pikir saya menyarankan FPC / Varnish untuk kinerja dan sebagai solusinya. Saya menyatakan JIKA mereka menggunakan atau mempertimbangkan FPC / Lenyap, mereka harus menyelidiki pendekatan ini untuk mengurangi lubang pukulan / permintaan ESI. Kami mendapatkan data stok yang kami butuhkan di bawah 100ms tanpa cache leaveraging.
john-jh
Dan Anda akan mendapatkan data yang sama dalam waktu yang sama menggunakan ESI. Pendekatan Anda dengan ESI hanya berbeda secara mendasar. Jadi, tanpa cache apa pun Anda masih bisa mendapatkan data yang sama, dalam waktu yang lebih singkat. Alih-alih melalui router lain untuk mengirim kembali JSON, Anda menulis array stok dalam JavaScript yang memperbarui DOM, dll. Sial, masukkan ke dalam JSON jika Anda mau, cukup potong router.
Melvyn
1
Caching akan digunakan tetapi pertanyaannya lebih pada garis optimasi kinerja. Beberapa latar belakang: magento.stackexchange.com/questions/13957/… (tidak ada cache / hampir tidak ada) Terima kasih atas jawabannya, menghargai masukan!
B00MER
Tidak yakin apakah ada cara "praktik terbaik" dalam melakukan ini dalam M2, tetapi solusi Anda adalah bagaimana kami selalu melakukannya sejak Magento 1.x.
thdoan