Apa cara praktik terbaik di Magento 2 untuk menciptakan hubungan Many To Many?


15

Saya telah melihat-lihat inti dan melihat beberapa contoh banyak ke banyak hubungan antara model, tetapi saya tidak dapat melihat jawaban yang pasti tentang ini.

Sebagai contoh, katakanlah kita membuat model baru dan kami ingin memiliki hubungan banyak ke banyak dengan tabel produk yang ada.

Jadi kami memiliki Model baru kami - Stockist, dan kami membuat 2 tabel dengan demikian, satu untuk menyimpan nama Stockist, yang lain untuk menyimpan banyak ke banyak hubungan dengan produk.

Versi kelas penyiapan yang terpotong:

$table = $setup->getConnection()
        ->newTable($installer->getTable('stockist'))
        ->addColumn('stockist_id',
            \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
            null,
            ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
            'Stockist Id')
        ->addColumn('name',
            \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            null,
            ['nullable' => false],
            'Stockist Name');

 $table = $installer->getConnection()
            ->newTable($installer->getTable('stockist_product'))
            ->addColumn(
                'entity_id',
                \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                null,
                ['identity' => true, 'nullable' => false, 'primary' => true],
                'Entity ID'
            )
            ->addColumn(
                'stockist_id',
                \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                null,
                ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
                'Stockist ID'
            )
            ->addColumn(
                'product_id',
                \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                null,
                ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
                'Product ID'
            )
            ->addIndex(
                $installer->getIdxName('stockist_product', ['product_id']),
                ['product_id']
            )
            ->addIndex(
                $installer->getIdxName(
                    'stockist_product,
                    ['stockist_id', 'product_id'],
                    \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE
                ),
                ['stockist_id', 'product_id'],
                ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE]
            )
            ->addForeignKey(
                $installer->getFkName('stockist_product', 'product_id', 'catalog_product_entity', 'entity_id'),
                'product_id',
                $installer->getTable('catalog_product_entity'),
                'entity_id',
                \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
            )
            ->addForeignKey(
                $installer->getFkName('stockist_product', 'stockist_id', 'stockist', 'stockist_id'),
                'stockist_id',
                $installer->getTable('stockist'),
                'stockist_id',
                \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
            )
            ->setComment('Stockist to Product Many to Many');

Kemudian kami membuat Model / ResourceModel / Collection untuk Stockist standar sebagai berikut:

namespace OurModule\Stockist\Model;

use Magento\Framework\Model\AbstractModel;

class Stockist extends AbstractModel
{

    protected function _construct()
    {
        $this->_init('OurModule\Stockist\Model\ResourceModel\Stockist');
    }

}

namespace OurModule\Stockist\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Stockist extends AbstractDb
{

    protected function _construct()
    {
        $this->_init('stockist', 'stockist_id');
    }

}

namespace OurModule\Stockist\Model\ResourceModel\Stockist;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;

class Collection extends AbstractCollection
{

    public function _construct()
    {
        $this->_init('OurModule\Stockist\Model\Stockist', 'OurModule\Stockist\Model\ResourceModel\Stockist');
    }

}

Di sinilah kita sampai pada bagaimana menangani tabel dengan banyak ke banyak hubungan. Sejauh ini saya telah menemukan sesuatu di sepanjang garis ini.

Buat model untuk mewakili StockistProduct

namespace OurModule\Stockist\Model;

use Magento\Framework\Model\AbstractModel;

class StockistProduct extends AbstractModel
{

protected function _construct()
{
    $this->_init('OurModule\Stockist\Model\ResourceModel\StockistProduct');
}

/**
 * @param array $productIds
 */
public function getStockists($productIds)
{
    return $this->_getResource()->getStockists($productIds);
}

/**
 * @param array $stockistIds
 */
public function getProducts($stockistIds)
{
    return $this->_getResource()->getProducts($stockistIds);
}
}

Di sini mendefinisikan 2 metode yang akan menggunakan array Id stokis, mengembalikan array Id Produk yang cocok dan sebaliknya.

Ini menggunakan Model Sumber Daya untuk tabel stockist_product yang berisi hubungan many to many:

/**
 * Class StockistProduct
 */
