Solving Magento

Solutions for Magento E-Commerce Platform

by Oleg Ishenko

Magento’s Front Controller

The basic experience of a web user is browsing web documents requested by URLs. In the beginning of the Internet most web documents were static HTML files stored on a server. Later, these documents started being dynamically generated, but in the essence almost every requested URL was processed by a separate file that it was matched to. Such approach is known as Page controller. Martin Fowler describes it as “one path leading to one file that handles the request”. He also adds, that this “is a simple model to understand”. However, its apparent simplicity becomes an issue in a complex web application such as an e-commerce site. There can be hundreds if not thousands of possible request types. Creating and maintaining a file for each of them is a laborious and inefficient task. And there are many subroutines which are shared among request processors. Initializing resources, establishing database connections, starting sessions and authenticating users – these and many other tasks are repeated every time a web application handles a request.

A solution to this problem is known as Front Controller. This design pattern channels every incoming request to a single point of entry – a front controller. This handler object performs all the common subroutines and then dispatches the request to a controller that handles specifics. The adoption of this approach is wide-spread owing to its flexibility and scalability.

So in a nutshell, a front controller is comprised of two parts – a web handler and command dispatcher.

The web handler‘s task is to parse the request URL and extract information that is necessary to find a delegate controller to which the request will be routed for processing. Usually this information is located in the path part of the URI, but query parameters can be used as well. The routing information normally includes the names of a controller and its action (command). The path can be first checked for a URL-rewrite, for example, in web applications that use human- or SEO-friendly URLs. In this case the routing information is extracted from a resource, which contains URLs matched to controller and action names. Once the controller is found, the command dispatcher instantiates it and calls the matched action.

Magento also features a front controller. If you take a look into the root folder of your application you find only a handful of *.php files and among them index.php.
In Magento index.php is the entry point for every incoming request. This is ensured by Apache’s module mod_rewrite and rewrite rules in the root folder’s .htaccess file:

############################################
## never rewrite for existing files, directories and links

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l

############################################
## rewrite everything else to index.php

    RewriteRule .* index.php [L]

These rules mean that unless a physical file or directory can be located, the request will be sent to the index.php file.

However, index.php is not a front controller. Magento’s front controller is implemented in a class that is instantiated in the early stages of the request processing. Before that the index.php instantiates the main Magento hub class, Mage. The application is started with the calling of the Mage::run() function. After loading configuration, establishing a database connection, and performing other common routines, the front controller is launched. The front controller is implemented in class Mage_Core_Controller_Varien_Front. Its centerpiece is the Mage_Core_Controller_Varien_Front::dispatch function, which is responsible for matching a URL and dispatching the request. But first, the front controller has to be initialized.

The Mage_Core_Controller_Varien_Front::init function does the following

  • Dispatches an event controller_front_init_before.
  • Gets the current store’s router configuration (under the node stores/default/web/routers, details). By this time Magento has already loaded all the module config XML files (more on extending the Magento router configuration). Once loaded the $routerInfo variable contains an array of two routers: admin and standard. Having this information, the system begins iterating through these routers and collect information from the module configurations, which extend them, by looking up the frontName nodes. This is achieved by calling Mage_Core_Controller_Varien_Router_Standard::collectRouters. The admin router will contain routing configurations for the administration back end part of the website, while the standard will be comprised of configurations for the front end.
  • Once the router configuration is collected, the system dispatches an event controller_front_init_routers. This event is observed by Mage_Cms_Controller_Router::initControllerRouters function, which adds a cms router to the front controller.
  • Finally, the front controller adds a default router of type Mage_Core_Controller_Varien_Router_Default. This router will be matched last.

