I want to create the Grid Serializer
functionality same as coming in Manage categories
If Anyone create that type functionality then please guide me.
I want to create the Grid Serializer
functionality same as coming in Manage categories
If Anyone create that type functionality then please guide me.
Assuming you have the module without the product relation here is what you need in addition.
First create a relation table between your entity and the products.
Add this in config.xml
inside the global/models/[module]_resource/entities
<[entity]_product>
<table>[entity]_product</table>
</[entity]_product>
Add this in one of the 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);
Now create the grid block. [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;
}
}
Now add this tab in the list of tabs. In [Namespace]_[Module]_Block_Adminhtml_[Entity]_Edit_Tabs::_beforeToHtml
add this below the main tab.
$this->addTab('products', array(
'label' => Mage::helper('[module]')->__('Associated products'),
'url' => $this->getUrl('*/*/products', array('_current' => true)),
'class' => 'ajax'
));
Now you need the controller actions to handle the products.
Add these methods to the admin controller for you entity:
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();
}
Now the layout for these 2 actions. In the admin layout file for your module add these 2 handles.
<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>
Now saving the data. In the saveAction
of your admin controller add this right before calling $[entity]->save()
$products = $this->getRequest()->getPost('products', -1);
if ($products != -1) {
$[entity]->setProductsData(Mage::helper('adminhtml/js')->decodeGridSerializedInput($products));
}
In your entity model add these methods and a member variable that will process the product relation:
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;
}
Now you need the entity-product relation model.
Create [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;
}
}
You also need a resource model. [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;
}
}
and a collection resource model. I promise that this is the last one. [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;
}
}
All you need to do is to replace the values between []
([Namespace]
, [Module]
, [module]
, ...) with your real values.
You may encounter some errors, because the way you structured your module may be a little different of what I have in mind. But with some debugging and changes you can get it to work. All the heavy lifting is there.
That's it.
Note: The code above was copy/pasted (and renamed the file names) from what was generated with UMC. You can use that to create your full module without having to worry about linking your entity to products. You just say in the UI "Link entity to products:Yes".
This is not spam. The extension is free.