Replacement of an abstract class in custom module
-
12-12-2019 - |
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.
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_Abstrac
t.
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