Magento Basics, Request Flow, Standards and Best Practices

Share this article

Nowadays, companies are migrating their businesses online more and more. They’ve chosen to direct their attention to online communication in order to stay closer to their potential buyers, to make use of social websites to inform people about their products/services and, finally, to find a workaround that provides people with a buying process directly from home, work office or any place with an Internet connection.

One of the solutions for e-commerce that gained trust from lots of companies is Magento. It supports small businesses, but also scales to larger sizes.

Alongside the expansion of e-commerce came across the need for experts to maintain and customize functionalities for their specific shop infrastructure.

In this article we will discuss the initial step that needs to be accomplished by a developer in order to get familiar with Magento’s structure and be ready to start adding custom functionality.

Magento’s Basics

A free version of Magento Community Edition can be downloaded from here, the official Magento website.

Assuming we have already configured a virtual host in a local environment and extracted Magento in the desired folder, before firing the installer, file permissions needs to be set correctly. Here are the steps:

  • set all directories and subdirectories from the application to 775

  • set all files to 644

  • set directory app/etc/ and all its files and subdirectories to 777

  • set directory var/ and all its files and subdirectories to 777

  • set directory media and all its files and subdirectories to 777

In a linux system you can achieve all this by typing the following commands in your Magento folder:

find . -type d -exec chmod 775 {} \;
find . -type f – exec chmod 644 {} \;
chmod 777 -R app/etc/
chmod 777 -R var/
chmod 777 -R media/`

After the installer is done working, file permissions from app/etc should be changed back – directories to 775 and files to 644, for security reasons.

Code pools

Modules are located in app/code/ in the existing code pools: core, community (deprecated) and local.

Each module has a corresponding configuration in an .xml file in app/etc/modules/ and has defined a syntax like <codePool>local</codePool> from which Mage_Core_Model_ConfiggetModuleDir() will point to the module’s path.

Module structure

Block

The files in this folder inherit or load data and transfer it to the templates from your theme (.phtml files).

controllers

Controllers represent the business logic, containing specific actions that are matched for a given request (dispatch(), preDispatch(), postDispatch() methods) and delegate commands to the other parts of the system.

Helper

In the Helper directory you can create class files with utility methods, parsing methods and other generally helpful methods for your store which are commonly used by the whole system. Methods declared in helpers can be called from any template file or block, model or controller. Magento is returning a singleton instance for helper classes.

Controller

In this directory routes can be defined, used to match module-controller-action based on the request, template layers for controller classes, etc. For an example, see the “Paypal” module.

Model

Usually contains classes that correspond to database tables. Models can be used as regular models that use two resource classes (one for reading and one for writing) to communicate with the database, resource models used to prepare query data for database communication, service models used as standalone classes that define a process flow, helper models used as standalone classes with individual methods for computing more complex algorithms than regular Helpers, and so on.

etc

Contains module behavior configurations. Each module must have at least a config.xml file and declare paths for models, blocks, helpers, routers, etc.

sql

Each module can come along with sql installers to prepare database entities. Installers have a group name defined in each module/etc/config.xml and each sql installer has a version for order iteration purposes.

data

Almost the same functional statement as sql installers, but with a different scope: will not create/update table schemes and attributes, instead it will update existing records or populate database tables with default records.

doc

A folder dedicated to documentation and module explanation.

Templates and Layout

The layout in Magento is kept in app/design/ and has a well defined structure for default and custom theming. Loading hierarchy within its priority and file existence starts with the custom theme. If not found, it will search the .phtml file in default theme and if still not found, the last search path will be the base theme.

Magento establishes the theming structure in high-level areas such as adminhtml (system administration templates), frontend (the visible template for an end-user), installer (templates for the helper system that will automatically configure the shop).

Each theme has a folder ‘layout’ with .xml files (usually each module has its own referred layout configuration file) that defines a block of content for a controller action.

The custom theme may also contain a folder called ‘locales’ that will keep a file ‘translate.csv’ where all the custom translations are kept or even override existing ones already defined in standard Magento.

Skin and Javascript

The CSS files, images, and custom JS are located in the directory skin/ and implement the same theming structure and loading priority as for Templates and Layout (skin/area_name/package_name – a custom namespace can be defined or base or default/theme_name).

Class naming conventions

Magento applies the basic, albeit outdated Zend class naming convention and uses Varien_Autoload::register() to autoload classes by replacing the ‘_’ in the name with a directory separator to find the inclusion path to the file. This is very primitive, but due to backwards compatibility could not be solved sooner – Magento 2 will use ZF2, modern PHP and namespaces.

Request Flow

Let’s see how a Magento application handles a request starting from the main index.php file.

Application Initialization

1) If you use Nginx, you should follow the configuration guide. If you’re on Apache, these are the rewrite rules for .htaccess from the main application directory that shouldn’t be missing.

Rewrite rules for skin, media, JS directories to allow loading files and, if not found, to return 404. Everything else is rewritten to index.php:

<IfModule mod_rewrite.c>

############################################
## enable rewrites

    Options +FollowSymLinks
    RewriteEngine on

############################################
## always send 404 on missing files in these folders

    RewriteCond %{REQUEST_URI} !^/(media|skin|js)/

############################################
## 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]

</IfModule>

2) These are the steps the application follows when initialized:

  • run file index.php where app/Mage.php is included

  • call Mage::run($mageRunCode, $mageRunType)

  • in ‘run’, we load Varien Events Collection, the class Mage_Core_Model_Config and the class Mage_Core_Model_App

  • Mage_Core_Model_App::run() is triggered

  • load configuration files from app/etc/modules

  • load configuration xml files inside modules app/code/{code pool}/{module name}/etc/config.xml

  • initialize current store

  • initialize request object

  • run sql and data installers

  • update/create versions of modules in core_resource

  • Front Controller dispatch – Mage_Core_Controller_Varien_Front::dispatch();

  • collect routers from config by Area and Route Code

  • use routes to match Controller

  • if a controller and action will be matched, the controller file will be included, instantiated and action method will be called

  • action method will instantiate and call methods on models, depending on the request

  • the Varien Action Controller will call a Layout Object

  • this Layout Object will create a list of Block objects that are valid for this request, based on some request variables and system properties (also known as “handles”)

  • template files (.phtml) are assigned in the layout xml file for each block.

  • _prepareLayout() method is called where, based on action layout xml structure, specific blocks are instantiated within associated .phtml files

  • _toHtml() method is triggered to generate html

  • output html

Front controller

1) the properties and role of the Front Controller:

  • directory path: app/code/core/Mage/Core/Controller/Varien/Front.php

  • base role: receive all requests from the browser and return HTML code

  • Front controller uses routes of the system to match a controller class and its action method

  • default Magento routers are: Standard (class Mage_Core_Controller_Varien_Router_Standard), Admin (class Mage_Core_Controller_Varien_Router_Admin), Default (class Mage_Core_Controller_Varien_Router_Default)

Here’s is an example of a defined route in the Customer module’s /etc/config.xml:

<routers>
    <customer>
        <use>standard</use>
        <args>
            <module>Mage_Customer</module>
            <frontName>Customer</frontName>
        </args>
    </customer>
</routers>

2) events that Front Controller triggers:

  • controller_front_init_before

  • controller_front_init_routers

  • controller_front_send_response_before

  • controller_front_send_response_after

URL rewrites

URL structure/processing in Magento.

A link in Magento has the below structure:

https://user:password@host:443/{base_path}/{base_script}/{storeview_path}/{module_front_name}/{controller_name}/{action_name}/{param1}/{value1}?{
query_param=query_value#fragment}

  • user:password@host:443/{base_path}/{base_script}: the path to the Script file which runs Magento. Usually, it is an index.php file or a path that uses access rewrite rules to index.php

  • {storeview_path}: store view code will be used if the website has a multi-store-view model (e.g. multi-language support that is marked in the url)

  • {module_front_name}/{controller_name}/{action_name}: the path to match a module controller and action method

  • {param1}/{value1}: name and value of a parameter sent by url

  • ?query_param=query_value#fragment: parameters query sent via the standard GET request

The above link will traverse through the following files, each contributing to match a schema for url and call the correct module-controller-action to output content:

  • app/Mage.php (Mage::app()->run())

  • app/code/core/Mage/Core/Model/App.php

  • Init and Dispatch controller $this->getFrontController()->dispatch();

  • app/code/core/Mage/Core/Controller/Varien/Front.php

  • choose the defined router from config.xml to match module-controller-action $router->match($this->getRequest())

    • app/code/core/Mage/Core/Controller/Varien/Router/Admin.php
    • app/code/core/Mage/Core/Controller/Varien/Router/Standard.php
    • app/code/core/Mage/Core/Controller/Varien/Router/Default.php
  • app/code/core/Mage/Core/Controller/Varien/Action.php

  • call Action method (example: indexAction())

URL rewrite process

Url is rewritten in the following cases:

  • core url rewrite: having priority over routers, will try to translate a custom request path to standard module/controller/action path based on the defined rows in database (core_url_rewrite table)

  • module name rewrite: a front name will be defined in a module’s config.xml to rewrite the actual path and name (example: Mage_Customer will be matched by url through using its defined front name ‘customer’)

  • custom routers will rewrite the url (mostly used for SEO purposes): for the default Magento an example will be the CMS module that will match a url-identifier like homepage.html to module ‘Mage_Cms’, controller ‘Page’, action ‘View’ and a parameter id that will match the cms entity row in the database.

Standards and Best Practices

Sample configuration xml

This is a sample of module config.xml (path: {base_app_folder}/app/local/{module_name}/etc/config.xml) that includes the main configuration:

<?xml version="1.0"?>
<config>
    <modules>
        <{{localnamespaceC}}_{{modulenameC}}>
            <version>0.1.0</version>
        </{{localnamespaceC}}_{{modulenameC}}>
    </modules>
    <global>
        <models>
            <{{localnamespaceL}}_{{modulenameL}}>
                <class>{{localnamespaceC}}_{{modulenameC}}_Model</class>
            </{{localnamespaceL}}_{{modulenameL}}>
        </models>
        <resources>
            <{{localnamespaceL}}_{{modulenameL}}_setup>
                <setup>
                    <module>{{localnamespaceC}}_{{modulenameC}}</module>
                </setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </{{localnamespaceL}}_{{modulenameL}}_setup>
        </resources>

        <blocks>
            <{{localnamespaceL}}_{{modulenameL}}>
                <class>{{localnamespaceC}}_{{modulenameC}}_Block</class>
            </{{localnamespaceL}}_{{modulenameL}}>
        </blocks>

        <helpers>
            <{{localnamespaceL}}_{{modulenameL}}>
                <class>{{localnamespaceC}}_{{modulenameC}}_Helper</class>
            </{{localnamespaceL}}_{{modulenameL}}>
        </helpers>
    </global>
    <frontend>
        <routers>
            <{{localnamespaceL}}_{{modulenameL}}>
                <use>standard</use>
                <args>
                    <module>{{localnamespaceC}}_{{modulenameC}}</module>
                    <frontName>{{modulenameL}}</frontName>
                </args>
            </{{localnamespaceL}}_{{modulenameL}}>
        </routers>
        <layout>
            <updates>
                <{{localnamespaceL}}_{{modulenameL}} module="{{localnamespaceC}}_{{modulenameC}}">
                   <file>{{modulenameL}}.xml</file>
                </{{localnamespaceL}}_{{modulenameL}}>
            </updates>
        </layout>
    </frontend>
</config>

Legend:

  • localnamespaceC and localnamespaceL is the name of your chosen namespace directory in app/local/{namespace} (C is for uppercase first letter of the word, and L for lower case)

  • modulenameC and modulenameL is the name of your module in app/local/{namespace}/{modulename}

Magento’s factory methods

Magento makes use of factory methods to instantiate models, helpers and blocks. The methods are:

  • Mage::getModel('{module}/{path to file in model directory}') – returns an instance of a class in the Model directory

  • Mage::helper('{module}/{path to file in helper directory}') – returns a singleton instance of a class in the Helper directory

  • Mage::getSingleton('{module}/path to file in model directory') – returns a singleton instance of a class in the Model directory

  • Mage::getResourceModel('{module}/{path to file in model/resource directory}') – returns an instance of a class in the Model/Resource directory.

  • Mage::getBlockSingleton('{module}/{path to file in block directory}') – returns a singleton instance of a class in the Block directory after the layout for a controller action was initialized.

Rewriting the core

Magento’s architecture offers several ways to rewrite core files. Let’s see what they are and list some pros and cons:

a) rewrite a file by creating a similar directory path and file name in the ‘local’ code pool

  • you need to copy entire class with all its properties even if one line of code needs to be changed (downside)

  • if the file is also overridden in a custom module, the tracking for applied change previously may be lost due to the fact that it doesn’t respect the standard developers are used to.

b) rewrite the file in a Custom Module (local/MyNamespace/MyCustomModule/) and create a subdirectory with the core module name and add the original subdirectory tree (e.g. local/MyNamespace/MyCustomModule/Model/Core/Rewrite.php).

  • to override a file in a custom module name and not using Magento’s module name for this purpose will also confuse developers and the tracking of those changes may be lost by adding another rewrite in a different place. However, by adding module configuration (in app/etc/modules/MyCustomModule.xml) to mark dependency to the Mage_Core module you can give developers a heads up that a file rewrite was made.

c) rewrite a file in a Custom Module with Magento’s module name and preserve path (e.g. local/MyNamespace/Core/Model/Rewrite.php)

  • this rewrite method is the most clear as developers can keep track of changes due to the naming convention.

  • will encourage other developers working on the same side to extend already changed functionality and not override it

  • a small disadvantage for this rewrite method is that the number of modules in a chosen namespace will grow along with each file that is overriden from different Magento modules.

Dependency between modules

a) when extending a Magento core module, dependency between modules needs to be configured

e.g. app/etc/modules/MyNamespace_Customer.xml:

<MyNamespace_Customer>
    <active>true</active>
    <codePool>local</codePool>
    <priority>1</priority>
    <depends>
        <Mage_Customer/>
    </depends>
</MyNamespace_Customer>

b) when creating an sql installer or data installer in the Custom Module that updates the Magento core module entity, a dependency needs to be created

e.g. installer in MyCustomModule:

$installer = $this;
$installer->startSetup();

$sqlQuote = 'ALTER TABLE ' . $this->getTable('sales_flat_quote') .
    ' ADD `is_urgent` TINYINT UNSIGNED NOT NULL DEFAULT 0';

$installer->run($sqlOrder);
$installer->run($sqlQuote);

$installer->endSetup();

e.g. dependency config (sales quote entity is altered, dependency with ‘Sales’ module needs to be added):

<MyNamespace_MyCustomModule>
    <active>true</active>
    <codePool>local</codePool>
    <priority>1</priority>
    <depends>
        <Mage_Sales/>
    </depends>
</MyNamespace_MyCustomModule>

c) Extending/Rewriting a file (model, helper, block, controller) from the Magento core module requires dependency between modules, otherwise the last changed version will be arbitrary and you will lose control over the rewrite.

Module dependencies are important to prioritize order of sql statements, and on a fresh install they will avoid conflicts, crashes or wrong final data.

Conclusion

In this article, I’ve covered some of Magento’s fundamentals that will help developers understand the basic architecture and have a starting point in building their custom functionalities. If you’d like to see specific upgrades to Magento covered, or have use cases you’re curious about, let us know. Stay tuned for some Magento 2 tutorials and explanations as well!

Frequently Asked Questions on Magento Basics, Request Flow, Standards, and Best Practices

What are the key Magento coding standards and best practices?

Magento coding standards and best practices are a set of guidelines and principles designed to improve the quality, readability, and maintainability of the code. These include following the PSR-1 and PSR-2 coding standards, using dependency injection, avoiding the use of ObjectManager directly, using plugins instead of observers, and avoiding the use of raw SQL queries. Following these standards and practices not only ensures the quality of the code but also makes it easier for other developers to understand and work with the code.

How does the Magento request flow work?

The Magento request flow is the process that Magento follows to handle a request and generate a response. It starts with the web server receiving a request and passing it to the index.php file. The index.php file then initializes the Magento application, which involves loading the configuration files, setting up the dependency injection container, and initializing the application state. The application then routes the request to the appropriate controller action, which processes the request and generates a response. The response is then sent back to the web server, which sends it to the client.

What is dependency injection in Magento and why is it important?

Dependency injection is a design pattern used in Magento to manage dependencies between objects. It involves passing the dependencies of an object as arguments to its constructor, rather than having the object create or find its dependencies. This makes the code more modular, testable, and maintainable. It also makes it easier to swap out dependencies for testing or to change the behavior of the application.

What are Magento plugins and how are they used?

Magento plugins, also known as interceptors, are a way to modify the behavior of public class functions. They allow you to execute code before, after, or around a function call, without modifying the function itself. This makes it possible to change the behavior of a function without changing the core code, which is a key principle of Magento development.

Why should raw SQL queries be avoided in Magento?

Raw SQL queries should be avoided in Magento because they can introduce security vulnerabilities, such as SQL injection attacks. They also make the code harder to maintain and less portable, as they are specific to a particular database system. Instead, Magento provides a set of database access and manipulation methods that should be used.

What are observers in Magento and when should they be used?

Observers in Magento are a way to execute code in response to specific events. They are used when you need to perform an action whenever a certain event occurs, such as a customer logging in or a product being saved. However, observers should be used sparingly, as they can make the code harder to understand and debug. In many cases, plugins are a better alternative.

What are the PSR-1 and PSR-2 coding standards?

PSR-1 and PSR-2 are coding standards defined by the PHP Framework Interop Group. PSR-1 covers basic coding standards, such as file structure, namespaces, class and method names, and constants. PSR-2 covers coding style, such as indentation, line length, control structure syntax, and method and property visibility. Following these standards makes the code more readable and consistent.

How is the application state initialized in Magento?

The application state in Magento is initialized in the index.php file. This involves loading the configuration files, setting up the dependency injection container, and initializing the application state. The application state includes things like the current store, the current customer group, and the current area (frontend or admin).

How are configuration files used in Magento?

Configuration files in Magento are used to define various aspects of the application, such as module dependencies, routing rules, and database schema. They are loaded during the initialization of the application and are used throughout the application to configure its behavior.

How is the response generated in Magento?

The response in Magento is generated by the controller action that handles the request. The controller action processes the request, performs any necessary business logic, and generates a response. The response typically involves rendering a view, which is a template file that generates the HTML to be sent to the client. The response is then sent back to the web server, which sends it to the client.

Adrian MorutanAdrian Morutan
View Author

Adrian is a Web Developer and Initiator who lives in Cluj-Napoca, Romania. He's certified as a Magento Developer and has worked with several PHP frameworks and technologies. Beside programming, he analyses and provides consultancy in finding the most appropriate solutions for web projects and guides development processes.

magentoPHP
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week