Question

I read a lot of information on this issue, but have not found a solution. I need to change the function getAddToCartUrl, in class Mage_Catalog_Block_Product_Abstract. Is there a way to make a substitution function module (without creating a copy of it in the local directory)? Rewrite method in the case Abstract classes does not work.

Was it helpful?

Solution

You cannot rewrite abstract classes What you need to do is rewrite the class that extends, and inherits the abstract class methods.

As an example:

Mage_Catalog_Block_Product_View extends Mage_Catalog_Block_Product_Abstract, so if you want to change the behaviour of getAddToCartUrl when you view a product, you'd rewrite Mage_Catalog_Block_Product_View

Can you explain what it is that you are trying to do?

I personally think that you are trying to change the wrong method (it is too low level to change), but since I don't know your end-goal, I cannot really comment on that.

I'll continue with some thoughts, as it could help you re-evaluate your intended implementation, and possibly identify the right place to extend.

Lets assume that your intention is to change the url retrieved for all products, system wide.

Lets look at what goes on in Mage_Catalog_Block_Product_Abstract::getAddToCartUrl()

public function getAddToCartUrl($product, $additional = array())
{
    if ($product->getTypeInstance(true)->hasRequiredOptions($product)) {
        if (!isset($additional['_escape'])) {
            $additional['_escape'] = true;
        }
        if (!isset($additional['_query'])) {
            $additional['_query'] = array();
        }
        $additional['_query']['options'] = 'cart';

        return $this->getProductUrl($product, $additional);
    }
    return $this->helper('checkout/cart')->getAddUrl($product, $additional);
}

We can see in the code above that it checks to see if we have a valid product (and some url params), and if so, flow goes to another method getProductUrl, or to a helper checkout/cart

Great, lets go look at getProductUrl first:

public function getProductUrl($product, $additional = array())
{
    if ($this->hasProductUrl($product)) {
        if (!isset($additional['_escape'])) {
            $additional['_escape'] = true;
        }
        return $product->getUrlModel()->getUrl($product, $additional);
    }

    return '#';
}

Again there is some checking for url params, and then flow is going to the $product object, getUrlModel()

Lets go see what that does:

public function getUrlModel()
{
    if ($this->_urlModel === null) {
        $this->_urlModel = Mage::getSingleton('catalog/product_url');
    }
    return $this->_urlModel;
}

Great, it instantiates a new model (catalog/product_url), and in that it call the method getUrl

So, first off, there is a potential entry point to extend: Mage_Catalog_Model_Product_Url, rather than your intended, low level method.

So can you potentially get the require result by doing a rewrite on that class/method ?

So, lets stop there, and backtrack to that helper method also called:

$this->helper('checkout/cart')->getAddUrl($product, $additional);

Not really going to dig to deep here, but clearly there is another class that you can rewrite.

So ultimately, unless your actual goal is to change the checking of the params in the low level getProductUrl in that abstract class, I have just identified two other potential places you can extend, and atain your required functionality (whatever that is)

Hope this helps you in the right direction.

OTHER TIPS

Solved and Tested: You can't extend Mage abstract class in your custom module directly but you need to find such mage class which extends your desire mage abstract class, so you extend that class. Example: - Mage_sales_order_pdf_abstract (you want to extends this class) Mage_sales_order_pdf_invoice extends Mage_sales_order_pdf_abstract What you need to do is given below CustomModule_model_classname extends Mage_sales_order_pdf_invoice and now you can override any method from both classes - Mage_sales_order_pdf_abstract - Mage_sales_order_pdf_invoice

Thanks

I am not clear about your question.

Step1: create a class on your custom module which is extends Mage_Catalog_Block_Product_Abstract .

<?php 
class YourNameSpace_Yourmodule_Block_Catalog_Product_Myclass extends Mage_Catalog_Block_Product_Abstract{

public function getAddToCartUrl($product, $additional = array())
    {
.....................
    }
}

Step2: rewrite all class which is extending Mage_Catalog_Block_Product_Abstract.You need to change those class extending class

from Mage_Catalog_Block_Product_Abstract to YourNameSpace_Yourmodule_Block_Catalog_Product_Myclass

