I want to know why are the steps to extend magento controller different from model or block. Why cant a controller be extended like other magento classes are overridden? Why do we have to include the class file in the file which is extending it in case of controller?
In short: This is how Magento was designed (not to allow override the controller as with Model, Helper and Block). I mean they are free to design the whatever they want.
In long: You can always instantiate Model, Block, Helper via Factory method, usually, Mage::getModel('your/model'), Mage::getBlock('your/block') and Mage::getHelper('module/helper'). However, it is not possible to instantiate controller this way.
The factory method Mage::getModel() checks all configurations files (usually files in et/config.xml of all modules) to determine overloading. However, Controller class are determined by Router based on complex, multi-level system routing.
Related
I am new in codeigniter framework.I have some question.When we write some controller class then we call constructor.I am loading some library and some helper.I want to know what is the perfect way for loading this helper and library under construct class or under other functions.If i load everything in construct class then what is the disadvantages for it?if i use more controller class for one project then it is good or bad.Like i want to use some controller class for ajax functionalities,some for form submission,some for other sector.My english is not so good.Please help me.
For common libraries and helpers used by all functions of your controller try to load it in constructor or autoload. Except that for specific libraries e.g. payment gateway load inside the function.
How you use or how many controllers you are using depends upon your needs. But I would suggest you to build separate controllers for separate functions. Like admin for admin functions, users for user related functions, and so on. It build a user friendly URL too.
Well! everything depends on your requirements.
If you need any library , model or helper globally you can autoload it autoload.php.
It means the loading will be done on each request.
if you need any library , model or helper throughout your controller methods you can load them in constructor.
It means loading will be done on each method of controller.
if you need any library , model or helper for specific method you can load them in method.
It means loading will be done in method only.
For example let suppose you nees session and database library throughout your application so you can autoload it.
For a specific controller you need priviliges library so load it in constructor.
For email you need to send load email library in function.
These are only examples. You can explore SO to find more.
Loading takes time and performance. Not noticeable time by human standards, but time regardless. In order to cut of some slack to your server in the future, you do it a favor by only loading whatever is it you require for each page/controller method.
Used (almost) always
You can use application/config/autoload.php for things you almost always use. I usually include the helper url here.
Used (almost) always inside specific controller
Load it inside controller __construct. Don't forget to include parent::__construct();.
Used inside specific page
Load it inside method/function.
Used inside specific function
Load it at beginning or inside if-statement in function. You can load it numerous of times, it will only execute first time.
We're currently developing an E-commerce site. We have a public and admin module.
Sometimes we offer the same functionality in both modules like viewing of products or creating of orders. But there are also some functionalities that is present in either public or admin like adding of products (which is in admin).
Our problem is that common functionalities lead to duplication of logic. We need to implement it in both modules.
One way of solving the problem is to make use of layers. So what we did was move the common logic into the Model. However, the controller is still duplicating codes like the one shown below:
public function invoice() {
$this->Invoice->create();
$this->Invoice->setCustomer($this->getCurrentUser);
$invoice_items = // get list of items from post
$this->Invoice->setItems($invoice_items);
$this->Invoice->save();
}
My question is, is it wise to create a webservice that will encapsulate this logic and you just have to call it from the admin and public modules..
How does Magento implement the public and admin panels. And how does it manage its logic..
I would recommend you not to do that. From your question, it is not exactly clear what sort of 'logic' are you referring to, but it does not seem too complex from your example. In general, business logic should be coded within the Model, controller, or Helper portions of the code. It can even reside in a separate extension as long as you set dependencies properly in the main xml file of the extension.
It seems that you may benefit from placing your logic in a helper class. The default helper file resides under /app/code/community/company/extension-name/Helper/Data.php. Then you can call the helper method anywhere in the backend (Block, Module, or controllers) by using this piece of code:
Mage::helper('extension-name')->getLogic()
Or you can call the same helper method from the view (phtml files) like this:
$this->helper('extension-name')->getLogic()
I wrote a three cascade dropDownLists that its listData are generated from the database models.
The lists are generated with an Ajax call to action in the controller based.
I want to reuse this code and to share it with more pages.
I tried to do the following:
Write it as a Custom Widget.
currently i use 'createurl' function that calls a function in the matching controller.
I cant write JavaScript since i want to use the existing db models.
In this case i need to write the action functions in an independent file - so should i write a controller? where should i place it?
Write it as a part of a module - but it seems overkill.
any suggestions, i am sure that there is a right and simple way to do it.
You could create it as a helper. A helper is just a class in the components which has no direct action in the M->C->V action flow but can be used in any controller, model, view, component, module, etc...
I would write a helper method to call it from the controller.
Another suggestion could be to extend CController to your own base controller and have your actual controllers, extend from your custom base controller. That way you can make it easily available in every controller, and then you just set some members that contain the models to use which you set in the actual controller.
If you need more help on this, find me on freenode #yii
I find myself needing to have a View expose its Model and Controller references. Is this the smell of bad design? Or is this considered "safe" practice?
For example: I have a list (composed of a ListView, ListController, and ListModel) and many list items (composed of a ItemView, ItemController, and ItemModel).
When I create the ItemModel, ItemView, and ItemController for each list item, I pass the ItemView instance off to the ListView. But, at some later point, my ListController needs a reference to the corresponding ItemController instance.
So, would it be more proper to pass both the ItemView and the ItemController in to ListView::addItem(), or just pass in ItemView and expose an instance method such as ItemView::getController()?
Or doesn't it matter? Is each approach equally viable? If followed to their logical conclusion, does either tactic result in an anti-pattern?
But, at some later point, my ListController needs a reference to the corresponding ItemController instance
Why? If you're decoupling your classes properly, you shouldn't need this.
Controllers almost always address a functional domain. An example of such a domain might be "Sales" or "Admin." In addition, MVC also supports the use of "Areas," which provides an additional hierarchical level of organization.
Adding references to controllers from other controllers is at cross-purposes with this organizational structure. If you need to combine functionality to make your code more DRY, ordinary refactoring will accomplish that. You can also inherit controllers from a base class containing common functionality.
In the mvc pattern the users request shall be routed to a controller, say invoicecontroller, that has actions.
Lets say the default action, Index, returns a list of invoices; the controller then creates a model with a list of invoice objects, instantiates the correct view and injects the model into the view.
Now it is the views turn to do its magic. It renders the best view it can with the data it has, which may include routes to one or more controllers.
In NO instance should the view (or model) do business logic themselves.
That said, I totally agree with Jakub. Hope that helps.
Considering you are not actually showing any code at all.
In my opinion, you should change your design. A controller is not supposed to communicate with another controller (directly), MVC dictates it: reference.
If you need to invoke a controller action from another controller, consider using delegates or composition. Instead of directly invoking the controller action.
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.