In Mage_Core_Model_Abstract there is the getCollection method that is widely used.
But, I had never looked at the getCollection method until now. I can see that all it does is call $this->getResourceCollection()
What is the point in having getCollection and why don't everyone just use getResourceCollection instead?
As for my point of view, it just gives me more clean code for model collection retrieval, without unnecessary typing of word Resource all the time. Also if you look into Order model or Quote model, you will see that it also using simplified method name for collection retrieval of items, addresses, payments, etc.
If it would be named getItemResourceCollection(), getAddressResourceCollection() instead of getAddressCollection() or getItemsCollection(), amount of characters you type during development is increasing. There were no explanation about why getCollection() should be used in favor getResourceCollection() while I was working in core team, but it was quite logical for me to use shorter name of method.
At least non of these methods are marked as deprecated, so you can use them both.
Related
I have developed a system where various classes have attributes consisting of a custom formula. The formula can contain special tokens which refer to different types of object. For example an object of class FruitSalad may have the following attribute;
$contents = "[A12] + [B76]";
In somewhat abstract terms, this means "add apple 12 to banana 76". It can also get significantly more complex than that with as many as 15 or 20 references to other objects involved in one formula.
I have a trait which passes formulae such as this and each time it finds a reference to a model (i.e. "[A12]") it gets it from the database with A::find(12) and adds it to an array of component objects which can be used for other processes later on in the request.
So, in essence, it's a relationship. But instead of a pivot table to describe the relationship, there is a formula on the parent model which can include references to child models.
This is all working. Yay! But it's really inefficient because there are so many tiny queries to get single models as formulae are parsed. One request may quite easily result in hundreds of queries. Oops.
I see two potential options;
1. Get all my apples and bananas from the database at the start of the request and get them from an in-memory store instead of from the database when parsing a formula (is this the repository pattern??).
2. Create a custom relation type (something like hasManyFromFormula) which makes eager loading work so that the parsing becomes much simpler because the relevant apples and bananas would already be loaded into the parent model.
Is there a precedent for this? As for why I am doing it like this, it would a bit tough to explain in brief but suffice to say it is to support a highly configurable data retrieval system which supports as-yet unknown input data configurations.
Help!
Thanks,
Geoff
Am not completely sure if it is the best solution, but in the end I created a new directory class for basic components and then set it up in the app service provider as a singleton. The constructor for the directory class loaded all models of several relevant classes and made them available as collections throughout the app.
I am brand new to Magento and the documentation, primarily the phpDocs, are difficult to navigate. For example,
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
In the php doc for Class Mage_Eav_Model_Entity_Attribute_Set there is no mention of the method getAttributeSetName() either in inherited methods or otherwise and yet this works.
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
echo $attributeSet->getAttributeSetName();
So I suppose I have several questions.
Can someone explain to me why the documentation is this way?
Where I can find the mysterious getAttributeSetName() method in the phpDocs?
My theory is that there is some inheritance or a design pattern implementation going on that I'm not understanding, maybe someone can shed some light on this for me.
If you really want to fry your brain, take a look at the source code for Mage_Eav_Model_Entity_Attribute_Set and follow the inheritance chain all the way back. You won't find a getAttributeSetName method defined anywhere.
All Magento objects that inherit from Varien_Object can have arbitrary data members set on them. Try this.
$attributeSet = Mage::getModel('eav/entity_attribute_set')->load($id);
$attributeSet->setFooBazBar('Value');
var_dump($attributeSet->getFooBazBar());
var_dump($attributeSet->getData('foo_baz_bar'));
var_dump($attributeSet->setData('foo_baz_bar','New Value'));
var_dump($attributeSet->getFooBazBar());
You can also get all the data members by using
var_dump($attributeSet->getData());
but be careful dumping these, because if there's a data object that has a circular reference and you're not using something like xDebug, then PHP will have a fit trying to display the object.
Magento stores data properties in a special _data array property. You can get/set values in this array with getData and setData. Magento also has implemented magic getting and setter methods, so when you say something like
$object->getFooBazBar();
The method getFooBazBar is transformed into the data property foo_baz_bar. and then getData is called using this property. It's a little tricky to get your head around, but once you get it you'll start to see how much time you can save using this pattern.
One side effect of this is, of course, it's impossible to infer what data properties any object might have by looking at it's class file, so there's no phpDocs for these methods.
In Magento, i know that you can do the following to get collections:
Mage::getResourceModel('module/model_collection');
and
Mage::getModel('module/model)->getCollection();
This all comes from the fact that you can provide your own custom name for collection
for example: Mage::getResourceModel('module/model_blahblahblah');
so getCollection will automatically find that for you.
My question is when would you actually want to use 'blahblahblah' instead of 'collection'
The difference between 'normal' resource model and collection are:
'normal' resource model -> extends from Mage_Core_Model_Resource_Db_Abstract (for flat type, version 1.6.0.0 ++). It is mainly used to connect with your database, such as get data / saving data to database
collection -> extends from Mage_Core_Model_Resource_Db_Collection_Abstract (for flat type). It is mainly used to get 'LIST' of your data. e.g. : get list of orders
So for your question: when would you actually want to use 'blahblahblah' instead of 'collection'
There is no exact answer for that. It is not a must to use name collection to get the list of data. You can use blahblahblah if you want but of course it is better to stick to the convention (Magento's way).
Naming it as collection will give 'normal' people a picture that it is related with collection (collection usually related with list, in our case it is a list of data / object / etc). What will happen if they see: Mage::getResourceModel('module/model_blahblahblah'); maybe blahblahblah is too weird to understandable by other people (though the name won't be as extreme as blahblahblah)
If you want to change your collection class:
Namespace_Module_Model_Mysql4_Module_Collection
to Namespace_Module_Model_Mysql4_Module_Blahblahblah
then you can use Mage::getResourceModel('module/model_blahblahblah') method for getting collection.
Was that helpful?
I'm a little confused about calls I see to Mage::getSingleton, and I'm hoping someone can help me understand a little better.
I have seen a piece of core code that does this:
Mage::getSingleton('customer/session')->isLoggedIn()
I don't know PHP, but I think I can make a safe assumption from the getSingleton method name that there will be only one instance of the class specified (the class being specified as a grouped class name, and resolving to app/code/core/Mage/Customer/Model/Session.php - containing class Mage_Customer_Model_Session.
Question 1 -
How did the getSingleton method know to look in the Model folder for the class?
Question 2 -
So there is one instance of the class for the whole ... I want to say JVM as I am from a Java background, but I'll say PHP engine in the hope that that is vaguely the correct terminology; the Mage_Customer_Model_Session is not passed in a customer id or any such identifier, yet we call the method isLoggedIn()! Give there is not a Mage_Customer_Model_Session instance per customer, how can we ask a singleton if a customer is logged in when we do not tell it what customer we are talking about?
Question 3 -
I've seen calls to Mage::getSingleton('core/session') and to Mage::getSingleton('customer/session') - what is the difference?
Thank you for any help.
First, before we get to Magento, it's important to understand that PHP has a radically different process model than Java. A PHP singleton (regardless of Magento's involvement) is a single instance of a class per HTTP Request. A PHP program isn't persistent in memory the same way a Java program is, so adjust your expectations of a "singleton" accordingly.
Next, it's important to understand that Magento is a framework built on top of PHP, using PHP, and in many cases the original Magento developers wanted to push things towards a more Java like architecture. So, you're going to see things that look familiar, are familiar, but likely differ in some major way from what you're used to because they still need to hew to PHP's version of the universe.
Magento uses a factory pattern to instantiate Helpers, Blocks, and "Model" classes. The string
core/session
is a class alias. This alias is used to lookup a class name in Magento's configuration. In short, this string is converted into path expressions that search Magento's configuration files to derive a classname, based on the context (helper, block, model) it was called in. For a longer version, see my Magento's Class Instantiation Autoload article.
The concept of a "Model" is a little fuzzy in Magento. In some cases models are used as domain, or service models. In other cases they're used as a more traditional middleware database persistence models. After working with the system for a few years, I think the safest way to think about Models is they're Magento's attempt to do away with direct class instantiation.
There's two ways to instantiate a model class.
Mage::getModel('groupname/classname');
Mage::getSingleton('groupname/classname');
The first form will get you a new class instance. The second form will get you a singleton class instance. This particular Magento abstraction allows you to create a singleton out of any Magento model class, but only if you stick to Magento's instantiation methods. That is, if you call
Mage::getSingleton('groupname/classname');
then subsequent calls to
Mage::getSingleton('groupname/classname');
will return that singleton instance. (This is implemented with a registry pattern). However, there's nothing stopping you from directly instantiating a new instance of the class with either
$o = Mage::getModel('groupname/classname');
$o = new Mage_Groupname_Model_Classname();
Which brings us to sessions. PHP's request model, like HTTP, was originally designed to be stateless. Each request comes into the system with, and only with, information from the user. As the language (and the web) moved towards being an application platform, a system that allowed information to be persisted was introduced to replace the homegrown systems that were cropping up. This system was called sessions. PHP sessions work by exposing a super global $_SESSION array to the end-user-programmer that allow information to be stored on a per web-user basis. Sessions are implemented by setting a unique ID as a cookie on the user end, and then using that cookie as a lookup key (also standard practice for web applications)
In turn, the Magento system builds an abstraction on top of PHP's session abstraction. In Magento, you can create a "session model" that inherits from a base session class, set data members on it, and save/load those data members just as you would with a database persistence model. The difference is information is stored in the session instead of the database store. When you see
core/session
customer/session
these are two different session models, with each one storing different data. One belongs to the Mage_Core module, the other belongs to the Mage_Customer model. This systems allows modules to safely set and manipulate their own session data, without accidentally stepping on another module's toes, and provide logical class methods for manipulating that data.
Hopefully that answers the questions you asked, as well as the ones you didn't.
Magento's getSingleton is almost the same as getModel. The difference is getModel always returns a new instance of a class, and getSingleton creates a new instance of a class only once and then always returns this instance. See the Mage::getSingleton and Mage::getModel methods.
Magento knows about looking to the Model folder because of configs in the config.xml file (f.e. Mage/Customer/etc/config.xml). See the Magento wiki for developers to know more about config files.
You do not specify customer directly. It's done automatically by Magento in parent classes of Mage_Customer_Model_Session (see Mage_Core_Model_Session_Abstract_Varien::start() method)
Magento has not one session class to discriminate session data. For example, customer ID is stored in Mage_Customer_Model_Session and error flash message 'Product is not available' will be stored in the Mage_Catalog_Model_Session class.
I am learning Magento currently and in particular how models and the ORM works.
As far as I can make out there are Models (which are the actual entities), Resource Models (which links directly with the database adapter) and Collections (which are containers to hold collections of models).
Why then, is there a ton of code and examples that use the Mage::getResourceModel() instead of just Mage::getModel() - particularly when grabbing a collection i.e. Mage::getResourceModel('catalog/product_collection').
The only reason I can see would be that Mage::getModel() would have to go through the resource model at some point so it may be more efficient to go directly to the resource model. However, isnt this bad practice?
As far as I know, all collections in Magento are resource models. They are instantiated by Mage::getResourceModel() or Mage::getModel()->getCollection(). It doesn't really matter which function you use; the latter one simply calls the first one. The Magento team simply chose to make collections part of the resource, probably because collections need to query the database a lot. Usually, you will not have to call Mage::getResourceModel() for anything else than collections.
Mage::getResourceModel()
As far as I know, all collections in Magento are resource models. They are instantiated by
Mage::getResourceModel()
or
Mage::getModel()->getCollection()
It doesn't really matter which function you use; the latter one simply calls the first one. The Magento team simply chose to make collections part of the resource, probably because collections need to query the database a lot. Usually, you will not have to call Mage::getResourceModel() for anything else than collections.