Magento – Rewrite core classes or override

moduleoverrides

I have made a bunch of changes in my local folder to override core classes. But I'd like to group some of them into modules so i can turn them on and off.

I am new to the module creation process. I've copied some code from tutorials online, but one thing I have not been able to answer is whether I should rewrite the core classes (which I am effectively already doing by overriding them in the local folder), or if I should extend them.

My understanding is that in either case, you create a class in your module folder that extends the core class. But in one case you surround in in <rewrite> tags and in the other you don't. But I don't know what the difference in effect is.

I need my module to change the behavior of

These Catalog template files in app/design/frontend/myinterface/mytheme/template/catalog/:

product/list.phtml
product/list/toolbar.phtml
product/view.phtml

These blocks in Catalog/Block/:

Product/List.php
Product/View.php
Product/List/Toolbar.php

These models in Catalog/Model/:

Layer/Filter/Attribute.php
Resource/Eav/Mysql4/Layer/Filter/Attribute.php
Resource/Eav/Mysql4/Product/Collection.php

Again, everything already works, but there is so much that is changed that I would like to package it into a module to make it easier to turn on and off and I want to make sure I go about it the right way.

EDIT:

In case anyone's wondering, the changes I've made are to group products together based on an attribute value. Some values are NULL, though, and those should not be grouped. I needed the filter functionality to display quantities that matched the visible products so that code had to be changed as well as the product list code.

Edit2:

After trying copying various online examples, one finally halfway worked, here.
Below xml attempts to load just 2 block files. The list.php is loading, but toolbar.php is not.

<!-- The root node for Magento module configuration -->
<config> 

    <!-- 
        The module's node contains basic 
        information about each Magento module
    --> 
    <modules>

        <!--
            This must exactly match the namespace and module's folder
            names, with directory separators replaced by underscores
        -->
        <Mynamespace_MyModule>

            <!-- The version of our module, starting at 0.0.1 -->
            <version>0.0.1</version>

        </Mynamespace_MyModule>

    </modules>
    <global>
        <models />      
        <blocks>
            <mynamespace_mymodule>
                <class>Mynamespace_MyModule_Block</class>
            </mynamespace_mymodule>
        <catalog>
        <rewrite>
                <!-- THEY LOAD! --><product_list>Mynamespace_MyModule_Block_Product_List</product_list>
        <product_list_toolbar>Mynamespace_MyModule_Block_Product_Toolbar</product_list_toolbar>
        </rewrite>

        </catalog>  
        </blocks>

        <helpers />
    </global>

</config>

I got the above XML to work after I realized that I misnamed my extension to the toolbar class.

Additional Info

Here is the function I'm overriding in the product resource class (my rewritten version).

class Mynamespace_MyModule_Model_Resource_Eav_Mysql4_Product_Collection
    extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
{

/**
     * Get SQL for get record count
     *
     * @return Varien_Db_Select
     */
    public function getSelectCountSql()
    {
        $this->_renderFilters();

        $countSelect = clone $this->getSelect();
        $countSelect->reset(Zend_Db_Select::ORDER);
        $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
        $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
        $countSelect->reset(Zend_Db_Select::COLUMNS);

        $countSelect->columns('COUNT(DISTINCT e.entity_id)');
        $countSelect->resetJoinLeft();

         //  $countSelect->columns('COUNT(*)'); // original code
        if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) { // handles group by. from stackoverflow
            $countSelect->reset(Zend_Db_Select::GROUP);
            //$countSelect->distinct(true);
            $group = $this->getSelect()->getPart(Zend_Db_Select::GROUP);
            $countSelect->reset(Zend_Db_Select::COLUMNS);
            $countSelect->columns(new Zend_Db_Expr("COUNT(DISTINCT ".implode(", ", $group).")"));
            $countSelect->columns(new Zend_Db_Expr('COUNT(DISTINCT e.entity_id)'));
        } else { // if no group by, handle the original way
            $countSelect->columns('COUNT(*)');
        }
        return $countSelect;
    }
}

And here's the one for the attribute resource:

/**
 * Catalog Layer Attribute Filter Resource Model
 *
 * @category    Mage
 * @package     Mage_Catalog
 * @author      Magento Core Team <core@magentocommerce.com>
 */
class Mynamespace_MyModule_Model_Resource_Eav_Mysql4_Layer_Filter_Attribute extends Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Attribute
{
/**
     * Retrieve array with products counts per attribute option
     *
     * @param Mage_Catalog_Model_Layer_Filter_Attribute $filter
     * @return array
     */
    public function getCount($filter)
    {
        // clone select from collection with filters
        $select = clone $filter->getLayer()->getProductCollection()->getSelect();
        // reset columns, order and limitation conditions
        $select->reset(Zend_Db_Select::COLUMNS);
        $select->reset(Zend_Db_Select::ORDER);
        $select->reset(Zend_Db_Select::LIMIT_COUNT);
        $select->reset(Zend_Db_Select::LIMIT_OFFSET);

        $connection = $this->_getReadAdapter();
        $attribute  = $filter->getAttributeModel();
        $tableAlias = $attribute->getAttributeCode() . '_idx';
        $conditions = array(
            "{$tableAlias}.entity_id = e.entity_id",
            $connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
            $connection->quoteInto("{$tableAlias}.store_id = ?", $filter->getStoreId()),
        );


            $select
                ->join(
                    array($tableAlias => $this->getMainTable()),
                    join(' AND ', $conditions),

                array('value', 'count' => "COUNT(DISTINCT IFNULL(e.custom_grouping,e.entity_id))"))

                ->group("{$tableAlias}.value");

        /*  $select // ORIGINAL CODE
            ->join(
                array($tableAlias => $this->getMainTable()),
                join(' AND ', $conditions),
                array('value', 'count' => "COUNT({$tableAlias}.entity_id)"))
            ->group("{$tableAlias}.value");
        */
            if(isset($_GET['testing'])) {   // 20140111 by Nick to see if this code is executing
                $_SESSION['called'][] = 'File ' . __FILE__ . ' - Line: ' . __LINE__ . 'getcount sql: ' . (string)$select;
            }
        return $connection->fetchPairs($select);
    }
}

Thanks.

Best Answer

Your customizations should be as easy to maintain as possible - especially for upgrades. This is likely best accomplished by identifying the best integration points and customizing core functionality when necessary.

When you rewrite a class via the configuration, you are changing the class instantiated, assumedly to customize a part of some core class behavior. This is more appropriate from a programmatic standpoint than owning the entire definition.

Rewrites won't work for parent classes or for library classes (e.g. Varien_Data_Collection_Db), so changes to these must be implemented by transferrance to local code pool. I'm very curious to know what you want to change with the DB collection superclass.

While blocks, helpers, and models all have a similar xpath for rewriting, e.g.

global>[blocks|helpers|models]>[class group]>rewrite>[class id]

resource models require a slightly different mapping. I can tell you are using a pre-MDBM release of Magento (CE <1.6), so your rewrite mappings would be as follows:

<global>
    <models>
        <catalog>
            <rewrite>
                <layer_filter_attribute></layer_filter_attribute>
            </rewrite>
        </catalog>
        <catalog_resource_eav_mysql4>
            <rewrite>
                <layer_filter_attribute></layer_filter_attribute>
                <product_collection></product_collection>
            </rewrite>
        </catalog_resource_eav_mysql4>
    </models>
</global>

As I said, I am quite curious to know your reasons for rewriting the resource models.

Related Topic