Я осмотрел ядро и увидел несколько примеров множества отношений между моделями, но я не вижу однозначного ответа на этот вопрос.
В качестве примера, скажем, мы создаем новую модель, и мы хотим иметь связь «многие ко многим» с существующей таблицей продуктов.
Итак, у нас есть наша новая Модель - Stockist, и мы создаем 2 таблицы как таковые: одну для хранения имени Stockist, другую для хранения связи многих со многими продуктами.
Усеченная версия классов настройки:
$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');
Затем мы создаем стандартную модель / ResourceModel / Collection для Stockist следующим образом:
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');
}
}
Здесь мы подходим к тому, как обращаться со столом с отношениями «многие ко многим». До сих пор я придумал что-то подобное.
Создать модель для представления 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);
}
}
Здесь определены 2 метода, которые будут принимать либо массив идентификаторов запаса, возвращая массив совпадающих идентификаторов продукта, и наоборот.
При этом используется модель ресурсов для таблицы stockist_product, содержащей отношение многие ко многим:
/**
* 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;
}
}
Затем используйте эту модель StockistProduct, когда вам нужно получить набор любой из этих моделей, предположив, что у нас есть Product Model в $ product, а $ stockistProduct является экземпляром \ OurModule \ Stockist \ Model \ StockistProduct
$stockists = $stockistProduct->getStockists([$product->getId()]);
Затем мы можем создать каждую модель по очереди, зациклив список возвращенных идентификаторов, как показано ниже, где $ stockistFactory является экземпляром \ OurModule \ Stockist \ Model \ StockistFactory
$stockist = $this->stockistFactory->create();
$stockist->load($stockistId);
Все это прекрасно работает и основано на некотором подобном коде в ядре Magento 2, но я не могу не задаться вопросом, есть ли лучший способ?
Ответы:
Я реализовал решение, подобное этому. Для каждой SKU была указана информация о соответствии: год, марка, модель автомобиля, к которому можно применить продукт (автомобильный аксессуар). На первый взгляд, это будет проще всего с нативными атрибутами Magento. Просто используйте три текстовых поля, одно для года, одно для марки, одно для модели. Это позволяет использовать все встроенные функции Magento, такие как поиск и фильтрация по этим атрибутам, а также легко обновлять их в будущем.
Проблема, как вы описываете, заключается в том, что нам нужно «много» из этих отношений. Мы могли бы сделать 30 текстовых атрибутов: год1, год1, модель1, год2, год2, модель2, ... год10, год10, модель10. Это а) скорее всего оставит много пустых атрибутов, и б) создаст искусственное ограничение на количество автомобилей, которые поддерживает продукт.
Что может сработать, примерно так:
И тогда после нажатия на плюс (+) вы увидите:
Такой пользовательский интерфейс может быть реализован с помощью javascript внутри шаблона темы с поддержкой. После отправки формы вам необходимо будет предоставить эти данные в Magento в качестве атрибутов продукта. Я не думаю, что в настоящее время существует тип атрибута, который поддерживает динамическую длину. Вы будете реализовывать пользовательский тип атрибута. Опять же, это обеспечивает поддержку встроенной функциональности Magento: поиск по введенным атрибутам, простое обновление этих атрибутов в будущем.
В итоге наш клиент принял решение сэкономить деньги, не реализовав это «простое редактирование», и вместо этого мы заблокировали данные в пользовательской таблице, как вы описали. У меня есть собственный скрипт импорта, который принимает входные и выходные данные CSV в таблицу. Позже страница продукта (ну, его блок) делает запросы к этой таблице, извлекает информацию о его SKU и отображает для пользователя в виде таблицы. Эта таблица страниц продукта была желательным поведением клиента, поэтому для нас не было смысла копаться в том, чтобы сделать это «Путь Magento» и реализовать атрибут переменной-члена.
источник