Magento 1.8 – Overwrite Controller and Block in Admin

adminadminhtmlcatalogmagento-1.8overrides

I want to add a custom tab in catalog_product_edit page with my custom module. I want this tab of ajax type, since the tab holds grid content.

To achieve this I rewrite the Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php block with my Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php block. It successfully rewrote the core block. My custom tab appeared in the edit page, but while click on the tab, it didnt work properly.

I have gone through the core files, and I found that, for ajax tabs, the action is defined in the controller Mage/Adminhtml/controllers/Catalog/ProductController.php. So I assumed the problem occurs due to my tabs action is not present in the core controller. So I planned to rewrite the above controller with myown Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php. When I rewrote the controller, edit page now shows nothing.

my app/code/local/Mysite/Combooffers/etc/config.xml

<config>
<modules>
    <Mysite_Combooffers>
        <version>0.1.0</version>
    </Mysite_Combooffers>
</modules>
<frontend>
    <routers>
        <Combooffers>
            <use>standard</use>
            <args>
                <module>Mysite_Combooffers</module>
                <frontName>combooffers</frontName>
            </args>
        </Combooffers>
    </routers>
    <layout>
        <updates>
            <combooffers>
                <file>combooffers.xml</file>
            </combooffers>
        </updates>
    </layout>
</frontend>
<admin>
    <routers>
         <adminhtml>
            <args>
                <modules>
                    <Mysite_Combooffers before="Mage_Adminhtml">Mysite_Combooffers_Adminhtml</Mysite_Combooffers>
                </modules>
            </args>
        </adminhtml>
    </routers>
</admin>
<adminhtml>
    <layout>
        <updates>
            <combooffers>
                <file>combooffers.xml</file>
            </combooffers>
        </updates>
    </layout>
