Qual è il modo migliore in Magento 2 per creare relazioni Many To Many?


15

Mi sono guardato attorno e ho visto alcuni esempi di molte o molte relazioni tra i modelli, ma non riesco a vedere una risposta definitiva su questo.

Ad esempio, supponiamo che creiamo un nuovo modello e desideriamo avere molte o molte relazioni con la tabella dei prodotti esistenti.

Quindi abbiamo il nostro nuovo modello - Stockista e creiamo 2 tabelle come tali, una per memorizzare il nome del rivenditore, l'altra per memorizzare le molte o molte relazioni con i prodotti.

Versione troncata delle classi di installazione:

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

Quindi creiamo un modello standard / ResourceModel / Collection per Stockist in questo modo:

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

}

Qui è dove arriviamo a come gestire la tabella con la relazione molti a molti. Finora ho escogitato qualcosa del genere.

Crea un modello per rappresentare 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);
}
}

Qui vengono definiti 2 metodi che includeranno una matrice di ID stockist, restituendo una matrice di ID prodotto corrispondenti e viceversa.

Questo utilizza un modello di risorsa per la tabella stockist_product contenente la relazione molti a molti:

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

Quindi utilizzare questo modello StockistProduct quando è necessario recuperare un set di entrambi i modelli in questo modo, supponendo che abbiamo un modello prodotto in $ product e $ stockistProduct sia un'istanza di \ OurModule \ Stockist \ Model \ StockistProduct

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

È quindi possibile creare a turno ciascun modello eseguendo il ciclo dell'elenco di ID restituiti come tali, dove $ stockistFactory è un'istanza di \ OurModule \ Stockist \ Model \ StockistFactory

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

Tutto funziona bene e si basa su un codice simile all'interno del Core of Magento 2, ma non posso fare a meno di chiedermi se esiste un modo migliore?


Devo fare qualcosa di molto simile ... e questa è l'unica idea che ho, se non ci sono risposte :(
slayerbleast

Risposte:


1

Ho implementato una soluzione simile a questa. Per ogni SKU c'erano informazioni di "montaggio": anno, marca, modello di un'auto a cui il prodotto (accessorio per auto) poteva essere applicato. A prima vista, questo sarebbe più semplice con gli attributi nativi di Magento. Basta usare tre campi di testo, uno per anno, uno per make, uno per modello. Ciò consente tutte le funzionalità integrate di Magento, come la ricerca e il filtro con questi attributi, nonché un facile aggiornamento in futuro.

Il problema, come descrivi, è che abbiamo bisogno di "molte" di queste relazioni. Potremmo creare 30 attributi di testo: year1, make1, model1, year2, make2, model2, ... year10, make10, model10. Ciò a) probabilmente lascerebbe molti attributi vuoti e b) creerebbe un limite artificiale al numero di auto supportate da un prodotto.

Ciò che potrebbe funzionare è qualcosa del genere:

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

E dopo aver fatto clic sul segno più (+) vedresti:

Year: ____
Make: ____
Model: ____

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

Tale interfaccia utente potrebbe essere implementata con javascript all'interno di un modello tematico supportato. Al momento dell'invio del modulo, è necessario fornire questi dati a Magento come attributi del prodotto. Non credo ci sia attualmente un tipo di attributo che supporti una lunghezza dinamica. Stai implementando un tipo di attributo personalizzato. Ancora una volta, questo fornisce supporto dalla funzionalità integrata di Magento: ricerca degli attributi immessi, facile aggiornamento per questi attributi in futuro.

Alla fine, il nostro cliente ha preso la decisione di risparmiare denaro non implementando questa "modifica semplice", e invece abbiamo bloccato i dati in una tabella personalizzata, proprio come tu descrivi. Ho uno script di importazione personalizzato che porta input e output CSV al tavolo. Successivamente, la pagina del prodotto (beh, il suo blocco) fa una query a questa tabella, estrae le informazioni sul suo SKU e viene visualizzata all'utente come una tabella. Questa tabella di pagine del prodotto era il comportamento desiderato dal client, quindi per noi non aveva senso scavare nel farlo "The Magento Way" e implementare un attributo a membro variabile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.