The Basics

Exam proportion: 6%.

Fundamentals

Magento uses Object Oriented Programming (OOP) as its programming paradigm which consists of classes, objects and methods. It also uses the Model-View-Controller (MVC) design pattern.

Magento makes use of an Event Driven Architecture (EDA). This is where components of the system are either producers or consumers of events. An EDA allows for loosely coupled, distributed software modules and is, by its nature, a reactionary system that performs actions based on stimuli.

Design Patterns

There are numerous development designs patterns used in Magento (Source).

<?php $product = Mage::getModel('catalog/product'); ?>
<?php $category = Mage::getSingleton('catalog/session'); ?>
<?php $currentCategory = Mage::registry('current_category'); ?>
<?php Mage::dispatchEvent('event_name', array('key'=>$value)); ?>
<config>
    <global>
        <events>
            <event_name>
                <observers>
                    <unique_name>
                        <class>Class_Name</class>
                        <method>methodName</method>
                    </unique_name>
                </observers>
            </event_name>
        </events>
    </global>
</config>
<?php Mage::getModel('catalog/product')->getTypeInstance(); ?>
<?php
$id = Mage::objects()->save($object);
$object = Mage::objects($id);
?>
<?php Mage::getModel('catalog/product')->getCollection(); ?>
<?php Mage::helper('core'); ?>

Constructors

Magento uses public __construct methods and, typically, protected _construct methods for class initialisation. More information on the difference between the two can be found on stackoverflow.

Arguments can be passed to models created through factories by using a second argument, e.g.

<?php
    $instance = Mage::getModel('prefix/model', array(
        `argument_one` => $value_one,
        `argument_two` => $value_two
    ));
?>

The argument parameter to getModel will be passed as is. There is no way to specify more than one argument for the constructor. To get around this restriction, we use an array.

High-Level Architecture

Code Pools

Magento is split up into three code pools.

Typical Module Structure

app/etc/modules/{namespace}_{module name}.xml

Defines the module, the code pool it is in, any dependencies and whether it is enabled.

app/code/{codepool}/{namespace}/{module name}

Contains the module configuration and code. This includes:

Magento Templates and Layout Files

app/design/{area}/{package}/{theme}/

Layout and template files are organised into folders by store area, package (theme namespace) and theme. Inside, the layout files and template files are separated into layout/ and template/ directories respectively.

Magento Skin and JavaScript files location

skin/{area}/{package}/{theme}

As with template files, most Magento assets (js, css and images) are organised by store area, package and theme. Inside, the convention is to put different types of assets into their own folders, but it is not enforced.

js/

Contains theme independent JavaScript files and other assets (e.g. css, images), organised by library.

Magento Design Areas

Class Naming Conventions and Autoloader

Magento’s include path is set to look for files (app/code) and libraries (lib/) in each of the code pools (core, community and local). Classes are resolved using the PSR-0 autoloading standard. That is, the autoloader simply replaces the underscores in the class name with directory separators and adds the .php extension:

<?php
public function autoload($class)
{
    $classFile = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $class)));
    $classFile.= '.php';
    @include $classFile;
}
?>

The class naming convention for most Magento classes is:

{Namespace}_{Module name}_{Object type}_{Object name}

Module Conflict Resolution

Conflicts can arise in three ways:

Magento Configuration

Config Load

Configuration in Magento is stored as an XML tree. Magento reads in the config.xml files for each module and merges the configuration into a single tree. This allows modules to modify existing configuration elements and add new ones.

Class Group Config and Factory Methods

In Magento models, blocks and helpers are registered in configuration using the following format:

<config>
	<global>
		<{object type}>
			<{module identifier}>
				<class>{class prefix}</class>
			</{module identifier}>
        </{object type}>
    </global>
</config>

These objects are then instantiated in the code using the factory methods (Mage::getModel() or Mage::helper()) and are referred to using their grouped class name - {module identifier}/{object identifier}. Internally, Magento uses the module identifier (the part before the slash) to find the class name prefix to prepend to the object name (the part after the slash) to find the class that needs to be instantiated. This allows modules to redefine existing objects and functionality by changing the configuration.

