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.
Key Takeaways
- Magento is a highly scalable e-commerce solution trusted by many businesses, from small enterprises to larger corporations, offering a structured approach to online store management.
- Proper file permissions setup is crucial in Magento installation, with specific permissions for directories and files to ensure security and functionality before and after running the installer.
- Magento’s architecture includes a variety of directories such as Block, Controller, Model, Helper, etc., each serving specific roles from business logic execution to database interaction and layout rendering.
- The request flow in Magento starts with the web server passing the request to the index.php file, leading to application initialization and routing to appropriate controller actions based on configured URL rewrites and router settings.
- Best practices in Magento development include adhering to coding standards like PSR-1 and PSR-2, utilizing dependency injection, and avoiding direct use of ObjectManager and raw SQL queries to enhance code quality and maintainability.
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_Config
→ getModuleDir()
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 includedcall
Mage::run($mageRunCode, $mageRunType)
in ‘run’, we load Varien Events Collection, the class
Mage_Core_Model_Config
and the classMage_Core_Model_App
Mage_Core_Model_App::run()
is triggeredload 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 htmloutput 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 (classMage_Core_Controller_Varien_Router_Admin
), Default (classMage_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 anindex.php
file or a path that uses access rewrite rules toindex.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 directoryMage::helper('{module}/{path to file in helper directory}')
– returns a singleton instance of a class in the Helper directoryMage::getSingleton('{module}/path to file in model directory')
– returns a singleton instance of a class in the Model directoryMage::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 theMage_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 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.