And copy all code from original to new class rewrite code and don't extending parent class and using copying of all code from main class make the rewrite class work like main class

From Mage_Catalog_Block_Product_Abstract to YourNameSpace_Yourmodule_Block_Catalog_Product_Myclass Suppose in this case, i need rewrite class Mage_Catalog_Block_Product_List as it extends Mage_Catalog_Block_Product_Abstract. For this List class i have create rewrite class YourNameSpace_Yourmodule_Block_Catalog_Product_List

and copy all code from Mage_Catalog_Block_Product_List to YourNameSpace_Yourmodule_Block_Catalog_Product_List

just like :

<?php 
YourNameSpace_Yourmodule_Block_Catalog_Product_List {

    /**
     * Default toolbar block name
     *
     * @var string
     */
    protected $_defaultToolbarBlock = 'catalog/product_list_toolbar';

    /**
     * Product Collection
     *
     * @var Mage_Eav_Model_Entity_Collection_Abstract
     */
    protected $_productCollection;

    /**
     * Retrieve loaded category collection
     *
     * @return Mage_Eav_Model_Entity_Collection_Abstract
     */
    protected function _getProductCollection()
    {
        if (is_null($this->_productCollection)) {
            $layer = $this->getLayer();
            /* @var $layer Mage_Catalog_Model_Layer */
            if ($this->getShowRootCategory()) {
                $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
            }

            // if this is a product view page
            if (Mage::registry('product')) {
                // get collection of categories this product is associated with
                $categories = Mage::registry('product')->getCategoryCollection()
                    ->setPage(1, 1)
                    ->load();
                // if the product is associated with any category
                if ($categories->count()) {
                    // show products from this category
                    $this->setCategoryId(current($categories->getIterator()));
                }
            }

            $origCategory = null;
            if ($this->getCategoryId()) {
                $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
                if ($category->getId()) {
                    $origCategory = $layer->getCurrentCategory();
                    $layer->setCurrentCategory($category);
                }
            }
            $this->_productCollection = $layer->getProductCollection();

            $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

            if ($origCategory) {
                $layer->setCurrentCategory($origCategory);
            }
        }

        return $this->_productCollection;
    }

    /**
     * Get catalog layer model
     *
     * @return Mage_Catalog_Model_Layer
     */
    public function getLayer()
    {
        $layer = Mage::registry('current_layer');
        if ($layer) {
            return $layer;
        }
        return Mage::getSingleton('catalog/layer');
    }

    /**
     * Retrieve loaded category collection
     *
     * @return Mage_Eav_Model_Entity_Collection_Abstract
     */
    public function getLoadedProductCollection()
    {
        return $this->_getProductCollection();
    }

    /**
     * Retrieve current view mode
     *
     * @return string
     */
    public function getMode()
    {
        return $this->getChild('toolbar')->getCurrentMode();
    }

    /**
     * Need use as _prepareLayout - but problem in declaring collection from
     * another block (was problem with search result)
     */
    protected function _beforeToHtml()
    {
        $toolbar = $this->getToolbarBlock();

        // called prepare sortable parameters
        $collection = $this->_getProductCollection();

        // use sortable parameters
        if ($orders = $this->getAvailableOrders()) {
            $toolbar->setAvailableOrders($orders);
        }
        if ($sort = $this->getSortBy()) {
            $toolbar->setDefaultOrder($sort);
        }
        if ($dir = $this->getDefaultDirection()) {
            $toolbar->setDefaultDirection($dir);
        }
        if ($modes = $this->getModes()) {
            $toolbar->setModes($modes);
        }

        // set collection to toolbar and apply sort
        $toolbar->setCollection($collection);

        $this->setChild('toolbar', $toolbar);
        Mage::dispatchEvent('catalog_block_product_list_collection', array(
            'collection' => $this->_getProductCollection()
        ));

        $this->_getProductCollection()->load();

        return parent::_beforeToHtml();
    }

    /**
     * Retrieve Toolbar block
     *
     * @return Mage_Catalog_Block_Product_List_Toolbar
     */
    public function getToolbarBlock()
    {
        if ($blockName = $this->getToolbarBlockName()) {
            if ($block = $this->getLayout()->getBlock($blockName)) {
                return $block;
            }
        }
        $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, microtime());
        return $block;
    }

    /**
     * Retrieve additional blocks html
     *
     * @return string
     */
    public function getAdditionalHtml()
    {
        return $this->getChildHtml('additional');
    }

    /**
     * Retrieve list toolbar HTML
     *
     * @return string
     */
    public function getToolbarHtml()
    {
        return $this->getChildHtml('toolbar');
    }

    public function setCollection($collection)
    {
        $this->_productCollection = $collection;
        return $this;
    }

    public function addAttribute($code)
    {
        $this->_getProductCollection()->addAttributeToSelect($code);
        return $this;
    }

    public function getPriceBlockTemplate()
    {
        return $this->_getData('price_block_template');
    }

    /**
     * Retrieve Catalog Config object
     *
     * @return Mage_Catalog_Model_Config
     */
    protected function _getConfig()
    {
        return Mage::getSingleton('catalog/config');
    }

    /**
     * Prepare Sort By fields from Category Data
     *
     * @param Mage_Catalog_Model_Category $category
     * @return Mage_Catalog_Block_Product_List
     */
    public function prepareSortableFieldsByCategory($category) {
        if (!$this->getAvailableOrders()) {
            $this->setAvailableOrders($category->getAvailableSortByOptions());
        }
        $availableOrders = $this->getAvailableOrders();
        if (!$this->getSortBy()) {
            if ($categorySortBy = $category->getDefaultSortBy()) {
                if (!$availableOrders) {
                    $availableOrders = $this->_getConfig()->getAttributeUsedForSortByArray();
                }
                if (isset($availableOrders[$categorySortBy])) {
                    $this->setSortBy($categorySortBy);
                }
            }
        }

        return $this;
    }


}

