Override/Extend Magento Abstract class? - magento

I only need to add a method to the Mage_Core_Model_Abstract class.
For that, in my config.php I have
<models>
<mymodule>
<class>Mynamespace_Mymodule_Model</class>
</mymodule>
<core>
<rewrite>
<mage_core_model_abstract>Mynamespace_Mymodule_Model_Abstract</mage_core_model_abstract>
</rewrite>
</core>
</models>
It doesn't really work..
I know that there is a way of "overriding" by copying all the folder structure including the class file into my module, but I would like to know if there is a way to make it more fancy, within my module - something similar as above..

You can only rewrite classes that you instantiate directly, from config.xml.
The various values in config.xml are used when creating an object through a factory (e.g. Mage::getModel($class), Mage::getSingleton($class), Mage::helper($class), etc). The value of the $class argument is used to translate catalog/product into Mage_Catalog_Model_Product.
This means it's impossible to rewrite (in the Magento sense) classes that are used as superclasses, including abstract classes (by definition).
If you want to redefine any class that's used as a superclass, then you'll need to place a file in the correct place further up the include path. In this case, you'd need to make a file in app/code/local/Mage/Core/Model/Abstract.php.

Related

Magento 1.7 Override Pdf Classes

I tried to override Pdf classes for making changes toInvoice/Shipment/Creditmemo pdf but it doesnt seem to reflect.
I created a module with following in the Mymodule/etc/config.xml
<config>
<modules>
<Mymodule_Printtemplates>
<version>0.1.0</version>
</Mymodule_Printtemplates>
</modules>
<global>
<models>
<sales>
<rewrite>
<order_pdf_abstract>Mymodule_Printtemplates_Model_Order_Pdf_Abstract</order_pdf_abstract>
<order_pdf_invoice>Mymodule_Printtemplates_Model_Order_Pdf_Invoice</order_pdf_invoice>
<order_pdf_creditmemo>Mymodule_Printtemplates_Model_Order_Pdf_Creditmemo</order_pdf_Creditmemo>
<order_pdf_shipment>Mymodule_Printtemplates_Model_Order_Pdf_Shipment</order_pdf_shipment>
</rewrite>
</sales>
</models>
</global>
Then I created following Model classes in Mymodule/models/
as Abstract.php, Invoice.php, Shipment.php, Creditmemo.php
abstract class Mymodule_Printtemplates_Model_Order_Pdf_Abstract extends Mage_Sales_Model_Order_Pdf_Abstract
class Mymodule_Printtemplates_Model_Order_Pdf_Invoice extends Mymodule__Printtemplates_Model_Order_Pdf_Abstract { ... functions here ...}
class Mymodule_Printtemplates_Model_Order_Pdf_Shipment extends Mymodule__Printtemplates_Model_Order_Pdf_Abstract{ ... functions here ...}
class Mymodule_Printtemplates_Model_Order_Pdf_Creditmemo extends Mymodule__Printtemplates_Model_Order_Pdf_Abstract{ ... functions here ...}
The module is enabled - I have checked it through System>Configuration>Admin>Advanced but it doesn't seem to reflect the changes
On the other-hand, if I copy paste Mage/Sales/Model/Order/Pdf/*.php into local and change, changes are reflected. I know this is not a recommended method but the method via rewriting classes doesnt seem to work.
Any help for the first method via class rewrite would be appreciated.
Thanks,
Loveleen
The real problem was a Syntax in error in etc/config.xml [see Capital C in ending tag]
Mymodule_Printtemplates_Model_Order_Pdf_Creditmemo
I used the following to debug the issue: Drop this in the bottom of your index.php, similar to Alans Module List but a quick code copy/paste approach. Remember all of Magento's XML's get combined into one XML tree.
header("Content-Type: text/xml"); die(Mage::app()->getConfig()->getNode()->asXML());
Taken from the answers of: How do I know whether my Config.xml file is working in Magento?
Here are a couple of things that I am seeing.
What are the file paths to each of your overridden files? They should be: Mymodule/Printtemplates/Model/Order/Pdf/Invoice.php, for example. The class name should match the file name.
Rewrites do not affect abstract classes, unless the abstract class is called with a factory method (not recommended). The way that a rewrite works is through the factory methods (Mage::getModel('')). Using the factory method allows Magento to look through the system to see if another class is needing to be used. However, when a class is hard-referenced (e.x. Mage_Sales_Model_Order_Pdf_Abstract), it does not go through the factory method, and thus no rewrites will occur on that.
I would consider making each of your classes extend their original class (e.x. Mage_Sales_Model_Order_Pdf_Invoice, etc). If you have extra common functions, you would possibly put those into a Helper.
To see if the code is even being called, put a known code error in the file. PHP will complain, and that tells you that your file is being loaded.
I used the following to debug the issue:
Drop this in the bottom of your index.php, similar to Alans Module List but a quick code copy/paste approach. Remember all of Magento's XML's get combined into one XML tree.
header("Content-Type: text/xml");
die(Mage::app()->getConfig()->getNode()->asXML());
Taken from the answers of: How do I know whether my Config.xml file is working in Magento?

Are there standard naming conventions for a catalog override module in Magento?

If writing a module to add and modify some catalog logic. Is there anything wrong or against any standards/best practices in creating a module named "Catalog" that lives in the app/code/local directory?
example:
app/
--code/
----local/
------Catalog/
--------controllers/
--------etc/
-or should it be prefixed, something like: Foo_Catalog
I'm specifically looking if best practices/standards for Magento exist for this. (not just opinion)
Best practices would be to in essence extend Catalog via your Module and its specific purpose. So if you are adding/modifying Product's image gallery functionality within the Catalog module your module might be named CompanyName_NewGallery, thereafter you could have a folder structure like the such:
app/
--code/
----local/
------CompanyName/
--------NewGallery/
----------Block/Catalog/Product/Gallery.php
----------controllers/Catalog/
----------etc/
In your config.xml you would set it up so that your Gallery.php would overwrite magento's in the following way:
<global>
<blocks>
<sales>
<rewrite>
<product_gallery>CompanyName_NewGallery_Block_Catalog_Product_Gallery</product_gallery>
</rewrite>
</sales>
</blocks>
</global>
Then declare your class and you can either totally overwrite the class and extend the original class' parent (Mage_Core_Block_Template) or the original class (Mage_Catalog_Block_Product_Gallery)

Magento - how to declare multiple helper classes in the same config

Could someone please tell me how I can declare multiple helpers within the same config file for the same module?
I've been using helper utility files for awhile now, but as my utility method is becoming increasingly long, with many functions, I'd like to split it up into seperate helper utility classes based on the functionality. So I'd have a class called Categoryhelper and one called Attributehelper. Obviously this step I can do, but I'm not sure how to declare these in the config.xml.
I've tried messing around with the config, doing trial and error but cant seem to get anything to work.
Here's what I originally had, using the default helper:
(note - my custom module name is called 'Helper'
<global>
...
<helpers>
<helper>
<class>GPMClient_Helper_Helper</class>
</helper>
</helpers>
...
and here's what I've tried:
<helpers>
<helper>
<class>GPMClient_Helper_Helper/Categoryhelper</class>
</helper>
<helper>
<class>GPMClient_Helper_Helper/Attributehelper</class>
</helper>
and:
<helpers>
<helper>
<class>GPMClient_Helper_Helper/Categoryhelper</class>
<class>GPMClient_Helper_Helper/Attributehelper</class>
</helper>
Should the helper classes go into their own xml fragment or should both be grouped together?
If anyone could please post a sample config with multiple helper classes declared, I'd be most grateful.
Thanks,
Ian
Seems like you got wrong how it works. When you add next lines to your GPMClient_Helper module config.xml
<helpers>
<helper>
<class>GPMClient_Helper_Helper</class>
</helper>
</helpers>
you define class prefix for all your helpers. So, now in your GPMClient/Helper/Helper directory you should create file Data.php with GPMClient_Helper_Helper_Datacode inside and any number of classes named GPMClient_Helper_Helper_*.

Magento-module renamed, but Magento keeps asking for the old helper class

Magento, versions CE 1.4.2, 1.5.0.1, 1.5.1.0
I have had to adapt a payment module for Magento, following all recipes, config.xml, system.xml, etc/module/Mycompany_Mypaymentmodule.xml, which all work fine.
But recently, I've double checked and found an error:
in my config.xml, I had put:
<config>
<modules>
<Mage_Mycompany>
<version>0.1.0</version>
</Mage_Mycompany>
</modules>
...
That's because originally, the module was supposed to be placed inside the community-folder.
Following the guidelines, I've rewritten classes, xml's et cetera to reflect the local codepool. That too went well (except for an error that I had debugged).
However, inside the config.xml, I have renamed the modules-tag, like so:
<config>
<modules>
<Mycompany_Mypaymentmodule>
<version>0.1.0</version>
</Mycompany_Mypaymentmodule>
</modules>
The strange thing is that Magento now keeps asking me for the old Helper-class-file when I go to the Payment Methods in the backend, resulting in:
Fatal error: Class 'Mage_Mycompany_Helper_Data' not found in path\to\app\Mage.php on line 520
In other words, Magento keeps asking for a helper class of my old, pre-renamed module, which of course is nowhere to be found.
I've done an extensive search in all files, but nowhere is the string Mage_Mycompany to be found, so my guess is Magento is trying to load this helper class out of a database table. Of course, I've cleared the cache and rebuilt all indexes multiple times, and removed all cache files. I also checked practically all database tables, but to no avail.
Second, when I create the helper class by hand in app/code/community/Mage/Mycompany/Helper/Data.php, all goes well, which to me sounds strange, because the class itself should not be called (since it is never mentioned in any config.xml).
I must be missing something, and perhaps the class name is generated on the fly, but I really do not know how to avoid it or to fix it... so any help is appreciated!
Step one, of course, is to clear your cache.
If clearing cache doesn't work.
Step 2: The data helper class is used to translate strings for a module. That is, each data helper has a method
$helper->__('Translate this symbol');
that will translate a string per that module's helper file.
Throughout the system, there are several XML files where you may want certain nodes to be translated. The syntax looks something like this.
<dhl translate="label" module="usa">
<label>The Label</label>
</dhl>
Here you're telling magento to translate the "label" node enclosed in dhl, and to use the usa module to do it. That is, use the helper instantiated like
$Mage::getModel('usa/data');
//same thing as above, helpers default to data
Mage::getModel('usa');
to translate the label
$helper->__('The Label');
My guess is one of your XML files still has your old module configure for translation
<sometag module="mycompany" translate="someothertag" />
which makes magento look for a helper that's no longer there, and boom, there's your error.
Tha Data helper is loaded when you call the translation helper, ie: Mage::helper('modulename')->__("some string to translate").
In your config .xml, have you declared the module's helper class?:
<config>
...
<global>
...
<helpers>
<yourmodule>
<class>Yourcompanyname_Yourmodule_Helper</class>
</yourmodule>
</helpers>
...
</global>
...
</config>

Magento - extending the Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection class

OK, so this is leading on from another question I asked here recently. Basically, I want to extend the Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection class, so I can add some extra filters for the product collections that can be re-used throughout my store (such as best-selling). This is meant to replace the following code, which I currently use, which is in my template.phtml file:
$_bs_productCollection = Mage::getResourceModel('reports/product_collection')
->addAttributeToSelect('name')
->addAttributeToFilter('visibility', $visibility)
->addOrderedQty()
->setOrder('ordered_qty', 'desc')
->setPageSize(6);
$_bs_productCollection->load();
So, I set up my module, and it's loading (it shows in the admin/system/config/advanced). Folder structure as follows:
etc/modules/Samsmodule.xml
local/Samsmodule
local/Samsmodule/Catalog
local/Samsmodule/Catalog/etc
local/Samsmodule/Catalog/etc/config.xml
local/Samsmodule/Catalog/Model
local/Samsmodule/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php
local/Samsmodule/Catalog/Helper (not sure if this is needed or not)
My Samsmodule.xml is:
<config>
<modules>
<Samsmodule_Catalog>
<active>true</active>
<codePool>local</codePool>
</Samsmodule_Catalog>
</modules>
</config>
My config.xml is:
<config>
<modules>
<Samsmodule_Catalog>
<version>0.1.0</version>
</Samsmodule_Catalog>
</modules>
<global>
<models>
<catalog_resource_eav_mysql4>
<rewrite>
<product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</product_collection>
</rewrite>
</catalog_resource_eav_mysql4>
</models>
</global>
</config>
And my Collection.php is:
<?php
class Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
{
public function filterbyBestSelling($attribute,$visibility,$_category,$no_of_items)
{
$this->addAttributeToSelect($attribute)->addOrderedQty()->setOrder('ordered_qty', 'desc')->addAttributeToFilter('visibility', $visibility)->addCategoryFilter($_category)->setPageSize($no_of_items);
return $this;
}
}
And then from my template.phtml I call it like so:
$_bs_productCollection = Mage::getResourceModel('reports/product_collection')
->filterbyBestSelling('name',$visibility,$_category,6);
But it's not working - what am I missing? If I just add the code from my Collection.php to the bottom of my core Collection.php file, and use the same call, it works fine.
(Didn't mean to leave you hanging in the other thread, but there's not a quick answer to this one that wouldn't either seem like magic or just confuse people further.)
You don't need to override a class unless you're going to change the behavior of an existing method. You just need to create a new class that extend the existing class. Here's how you do that.
Terminology For the Normal State of Things
Models are the logical classes/objects that define the behavior of some "thing" (product, etc.) in Magento
Models contain Model Resources. Model Resources are the classes that do the actual fetching of data from some datastore (mysql, etc). This is the Data Mapper pattern.
Collections are objects with array like properties that query the database and return a group of Models. Somewhat confusingly, Collections are also Model Resources.
So, in the normal state of things, you might say something like
Mage::getModel('catalog/product')
to get a product model and the underlying system uses
Mage::getResourceModel('catalog/product');
to get the Mode Resource object that queries for a single product, and either of the following are used
Mage::getResourceModel('catalog/product_collection');
Mage::getModel('catalog/product')->getCollection();
to get the Collection object that queries for many models. In current versions of Magento each Model object has a method named "getCollection" which returns its corresponding Collection Resource.
Reports Off the Rails
Reports go a little sideways, but everything is still within the same universe as described above. It turns out there's no such model as a
Mage::getModel('reports/product');
But there is a collection
Mage::getResourceModel('reports/product_collection')
If you look at the class (which you'll be extending below), you'll see that the 'reports/product_collection' collection
class Mage_Reports_Model_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
extends the the base product collection class. In other words, the client programmer working on the reports section had the exact same though you did. "I want to add some methods to to Mage::getModelResource('catalog/product_collection'). They did this by extending the base class.
Shut Up, I Just Want this to Work
So, what you really want to do here is
Create a new class Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection that extends the base Mage_Reports_Model_Mysql4_Product_Collection collection class.
Ensure that a call to Mage::getModelResource('samscatalog/product_collection') returns an instance of the above class by configurig our module to use Models and Model Resources.
We're also going to change you Module structure around a little bit to help ease naming confusion. I'm not a big fan of giving module folders the same names as core modules (i.e. "Catalog"), and the top level folder (after local/) is actually a Namespace, not a module folder. (A namespace may contain many modules)
We are not overriding the class. We are configuring a custom module under your namespace to use both Models and Model Resources. We're then defining a model resource that extends an existing PHP class already in the system. Overrides should only be used when you want to change the behavior of a particular method call. (Appologies for harping on this, but there's enough general confusion in the communiy about this that it's worth harping on over. and over. and over.)
First, we're going to create the module directory structure and files. We'll just need two
local/Samsnamespace/Samscatalog/etc/config.xml
local/Samsnamespace/Samscatalog/Model/Mysql4/Product/Collection.php
(and don't forget to enable the module in app/etc/modules. If you're not sure what that means, start reading)
The Collection.php file should contain
<?php
class Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection extends Mage_Reports_Model_Mysql4_Product_Collection
{
/* your custom methods go here*/
}
And the config file should contain
<config>
<modules>
<Samsnamespace_Samscatalog>
<version>0.1.0</version>
</Samsnamespace_Samscatalog>
</modules>
<global>
<models>
<samscatalog>
<class>Samsnamespace_Samscatalog_Model</class>
<resourceModel>samscatalog_mysql4</resourceModel>
</samscatalog>
<samscatalog_mysql4>
<class>Samsnamespace_Samscatalog_Model_Mysql4</class>
</samscatalog_mysql4>
</models>
</global>
</config>
With these files in place and the module enabled, you should be able to call
$test = Mage::getResourceModel('samscatalog/product_collection');
var_dump(get_class($test));
and your collection will be returned, and you can add methods to your heart's content.
What's Going On
This is mind bending, so you can stop reading if you want. It's also a rehash of concepts I've covered elsewhere.
When you say
Mage::getResourceModel('samscatalog/product_collection');
The underlying mage system codes says "ok, so this resource model"
samscatalog/product_collection
is part of the
samscatalog/product
model (not entirely true in this case, but it's what the system thinks).
So, since the resource model samscatalog/product_collection is part of the samscatalog/product model, let's look at the config at
global/models/samscatalog/resourceModel
To get the resource model URI of
samscatalog_mysql4
and then let's use that to look at the config at
global/models/samscatalog_mysql4/class
to get the base classname for all Resource Models that are a part of this Module. This ends up being
Samsnamespace_Samscatalog_Model_Mysql4
Which means the samscatalog/product_collection Resource Model is named
Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection
and then its just Magento's standard auto-load which does a
include('Samsnamespace/Samscatalog/Model/Mysql4/Product/Collection.php');
What is the class of the resulting product collection? Does your override work?
This section seems suspect, I'm surprised if it's actually working:
<global>
<models>
<catalog_resource_eav_mysql4>
<rewrite>
<product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</product_collection>
</rewrite>
</catalog_resource_eav_mysql4>
</models>
</global>
Try this instead:
<global>
<models>
<catalog>
<rewrite>
<resource_eav_mysql4_product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</resource_eav_mysql4_product_collection>
</rewrite>
</catalog>
</models>
</global>
The tag inside of refers to a module. Catalog is a module, while catalog_resource_eav_mysql4 isn't. The tag inside of specifies a class handle, which is basically everything after Mage_Catalog_Model_ in the classname.
Hope that helps!
Thanks,
Joe

Resources