Thus, the front controller initialization includes reading the router configuration from the system configuration objects and arranging the module routing extensions into four routers: admin, standard, cms, and default. This means that whatever router rewrites you have specified in your modules are now available to the front controller. The dispatch() function is now ready to go. It does the following:

  • Checks if the request URL matches the base URL, which is set in the shop configuration. If not, the system performs a redirect to the base URL. The redirect code is set in the configuration node web/url/redirect_to_base and can be null (in which case the further check is not performed), or 301, or 302.

  • Performs URL rewrites by searching for a URL in the core_url_rewrite table. This is done by function Mage_Core_Model_Url_Rewrite::rewrite. This function loads all entries from table core_url_rewrite that match the path info string (the URI path, the part between the host name and the query string, e.g. if the URL is http://www.test.com/sony-vaio-notebook-pc.html?showID=1 then the path info would be sony-vaio-notebook-pc.html). The found entries contain the target_path (e.g. catalog/product/view/id/144) that is used to locate the controller and action to which the request must be be dispatched. If no match is found, the rewrite function will return false and the router matching will use the original path info. Otherwise, the found target_path will be used as a new path info. It will be amended with a query string, if such was provided with the request.

  • Processes configuration rewrites. The front controller uses its function rewrite to retrieve configuration nodes under path global/rewrite. If such configuration entries are found, the front controller rewrites the path info property of the request object accordingly.

  • Finds a router match. As we have established, there are already 4 routers known to the front controller: admin, standard, cms, and default. These will be iterated through to match the controller and action parameters parsed from the URL. The loop, in which it is done, is nested.
    • The upper loop will iterate until either a request is matched or the loop count exceeds 100. It is done because some routers can be rewritten multiple times. In this case the inner loop will break and fall back to the external loop to match a rewritten request again. The limit of 100 iteration is set to avoid erroneous recursive rewrites, which otherwise would lead to an infinite matching circle. Upon reaching the iteration limit the system throws the “Front controller reached 100 router match iterations” exception.
    • The inner loop will go through all 4 routers. If a match is found, i.e. there is a valid controller class that has a callable action, the request is dispatched – the request is processed by the found controller. If no match is found in the first 3 routers, the request is transferred to the last, default, router that generates a noRoute output that is a 404 error page.
  • The matched request is now dispatched. Before outputting the generated HTML (or any other form of output: XML, JSON) the front controller sends a controller_front_send_response_before event. After the response is sent, a controller_front_send_response_after is dispatched.

As you can see the Magento’s front controller encapsulates the request processing from the moment after the application is initialized and until the output is ready to be sent back to the client. The router matching and request dispatching to a controller is a demonstration of a command-based pattern: a command is recognized from the request and executed. You can add new commands (create new controllers) without altering the front controller. Compared to their complexity the front controller is relatively simple, and its tasks are narrow: routing and dispatching.

Readers who read this post also read these:

  • Magento URL Rewrites
    Magento is a web application implementing a Front Controller pattern, and this means that most HTTP requests are routed to the index.php file in the root folder. In order to display a category, a p...
  • Magento OnePage Checkout Part 2: Model, Views, Controller
    This is part 2 of the One Page checkout discussion. You can find more about this checkout type in the Magento OnePage Checkout Part 1 and Magento OnePage Checkout Part 3: JavaScript. Checkout Comp...
  • Improving Magento Performance with APC Opcode Caching
    What is Opcode and why cache it? As you know, PHP is an interpreted language, and every instruction in your code has to be compiled into intermediate language before being passed over to the web s...
  • OneStep Checkout – A Magento Tutorial, Part 4 (Steps 11 and 12)
    This is the last part of the long tutorial on the Magento checkout customization. here, I will describe the last checkout section "Order Review" and explain how the OneStep checkout link can be add...

3 thoughts on “Magento’s Front Controller

  1. Pingback: Magento URL Rewrites | Solving Magento

  2. Hello,

    Is compilation process independent of number of store a Magento website implements.

    I have created 2 different store for a website and have enabled compiler, But only default stores works and other store give me a blank page.

    Any comments/suggestion on this?

Leave a Reply

Your email address will not be published. Required fields are marked *

Theme: Esquire by Matthew Buchanan.