now this rewrite class put it extends class YourNameSpace_Yourmodule_Block_Catalog_Product_Myclass

<?php
class YourNameSpace_Yourmodule_Block_Catalog_Product_List extends  YourNameSpace_Yourmodule_Block_Catalog_Product_Myclass
{
}

The code is not good,but it may works.

Another Solution,

Your main issue use of getAddToCartUrl(),if we will not using this function.as alternative solution just create a helper class function which will do same logic like getAddToCartUrl() .

Suppose my helper class is YourNameSpace_Yourmodule_Helper_Myadd2cart and function getAddToCartUrl on this function copy all code from Mage_Catalog_Block_Product_Abstract class function getAddToCartUrl()

<?php
class YourNameSpace_Yourmodule_Helper_Myadd2cart extends Mage_Core_Helper_Abstract{
 public function getAddToCartUrl($product, $additional = array())
    {
        if (!$product->getTypeInstance(true)->hasRequiredOptions($product)) {
            return $this->helper('checkout/cart')->getAddUrl($product, $additional);
        }
        $additional = array_merge(
            $additional,
            array(Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey())
        );
        if (!isset($additional['_escape'])) {
            $additional['_escape'] = true;
        }
        if (!isset($additional['_query'])) {
            $additional['_query'] = array();
        }
        $additional['_query']['options'] = 'cart';
        return $this->getProductUrl($product, $additional);
    }


}

But, you need to change in some position of this function

change 1:

change from

$this->helper('checkout/cart')->getAddUrl($product, $additional); 

to Mage::helper('checkout/cart')->getAddUrl($product, $additional);.

Change2:

$this->_getSingletonModel('core/session')->getFormKey()

from:

  Mage::getSingleton('core/session')->getFormKey()

also you add new functions:

   public function getProductUrl($product, $additional = array())
    {
        if ($this->hasProductUrl($product)) {
            if (!isset($additional['_escape'])) {
                $additional['_escape'] = true;
            }
            return $product->getUrlModel()->getUrl($product, $additional);
        }
        return '#';
    }

    /**
     * Check Product has URL
     *
     * @param Mage_Catalog_Model_Product $product
     * @return bool
     *
     */
    public function hasProductUrl($product)
    {
        if ($product->getVisibleInSiteVisibilities()) {
            return true;
        }
        return false;
    }

Now where you have using $this->getAddToCartUrl there you need to change this code:

from $this->getAddToCartUrl(yourparams) to Mage::helper()->getAddToCartUrl(yourparams) and params should be same

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top