2

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 <[email protected]>
 */
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.

1 Answer 1

6

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.

5
  • Ok, it turns out that Varien/Data/Collection/Db.php was not one of the files with a class I need to override. I needed a change to getSelectCountSql() and it did not work in Db.php because the function is overridden in Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php. So scratch that part. I'm only changing 1-2 methods maximum in each of the php files. Jan 15, 2014 at 2:41
  • I've added my config.xml. I feel like making a module IS the most efficient way of making my changes, rather than having a slurry of various changes all over the local structure. I don't know what the best integration point is but the 3-4 changes I've made to have the intended effect at least. And a module can be easily deactivated or reactivated, while a bunch of changes in local file structure cannot. Jan 15, 2014 at 5:11
  • If your module does not have any blocks of its own instantiated via mynamespace_mymodule then you don't need that node.
    – benmarks
    Jan 15, 2014 at 12:51
  • I've updated with Xpaths to use.
    – benmarks
    Jan 15, 2014 at 12:59
  • I put in the bodies of the overridden resource classes. Perhaps I'm doing things in an extremely improper way. I'm not satisfied with the built-in configurable products. So I made my own version. Jan 15, 2014 at 21:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.