</adminhtml>
<global>
    <blocks>
        <combooffers>
            <class>Mysite_Combooffers_Block</class>
            <sort_order>200</sort_order>
        </combooffers>
        <adminhtml>            
            <rewrite>  
                <catalog_product_edit_tabs>
                        Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs
                </catalog_product_edit_tabs> 
            </rewrite>  
        </adminhtml>
    </blocks>
    <routers>
        <adminhtml>
           <rewrite>
                  <mysite_combooffers_adminhtml_catalog_product>
                      <from><![CDATA[#^admin/catalog_product/$#]]></from>
                      <to>/admin/catalog_product/</to>
                  </mysite_combooffers_adminhtml_catalog_product>
            </rewrite>
       </adminhtml>
    </routers>
    <helpers>
        <combooffers>
            <class>Mysite_Combooffers_Helper</class>
        </combooffers>
    </helpers>
</global>
</config>

app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php

<?php

class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs
{
    protected function _prepareLayout()
    {
        /**Loads our tab using ajax.
            * ajax tab loads while click on the tab on edit page. Normally use to load grid content.
            * its complex
            * url is the important  one. when click on the tab, it will search for action correspond to the url in the controller.
            * here the action name should be `comboofferAction()`
        */
        $this->addTab('combooffer', array(
                'label'     => Mage::helper('catalog')->__('Combo Products'),
                'url'       => $this->getUrl('*/*/combooffer', array('_current' => true)),
                'class'     => 'ajax',
                'after'     => 'crosssell', //this will set tab after cross-sell tab.
            ));

        return parent::_prepareLayout();
    }
} 

app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Products/Edit/Tab/Combooffer.php

<?php

 class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tab_Combooffer extends Mage_Adminhtml_Block_Widget_Form
 {
/**
 * Set grid params
 *
 */
public function __construct()
{
    parent::__construct();
    $this->setId('combo_offers_product_grid');
    $this->setDefaultSort('entity_id');
    $this->setUseAjax(true);  // Using ajax grid is important
    if ($this->_getProduct()->getId()) {
        $this->setDefaultFilter(array('in_products'=>1)); // By default we have added a filter for the rows, 
                                                          //that in_products value to be 1
    }
   // if ($this->isReadonly()) {
   //     $this->setFilterVisibility(false);
    //}
    $this->setSaveParametersInSession(false);  //Dont save paramters in session or else it creates problems
}

/**
 * Retirve currently edited product model
 *
 * @return Mage_Catalog_Model_Product
 */
protected function _getProduct()
{
    return Mage::registry('current_product');
}

/**
 * Add filter
 *
 * @param object $column
 * @return Mysite_Combooffers_Adminhtml_Block_Catalog_Product_Edit_Tab_Combooffer
 */
protected function _addColumnFilterToCollection($column)
{
    // Set custom filter for in product flag
    if ($column->getId() == 'in_products') {
        $productIds = $this->_getSelectedComboOffers();
        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;
}


/**
 * Prepare collection
 *
 * @return Mage_Adminhtml_Block_Widget_Grid
 */
protected function _prepareCollection()
{
    $collection = Mage::getModel('catalog/product_link')->useUpSellLinks()
        ->getProductCollection()
        ->setProduct($this->_getProduct())
        ->addAttributeToSelect('*');

    if ($this->isReadonly()) {
        $productIds = $this->_getSelectedProducts();
        if (empty($productIds)) {
            $productIds = array(0);
        }
        $collection->addFieldToFilter('entity_id', array('in'=>$productIds));
    }

    $this->setCollection($collection);
    return parent::_prepareCollection();
}

/**
 * Add columns to grid
 *
 * @return Mage_Adminhtml_Block_Widget_Grid
 */
protected function _prepareColumns()
{
    if (!$this->_getProduct()->getUpsellReadonly()) {
        $this->addColumn('in_products', array(
            'header_css_class' => 'a-center',
            'type'      => 'checkbox',
            'name'      => 'in_products',
            'values'    => $this->_getSelectedComboOffers(),
            'align'     => 'center',
            'index'     => 'entity_id'
        ));
    }

    $this->addColumn('entity_id', array(
        'header'    => Mage::helper('catalog')->__('ID'),
        'sortable'  => true,
        'width'     => 60,
        'index'     => 'entity_id'
    ));
    $this->addColumn('name', array(
        'header'    => Mage::helper('catalog')->__('Name'),
        'index'     => 'name'
    ));

    $this->addColumn('type', array(
        'header'    => Mage::helper('catalog')->__('Type'),
        'width'     => 100,
        'index'     => 'type_id',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_type')->getOptionArray(),
    ));

    $sets = Mage::getResourceModel('eav/entity_attribute_set_collection')
        ->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
        ->load()
        ->toOptionHash();

    $this->addColumn('set_name', array(
        'header'    => Mage::helper('catalog')->__('Attrib. Set Name'),
        'width'     => 130,
        'index'     => 'attribute_set_id',
        'type'      => 'options',
        'options'   => $sets,
    ));

    $this->addColumn('status', array(
        'header'    => Mage::helper('catalog')->__('Status'),
        'width'     => 90,
        'index'     => 'status',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_status')->getOptionArray(),
    ));

    $this->addColumn('visibility', array(
        'header'    => Mage::helper('catalog')->__('Visibility'),
        'width'     => 90,
        'index'     => 'visibility',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_visibility')->getOptionArray(),
    ));

    $this->addColumn('sku', array(
        'header'    => Mage::helper('catalog')->__('SKU'),
        'width'     => 80,
        'index'     => 'sku'
    ));

    $this->addColumn('price', array(
        'header'        => Mage::helper('catalog')->__('Price'),
        'type'          => 'currency',
        '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',
        'type'              => 'number',
        'width'             => 60,
        'validate_class'    => 'validate-number',
        'index'             => 'position',
        'editable'          => true,  //!$this->_getProduct()->getUpsellReadonly(),
        'edit_only'         => true  //!$this->_getProduct()->getId()
    ));

    return parent::_prepareColumns();
}

/**
 * Rerieve grid URL
 *
 * @return string
 */
public function getGridUrl()
{
    return $this->_getData('grid_url') ? $this->_getData('grid_url') : $this->getUrl('*/*/combooffer', array('_current'=>true));
}

/**
 * Retrieve selected combo offers
 *
 * @return array
 */
protected function _getSelectedComboOffers()
{
    $products = $this->getSelectedComboOffers();
    if (!is_array($products)) {
        $products = array_keys($this->getSelectedComboOffers());
    }
    return $products;
}

/**
 * Retrieve combo offers
 *
 * @return arraygetSelectedComboOffers
 */
public function getSelectedComboOffers()
{
    $products = array();
    foreach (Mage::registry('current_product')->getUpSellProducts() as $product) {
        $products[$product->getId()] = array('position' => $product->getPosition());
    }
    return $products;
}

}

app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php

<?php

require_once('Mage/Adminhtml/controllers/Catalog/ProductController.php');

class Mysite_Combooffers_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Catalog_ProductController
{
    /** Use to set content of combo offer tab.
        * Defines layout of combo offer tab.
        * The layout defined here should present in app/design/adminhtml/default/default/<layout>.xml
    */
    public function comboofferAction()
    {
        $this->_initProduct();
        $this->loadLayout();
        $this->getLayout()->getBlock('catalog.product.edit.tab.combooffer')
            ->setProductsUpsell($this->getRequest()->getPost('products_combooffer', null));
        $this->renderLayout();
    }



}

app/design/adminhtml/default/default/layout/combooffers.xml

<combooffers_adminhtml_combooffer_combooffer>
<adminhtml_catalog_product_upsell>
    <block type="core/text_list" name="root" output="toHtml">
        <block type="adminhtml/catalog_product_edit_tab_upsell" name="catalog.product.edit.tab.combooffer"/>
        <block type="adminhtml/widget_grid_serializer" name="upsell_grid_serializer">
            <reference name="upsell_grid_serializer">
                <action method="initSerializerBlock">                       
                 <grid_block_name>catalog.product.edit.tab.combooffer</grid_block_name>
                    <data_callback>getSelectedComboOffers</data_callback>
                    <hidden_input_name>links[combooffers]</hidden_input_name>
                    <reload_param_name>products_combooffer</reload_param_name>
                </action>
                <action method="addColumnInputName">
                    <input_name>position</input_name>
                </action>
            </reference>
        </block>
    </block>
</adminhtml_catalog_product_upsell>
</combooffers_adminhtml_combooffer_combooffer>

Is there any problem with my approach ? Am I in the right path? What is the error that I have made here? Please give your suggestions. Thanks in advance

Best Answer

It would be easier if you'd change url for ajax call on tab In

$this->addTab('combooffer', array(
            'label'     => Mage::helper('catalog')->__('Combo Products'),
            'url'       => $this->getUrl('*/*/combooffer', array('_current' => true)),
            'class'     => 'ajax',
            'after'     => 'crosssell', //this will set tab after cross-sell tab.
        ));

url key is creating the path for ajax call. Asteriks means to use the same as current, so */*/combooffer is translated to admin/catalog_product/combooffer. You can change it to */my_controller/combooffer and it should work.

So change file app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php to app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ComboofferController.php so it would not overwrite core controller and make it extend Mage_Adminhtml_Controller_Action

and in app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php use code: 'url' => $this->getUrl('*/catalog_combooffer/combooffer', array('_current' => true)),

Related Topic