Class Overrides

Object classes can be overridden in configuration using the following syntax:

<config>
    <global>
        <{object type}>
            <{module identifier}>
                <rewrite>
                    <{object name}>{new class}</{object name}>
                </rewrite>
            </{module identifier}>
        </{object type}>
    </global>
</config>

This indicates to the factory methods that the specified class should be used instead of the usual class the object would resolve to.

Register an Observer

Observers are registered in Magento using the following syntax:

<config>
    <{area}>
        <events>
            <{event name}>
                <observers>
                    <{observer name}>
                        <type>{type}</type>
                        <class>{class}</class>
                        <method>{method}</method>
                    </{observer name}>
                </observers>
            </{event name}>
        </events>
    </{area}>
</config>

This requires specifying the area of the event listened to (frontend, adminhtml or global), the event being listened to, the observer identifier (unique name), the observer object type (e.g. singleton model), the class used and the method to call.

Function and use of automatically available events

Magento dispatches a number of events automatically that can be observed, e.g. *_save_before and *_load_after.

This provides us with the ability to modify models at the point before they are saved to the database or to modify a model immediately after its data has been retrieved from the database.

Cron Jobs

Crons jobs are defined in Magento using the following syntax:

<config>
    <crontab>
        <jobs>
            <{cronjob identifier}>
                <schedule>{schedule}</schedule>
                <run>
                    <model>{grouped class name}::{method name}</model>
                </run>
            </{cronjob identifier}>
        </jobs>
    </crontab>
</config>

The cron job schedule can either be a cron schedule expression (inside a <cron_expr> tag) or a configuration path (inside a config_path tag) where the crons schedule expression is stored. The <model> tag defines the function to execute in the format {grouped class name}::{method name}.

Loading active modules

Magento creates a central list of installed modules by loading all *.xml files within app/etc/modules. It records whether they are active and the location of their full configuration (<codepool>).

<?xml version="1.0" ?>
<!-- File: app/etc/modules/Meanbee_Royalmail.xml -->
<config>
    <modules>
        <Meanbee_Royalmail>
            <active>1</active>
            <codePool>community</codePool>
            <depends>
                <Mage_Shipping />
            </depends>
        </Meanbee_Royalmail>
    </modules>
</config>

Common config load methods

Per-Store Configuration in XML DOM

Per-store configuration values are located in the stores->{store name} part of the configuration and are usually retrieved with the Mage::getStoreConfig() method.

Configured Class prefixes

Prefixes are used for blocks, models and helpers. Using prefixes and not referring to classes directly by name allows rewriting the classes in the configuration and without the need to modify the code that uses them.

Internationalisation

Store views are typically used for internationalisation in Magento, with each one being configured for a particular language.

In template files $this->__('Translate Me') method is used to manage translatable text. This is then handled by Mage_Core_Helper_Data and Mage_Core_Model_Translate.

Before outputting this string it is checked against a number of locations. The priority for translations are in this order:

  1. Inline
    • The core_translate database table
  2. Theme
    • app/design/$area/$package/$theme/locale/
  3. Module
    • app/locale/

If developer mode is enabled, Magento doesn’t use translations unrelated to module.

Module scope translation:

"Namespace_Module::string","translation"

Sub-domains and Sub-directory Setup

To make use of the internationalisation, a store view with appropriate configurations should be initialised. Two ways that this can be handled is by sub-domain e.g. fr.example.com and sub-directory, e.g. example.com/fr.

There are advantages and disadvantages of each. But in general, sub-domains and sub-directories achieve the same effect.

Sub-domains are slightly easier for linking content. Another advantage of sub-domains is that they can be hosted on separate servers. This can be ideal for geo-locating boxes by country or region according to the language served per store view.

With sub-directories, we strengthen name-recognition for the primary domain. And enjoy the benefit that all store views are contributing to SEO efforts by raising total hits for the store brand. But we sacrifice the opportunity for cleaner URLs with localized domain branding. (e.g., http://amazon.com and http://amazon.de vs. http://amazon.com and http://amazon.com/germany)

See even more info in Belvg’s post on the subject.