Was ist die beste Vorgehensweise in Magento 2 zum Erstellen von Viele-zu-Viele-Beziehungen?


15

Ich habe mich im Kern umgesehen und einige Beispiele für viele bis viele Beziehungen zwischen Modellen gesehen, aber ich sehe keine endgültige Antwort darauf.

Nehmen wir zum Beispiel an, wir erstellen ein neues Modell und möchten eine viel zu viele Beziehung zur vorhandenen Produkttabelle haben.

Wir haben also unser neues Model - Stockist und erstellen zwei Tabellen, eine zum Speichern des Stockist - Namens, die andere zum Speichern der vielen zu vielen Beziehungen zu Produkten.

Verkürzte Version der Setup-Klassen:

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

Dann erstellen wir ein Standardmodell / ResourceModel / Collection für Stockist wie folgt:

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

}

Hier kommen wir zum Umgang mit dem Tisch in der Beziehung von vielen zu vielen. Bisher habe ich mir etwas in dieser Richtung ausgedacht.

Erstellen Sie ein Modell zur Darstellung von 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);
}
}

Hier werden zwei Methoden definiert, die entweder eine Reihe von Händler-IDs aufnehmen und eine Reihe von übereinstimmenden Produkt-IDs zurückgeben und umgekehrt.

Dies verwendet ein Ressourcenmodell für die Tabelle stockist_product, die die Beziehung many to many enthält:

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

Verwenden Sie dieses StockistProduct-Modell dann, wenn Sie einen Satz beider Modelle abrufen müssen, vorausgesetzt, wir haben ein Produktmodell in $ product und $ stockistProduct ist eine Instanz von \ OurModule \ Stockist \ Model \ StockistProduct

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

Wir können dann jedes Modell der Reihe nach erstellen, indem wir die Liste der zurückgegebenen IDs durchlaufen, wobei $ stockistFactory eine Instanz von \ OurModule \ Stockist \ Model \ StockistFactory ist

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

Das alles funktioniert gut und basiert auf einem ähnlichen Code im Core von Magento 2, aber ich frage mich, ob es einen besseren Weg gibt.


Ich muss etwas sehr ähnliches tun ... und das ist die einzige Idee, die ich habe, wenn es keine Antworten gibt :(
Slayerbleast

Antworten:


1

Ich habe eine ähnliche Lösung implementiert. Für jede SKU gab es "Einbau" -Informationen: Jahr, Marke, Modell eines Autos, auf das das Produkt (Autozubehör) angewendet werden konnte. Auf den ersten Blick ist dies mit nativen Magento-Attributen am einfachsten. Verwenden Sie einfach drei Textfelder, eines für das Jahr, eines für die Marke und eines für das Modell. Dies ermöglicht alle integrierten Magento-Funktionen, wie das Suchen und Filtern mit diesen Attributen, sowie eine einfache Aktualisierung in der Zukunft.

Das Problem ist, wie Sie beschreiben, dass wir "viele" dieser Beziehungen brauchen. Wir könnten 30 Textattribute erstellen: year1, make1, model1, year2, make2, model2, ... year10, make10, model10. Dies würde a) wahrscheinlich viele leere Attribute hinterlassen und b) die Anzahl der von einem Produkt unterstützten Autos künstlich begrenzen.

Was funktionieren könnte, ist etwa so:

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

Und nachdem Sie auf das Pluszeichen (+) geklickt haben, wird Folgendes angezeigt:

Year: ____
Make: ____
Model: ____

Year: ____
Make: ____
Model: ____

Add new YearMakeModel relationship (+)

Eine solche Benutzeroberfläche könnte mit Javascript in einer Vorlage für ein unterstütztes Thema implementiert werden. Nach dem Absenden des Formulars müssten Sie Magento diese Daten als Produktattribute zur Verfügung stellen. Ich glaube nicht, dass es derzeit einen Attributtyp gibt, der eine dynamische Länge unterstützt. Sie würden einen benutzerdefinierten Attributtyp implementieren. Auch dies bietet Unterstützung durch die integrierte Magento-Funktionalität: Suche nach eingegebenen Attributen, einfache Aktualisierung für diese Attribute in der Zukunft.

Am Ende hat unser Kunde die Entscheidung getroffen, Geld zu sparen, indem er diese "einfache Bearbeitung" nicht implementiert hat. Stattdessen haben wir die Daten in einer benutzerdefinierten Tabelle gesperrt, so wie Sie es beschreiben. Ich habe ein benutzerdefiniertes Importskript, das CSV-Ein- und Ausgaben in die Tabelle übernimmt. Später führt die Produktseite (also ihr Block) Abfragen an dieser Tabelle durch, ruft die Informationen zu ihrer SKU ab und zeigt sie dem Benutzer als Tabelle an. Diese Produktseitentabelle war das vom Kunden gewünschte Verhalten, daher war es für uns nicht sinnvoll, in "The Magento Way" zu graben und ein Attribut mit variablen Elementen zu implementieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.