class StockistProduct extends AbstractDb
{
    /**
     * Model initialization
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('stockist_product', 'entity_id');
    }

    /**
     * Retrieve product stockist Ids
     *
     * @param array $productIds
     * @return array
     */
    public function getStockists(array $productIds)
    {
        $select = $this->getConnection()->select()->from(
            $this->getMainTable(),
            ['product_id', 'stockist_id']
        )->where(
            'product_id IN (?)',
            $productIds
        );
        $rowset = $this->getConnection()->fetchAll($select);

        $result = [];
        foreach ($rowset as $row) {
            $result[$row['product_id']][] = $row['stockist_id'];
        }

        return $result;
    }


    /**
     * Retrieve stockist product Ids
     *
     * @param array $stockistIds
     * @return array
     */
    public function getProducts(array $stockistIds)
    {
        $select = $this->getConnection()->select()->from(
            $this->getMainTable(),
            ['product_id', 'stockist_id']
        )->where(
            'stockist_id IN (?)',
            $stockistIds
        );
        $rowset = $this->getConnection()->fetchAll($select);

        $result = [];
        foreach ($rowset as $row) {
            $result[$row['product_id']][] = $row['stockist_id'];
        }

        return $result;
    }
}

Kemudian gunakan model StockistProduct ini ketika Anda perlu mengambil satu set model dari keduanya, dengan asumsi kita memiliki Model Produk dalam $ produk, dan $ stockistProduct adalah turunan dari \ OurModule \ Stockist \ Model \ StockistProduct

$stockists = $stockistProduct->getStockists([$product->getId()]);

Kita kemudian dapat membuat masing-masing model secara bergiliran dengan mengulang daftar Id yang dikembalikan seperti itu, di mana $ stockistFactory adalah turunan dari \ OurModule \ Stockist \ Model \ StockistFactory

$stockist = $this->stockistFactory->create();
$stockist->load($stockistId);

Ini semua berfungsi dengan baik, dan didasarkan pada beberapa kode yang serupa di dalam Core of Magento 2, tetapi saya tidak bisa tidak bertanya-tanya apakah ada cara yang lebih baik?


Saya harus melakukan sesuatu yang sangat mirip ... dan ini adalah satu-satunya ide yang saya punya, jika tidak ada jawaban :(
slayerbleast

Jawaban:


1

Saya menerapkan solusi yang mirip dengan ini. Untuk setiap SKU, ada informasi "kesesuaian": tahun, merek, model mobil yang dapat digunakan produk (aksesori mobil). Pada permukaannya, ini akan lebih mudah dengan atribut asli Magento. Cukup gunakan tiga bidang teks, satu untuk tahun, satu untuk make, satu untuk model. Ini memungkinkan semua fungsionalitas Magento bawaan, seperti mencari dan memfilter dengan atribut ini, bersama dengan pembaruan yang mudah di masa depan.

Masalahnya, seperti yang Anda jelaskan, adalah bahwa kita membutuhkan "banyak" hubungan ini. Kita dapat membuat 30 atribut teks: year1, make1, model1, year2, make2, model2, ... year10, make10, model10. Ini akan a) kemungkinan meninggalkan banyak atribut kosong, dan b) membuat batas buatan pada jumlah mobil yang didukung produk.

Yang bisa berhasil adalah sesuatu seperti ini:

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

Dan kemudian setelah mengklik tanda tambah (+) Anda akan melihat:

Year: ____
Make: ____
Model: ____

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

UI seperti itu dapat diimplementasikan dengan javascript di dalam template tema yang didukung. Setelah mengirimkan formulir, Anda harus memberikan data ini ke Magento sebagai atribut produk. Saya tidak berpikir saat ini ada tipe atribut yang mendukung panjang dinamis. Anda akan menerapkan tipe atribut khusus. Sekali lagi, ini memberikan dukungan dari fungsionalitas Magento bawaan: mencari atribut yang dimasukkan, pembaruan yang mudah untuk atribut ini di masa mendatang.

Pada akhirnya, klien kami membuat keputusan untuk menghemat uang dengan tidak menerapkan "penyuntingan mudah" ini, dan sebaliknya kami mengunci data dalam tabel khusus, seperti yang Anda jelaskan. Saya memiliki skrip impor khusus yang mengambil input dan output CSV ke tabel. Kemudian, halaman produk (yah, blokirnya) membuat kueri ke tabel ini, mengeluarkan info tentang SKU-nya, dan ditampilkan kepada pengguna sebagai tabel. Tabel halaman produk ini adalah perilaku yang diinginkan dari klien, jadi bagi kami tidak masuk akal untuk melakukannya "The Magento Way" dan menerapkan atribut variabel-anggota.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.