Ответы:
Предполагая, что у вас есть модуль без отношения продукта здесь, это то, что вам нужно в дополнение.
Сначала создайте таблицу отношений между вашей сущностью и продуктами. Добавьте это config.xml
внутриglobal/models/[module]_resource/entities
<[entity]_product>
<table>[entity]_product</table>
</[entity]_product>
Добавьте это в один из upgrade scripts.
$table = $this->getConnection()
->newTable($this->getTable('[module]/[entity]_product'))
->addColumn('rel_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'unsigned' => true,
'identity' => true,
'nullable' => false,
'primary' => true,
), 'Relation ID')
->addColumn('[entity]_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'unsigned' => true,
'nullable' => false,
'default' => '0',
), '[Entity] ID')
->addColumn('product_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'unsigned' => true,
'nullable' => false,
'default' => '0',
), 'Product ID')
->addColumn('position', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'nullable' => false,
'default' => '0',
), 'Position')
->addIndex($this->getIdxName('[module]/[entity]_product', array('product_id')), array('product_id'))
->addForeignKey($this->getFkName('[module]/[entity]_product', '[entity]_id', '[module]/[entity]', 'entity_id'), '[entity]_id', $this->getTable('[module]/[entity]'), 'entity_id', Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
->addForeignKey($this->getFkName('[module]/[entity]_product', 'product_id', 'catalog/product', 'entity_id'), 'product_id', $this->getTable('catalog/product'), 'entity_id', Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
->setComment('[Entity] to Product Linkage Table');
$this->getConnection()->createTable($table);
Теперь создайте блок сетки. [Namespace]/[Module]/Block/Adminhtml/[Entity]/Edit/Tab/Product.php
<?php
class [Namespace]_[Module]_Block_Adminhtml_[Entity]_Edit_Tab_Product
extends Mage_Adminhtml_Block_Widget_Grid {
public function __construct(){
parent::__construct();
$this->setId('product_grid');
$this->setDefaultSort('position');
$this->setDefaultDir('ASC');
$this->setUseAjax(true);
if ($this->get[Entity]()->getId()) {
$this->setDefaultFilter(array('in_products'=>1));
}
}
protected function _prepareCollection() {
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->addAttributeToSelect('price');
$adminStore = Mage_Core_Model_App::ADMIN_STORE_ID;
$collection->joinAttribute('product_name', 'catalog_product/name', 'entity_id', null, 'left', $adminStore);
if ($this->get[Entity]()->getId()){
$constraint = '{{table}}.[entity]_id='.$this->get[Entity]()->getId();
}
else{
$constraint = '{{table}}.[entity]_id=0';
}
$collection->joinField('position',
'[module]/[entity]_product',
'position',
'product_id=entity_id',
$constraint,
'left');
$this->setCollection($collection);
parent::_prepareCollection();
return $this;
}
protected function _prepareMassaction(){
return $this;
}
protected function _prepareColumns(){
$this->addColumn('in_products', array(
'header_css_class' => 'a-center',
'type' => 'checkbox',
'name' => 'in_products',
'values'=> $this->_getSelectedProducts(),
'align' => 'center',
'index' => 'entity_id'
));
$this->addColumn('product_name', array(
'header'=> Mage::helper('catalog')->__('Name'),
'align' => 'left',
'index' => 'product_name',
));
$this->addColumn('sku', array(
'header'=> Mage::helper('catalog')->__('SKU'),
'align' => 'left',
'index' => 'sku',
));
$this->addColumn('price', array(
'header'=> Mage::helper('catalog')->__('Price'),
'type' => 'currency',
'width' => '1',
'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
'index' => 'price'
));
$this->addColumn('position', array(
'header'=> Mage::helper('catalog')->__('Position'),
'name' => 'position',
'width' => 60,
'type' => 'number',
'validate_class'=> 'validate-number',
'index' => 'position',
'editable' => true,
));
}
protected function _getSelectedProducts(){
$products = $this->get[Entity]Products();
if (!is_array($products)) {
$products = array_keys($this->getSelectedProducts());
}
return $products;
}
public function getSelectedProducts() {
$products = array();
$selected = Mage::registry('current_[entity]')->getSelectedProducts();
if (!is_array($selected)){
$selected = array();
}
foreach ($selected as $product) {
$products[$product->getId()] = array('position' => $product->getPosition());
}
return $products;
}
public function getRowUrl($item){
return '#';
}
public function getGridUrl(){
return $this->getUrl('*/*/productsGrid', array(
'id'=>$this->get[Entity]()->getId()
));
}
public function get[Entity](){
return Mage::registry('current_[entity]');
}
protected function _addColumnFilterToCollection($column){
// Set custom filter for in product flag
if ($column->getId() == 'in_products') {
$productIds = $this->_getSelectedProducts();
if (empty($productIds)) {
$productIds = 0;
}
if ($column->getFilter()->getValue()) {
$this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds));
}
else {
if($productIds) {
$this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds));
}
}
}
else {
parent::_addColumnFilterToCollection($column);
}
return $this;
}
}
Теперь добавьте эту вкладку в список вкладок. В [Namespace]_[Module]_Block_Adminhtml_[Entity]_Edit_Tabs::_beforeToHtml
добавление это ниже основной вкладки.
$this->addTab('products', array(
'label' => Mage::helper('[module]')->__('Associated products'),
'url' => $this->getUrl('*/*/products', array('_current' => true)),
'class' => 'ajax'
));
Теперь вам нужны действия контроллера для обработки продуктов.
Добавьте эти методы в контроллер администратора для вашей сущности:
public function productsAction(){
$this->_initEntity(); //if you don't have such a method then replace it with something that will get you the entity you are editing.
$this->loadLayout();
$this->getLayout()->getBlock('[entity].edit.tab.product')
->set[Entity]Products($this->getRequest()->getPost('[entity]_products', null));
$this->renderLayout();
}
public function productsgridAction(){
$this->_init[Entity]();
$this->loadLayout();
$this->getLayout()->getBlock('[entity].edit.tab.product')
->set[Entity]Products($this->getRequest()->getPost('[entity]_products', null));
$this->renderLayout();
}
Теперь макет для этих 2-х действий. В файле макета администратора для вашего модуля добавьте эти 2 маркера.
<adminhtml_[module]_[entity]_products>
<block type="core/text_list" name="root" output="toHtml">
<block type="[module]/adminhtml_[entity]_edit_tab_product" name="[entity].edit.tab.product"/>
<block type="adminhtml/widget_grid_serializer" name="product_grid_serializer">
<reference name="product_grid_serializer">
<action method="initSerializerBlock">
<grid_block_name>[entity].edit.tab.product</grid_block_name>
<data_callback>getSelectedProducts</data_callback>
<hidden_input_name>products</hidden_input_name>
<reload_param_name>[entity]_products</reload_param_name>
</action>
<action method="addColumnInputName">
<input_name>position</input_name>
</action>
</reference>
</block>
</block>
</adminhtml_[module]_[entity]_products>
<adminhtml_[module]_[entity]_productsgrid>
<block type="core/text_list" name="root" output="toHtml">
<block type="[module]/adminhtml_[entity]_edit_tab_product" name="[entity].edit.tab.product"/>
</block>
</adminhtml_[module]_[entity]_productsgrid>
Теперь сохраняем данные. В saveAction
вашем админ-контролере добавьте это прямо перед вызовом$[entity]->save()
$products = $this->getRequest()->getPost('products', -1);
if ($products != -1) {
$[entity]->setProductsData(Mage::helper('adminhtml/js')->decodeGridSerializedInput($products));
}
В вашей модели сущности добавьте эти методы и переменную-член, которая будет обрабатывать отношение продукта:
protected $_productInstance = null;
public function getProductInstance(){
if (!$this->_productInstance) {
$this->_productInstance = Mage::getSingleton('[module]/[entity]_product');
}
return $this->_productInstance;
}
protected function _afterSave() {
$this->getProductInstance()->save[Entity]Relation($this);
return parent::_afterSave();
}
public function getSelectedProducts(){
if (!$this->hasSelectedProducts()) {
$products = array();
foreach ($this->getSelectedProductsCollection() as $product) {
$products[] = $product;
}
$this->setSelectedProducts($products);
}
return $this->getData('selected_products');
}
public function getSelectedProductsCollection(){
$collection = $this->getProductInstance()->getProductCollection($this);
return $collection;
}
Теперь вам нужна модель отношения сущность-продукт.
Создайте [Namespace]/[Module]/Model/[Entity]/Product.php
<?php
class [Namespace]_[Module]_Model_[Entity]_Product
extends Mage_Core_Model_Abstract {
protected function _construct(){
$this->_init('[module]/[entity]_product');
}
public function save[Entity]Relation($[entity]){
$data = $[entity]->getProductsData();
if (!is_null($data)) {
$this->_getResource()->save[Entity]Relation($[entity], $data);
}
return $this;
}
public function getProductCollection($[entity]){
$collection = Mage::getResourceModel('[module]/[entity]_product_collection')
->add[Entity]Filter($[entity]);
return $collection;
}
}
Вам также нужна модель ресурса. [Namespace]/[Module]/Model/Resource/[Entity]/Product.php
<?php
class [Namespace]_[Module]_Model_Resource_[Entity]_Product
extends Mage_Core_Model_Resource_Db_Abstract {
protected function _construct(){
$this->_init('[module]/[entity]_product', 'rel_id');
}
public function save[Entity]Relation($[entity], $data){
if (!is_array($data)) {
$data = array();
}
$deleteCondition = $this->_getWriteAdapter()->quoteInto('[entity]_id=?', $[entity]->getId());
$this->_getWriteAdapter()->delete($this->getMainTable(), $deleteCondition);
foreach ($data as $productId => $info) {
$this->_getWriteAdapter()->insert($this->getMainTable(), array(
'[entity]_id' => $[entity]->getId(),
'product_id' => $productId,
'position' => @$info['position']
));
}
return $this;
}
}
и модель коллекции ресурсов. Я обещаю, что это последний.[Namespace]/[Module]/Model/Resource/[Entity]/Product/Collection.php
<?php
class [Namespace]_[Module]_Model_Resource_[Entity]_Product_Collection
extends Mage_Catalog_Model_Resource_Product_Collection {
protected $_joinedFields = false;
public function joinFields(){
if (!$this->_joinedFields){
$this->getSelect()->join(
array('related' => $this->getTable('[module]/[entity]_product')),
'related.product_id = e.entity_id',
array('position')
);
$this->_joinedFields = true;
}
return $this;
}
public function add[Entity]Filter($[entity]){
if ($[entity] instanceof [Namespace]_[Module]_Model_[Entity]){
$[entity] = $[entity]->getId();
}
if (!$this->_joinedFields){
$this->joinFields();
}
$this->getSelect()->where('related.[entity]_id = ?', $[entity]);
return $this;
}
}
Все , что вам нужно сделать , это заменить значения между []
( [Namespace]
, [Module]
, [module]
...) с реальными значениями.
Вы можете столкнуться с некоторыми ошибками, потому что способ, которым вы структурировали свой модуль, может немного отличаться от того, что я имею в виду. Но с некоторыми отладками и изменениями вы можете заставить его работать. Все тяжелые работы там.
Вот и все.
Примечание. Приведенный выше код был скопирован / вставлен (и переименован в имена файлов) из того, что было сгенерировано с помощью UMC . Вы можете использовать это для создания своего полного модуля, не беспокоясь о том, чтобы связать свою сущность с продуктами. Вы просто говорите в интерфейсе «Связать сущность с продуктами: да».
Это не спам. Расширение бесплатно.