Solving Magento

Solutions for Magento E-Commerce Platform

by Oleg Ishenko

Magento Catalog Price Rules

Mage_CatalogRule is a core module tasked to provide automated catalog price management, which can be controlled by a set of conditions. These conditions define a subset of the catalog to which price rules apply. For each rule a date range can be set, within which the rule is used. Also rules can be set to apply for certain customer groups. Catalog rules are defined on a website level, i.e. if a website has several store views, a website catalog price rule will apply to them all.

The catalog price rule management interface is found in the shop administration back-end under Promotions => Catalog Price Rules. If you are using a test installation with sample data (which you can obtain here), you can already see several catalog rules in the grid. We will discuss one of them as an example. If you don’t have the sample data – you can create sample catalog rules as we go over them.

Continue reading

Magento Application Initialization: Loading Module Configuration

Loading module configuration is one of the most important stages of the application initialization. It takes place relatively early in the process soon after the basic configuration is loaded from the etc/config.xml and etc/local.xml files and before instantiating the front controller and the request dispatching.

Module initialization starts in the Mage_Core_Model_App::run function. in it you can find a call to the function _initModules():

protected function _initModules()
{
    if (!$this->_config->loadModulesCache()) {
        $this->_config->loadModules();
        if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) {
            Varien_Profiler::start('mage::app::init::apply_db_schema_updates');
            Mage_Core_Model_Resource_Setup::applyAllUpdates();
            Varien_Profiler::stop('mage::app::init::apply_db_schema_updates');
        }
        $this->_config->loadDb();
        $this->_config->saveCache();
    }
    return $this;
}

This function uses an object of type Mage_Core_Model_Config to load the model configuration. The system checks if the configuration can be fetched from the cache, and if not, proceeds with loading it from module declaration and configuration files.

Continue reading

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 product, or a non-catalog information page Magento parses the incoming URL to determine which modules and controllers must be engaged to process the request. When the URL rewriting is not enabled Magento URLs look like this: catalog/product/view/id/166 or catalog/category/view/id/10. These are valid URLs and they contain important information, which Magento uses to produce HTML output. Thus, catalog points to the module Mage_Catalog, product is translated into ProductControler, view – into viewAction, and the parameter id passes its value “10”. Altogether such URL generates a call to function Mage_Catalog_ProductContoller::viewAction(), which renders a details page for a product with ID 10.

Despite being logical and well fit for an MVC web application which is Magento, this URL pattern has two significant drawbacks. First, it is not human friendly. The IDs used in these URLs tell users nothing about the shop products or categories. Second, these URLs are not search engine optimized because they contain only generic terms (“catalog”, “product”, “category”) that have little effect in achieving high search engine positions. Ranking algorithms of the modern search engines (Google, above all) place high value into terms contained within URLs. For these two reasons, human and search engine compatibility, it is imperative to include product and category names into shop URLs. Descriptive URLs consisting of words meaningful for both humans and search engines improve user experience and place the links to your shop higher in the search results relevant to your business.

Magento uses a rewrite engine to match descriptive URLs to its resources. The rewrite engine is a part of Magento core system and is responsible for matching incoming descriptive URLs to controllers, actions, and entity IDs. It is also tasked with automated creation of descriptive URLs for Magento resources.

Continue reading

Events and Observers: a Magento Tutorial

This tutorial will demonstrate the principles of the observer pattern implemented in Magento. The details of this implementation have already been discussed in the previous part Event-Driven Architecture in Magento: Observer Pattern. Now we will apply this knowledge in practice and develop a module, whose functionality is built upon events and observers.

The module will perform the following tasks:

  1. An XML export file is created every time an order is placed in the shop.
  2. Every time a new customer places his first order an email is dispatched to the shop manager.

As usual, the first step to create a module is adding a module configuration file to the app/etc/modules directory. The local code pool’s package of the module is Solvingmagento and the module name is OrderExport. Place the following configuration into the app/etc/modules/Solvingmagento_OrderExport.xml:

<?xml version="1.0"?>
	<config>
	    <modules>
		<Solvingmagento_OrderExport>
		    <active>true</active>
		    <codePool>local</codePool>
		</Solvingmagento_OrderExport>
	    </modules>
	</config>

Continue reading

Event-Driven Architecture in Magento: Observer Pattern

Imagine a situation: you are developing a custom e-commerce framework and are about to put some finishing touches to your order model. The task is to program functionality, which creates an order at the end of the checkout and saves it to the database. You realize that a confirmation email has to be sent and you add the necessary code. Next morning a product manager asks you to send a copy of the e-mail to his address, and you extend your code accordingly. At a meeting in the afternoon the warehouse guy proposes to automate inventory management by sending a message to the warehouse software; and you implement it in your code. Exporting order as an XML file to feed into the shipping system – done. Notifying the purchasing department when the inventory is too low – done too.

After all this you take a look at your order model and its function placeOrder and see it has become an unmaintainable mess. All these diverse and complex tasks just do not fit into the order model. Yet they are essential for the your business and must be implemented. Situations like this are not uncommon. The growing complexity of enterprise applications often results in code that is inflexible and difficult to maintain, and prohibitively expensive to scale.

Event-driven software architecture has evolved to address such problems by decoupling services and service providers. It introduces events – notable milestones in business processes that invoke services, which observe and react to them. Events alert their subscribers about a problem, or an opportunity, or a threshold in the current process flow. An event broadcasted in the system usually consists of an event header and body. The event header contains an ID that is used to locate subscribers, while the body transports information required to process the event. In some systems event headers can also include information on the event type and creator, or a timestamp – whatever data the specifications mandates.

The service providers are independent entities and can be added or removed without affecting objects, whose events they listen to. Event creators have no knowledge of the subscribed service providers and do not depend on them. Similarly service providers are not interested in the internal mechanics of event creators. This allows for extremely flexible, loosely coupled and distributed systems. This advantages, however, come at a price – tracing events and their subscribers can be difficult.

Events and Observers in Magento

Events in Magento are triggers that tell the system to look for subscribers, which must be executed when an event is fired. To fire an event you need to specify an event code – a string, e.g. my_custom_event_code. The event code should be descriptive. If the event is distinct, its code must be unique in the system. Optionally you can pass some data along with the event. We will talk about passing data with the event in detail a bit later. An example of an event fired in Magento:

Mage::dispatchEvent('event_code', array('myObject' => $myObject));

Continue reading

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.

Continue reading

Magento Global Functions

Reinventing the wheel – what a cliche! Of course you don’t do it, at least not intentionally. And you hate being reminded of code reuse on those rare occasions when someone points to a function you wrote, which allegedly does the same as some other function somewhere in the framework. Yet it happens. Sometimes looking for blueprints for the wheel takes longer than hacking it out yourself. Sometimes you might do it just for fun. And sometimes you simply don’t know a ready solution exists buried in some obscure location in your framework. Magento is no exception – it does have some functionality left there by the core programmers, which is used extensively by the system and yet often overlooked by us, shop maintainers and extension developers.

A few such gems can be found in app/code/core/Mage/Core/functions.php. This file contains no class definition but globally available functions. This file is included early in the application initialization stage in app/Mage.php. Some of its functions may be of little use when developing extensions, since they do core system work. But some can come in handy whenever a trivial task presents itself and you have to:

1. Find out if a Directory is Writable in Magento

It is a true rarity, a Magento shop running on Windows. Still, improbable not impossible. Assuming you are in a Linux environment, this task can be easily accomplished by calling is_dir($path) and is_writable($path). Not so simple with Windows hosts. The function is_dir_writeable($dir) does some additional checks for such cases – by literally trying to write a file into the directory being checked. This function is used by Magento when checking writability of certain paths during a shop installation before creating vartmp and cache directories. Obviously, it is a well-proven approach – why not use it?

2. Output a Current Date

A neat shortcut to generate a MySQL-compatible date string, meet now($dayOnly=false). Leave the $dayOnly empty or set to false to get a Y-m-d H:i:s-formatted string, otherwise it will output a short Y-m-d representation of the current date.

function now($dayOnly=false)
{
    return date($dayOnly ? 'Y-m-d' : 'Y-m-d H:i:s');
}

3. Recursively Delete a Directory in Magento

Ever needed to delete a deeply nested directory structure? Use mageDelTree($dir). Magento uses this function to, for instance, clear user sessions when they are stored on disk.

4. Find out if a Class exists in Magento

If you need to make sure an external dependency is available in your installation, check it with mageFindClassFile($class), where the $class parameter is a class name, e.g. ExtPackage_ExtModule_Model_Classname.

5. Use an Extended Version of ucwords

This nifty little function does the same as the regular ucwords. And more! If you need to uppercase words in a string that is separated by characters other than whitespace – you can save some extra lines of code here. Say, you have a string modulename_model_classname. Converting it into a valid Magento class name will require just one call:

$className = uc_words('modulename_model_classname');
//$className === Modulename_Model_Classname

This function can also swap separators. So if there is a string modulename/model/classname it can be converted into a valid class name by calling:

$className = uc_words('modulename/model/classname', '_', '/');
//$className === Modulename_Model_Classname

Neat, eh?

6. Parse a CSV String in Magento

Now this kind of task comes fairly often. This function will save you time writing a parser – even if such is simple and takes a minute. But why bother if the function already exists? And it can handle quoted values as well. Check it out:

mageParseCsv($string, $delimiter=',', $enclosure='"', $escape='\\')

The last parameter, however, is redundant and used nowhere in the function.

Magento EAV System

The following is a collection of my experience with the EAV system in Magento. It contains all the facts I needed early on in my Magento developer career. Being a reflection of a personal experience it may be incomplete, obscure, or overladen with details. Please comment if you have a suggestion on how to improve it. If you need a clarification on some part of the text below, please ask. If there is an error – point it out. Thank you!

The EAV system is one of the most complex part of Magento shop software. It is also the most controversial and often cited as a root of performance problems in shops that have to handle large and complex product databases. When developing Magento extensions these problems can be exacerbated by failure to properly use the EAV implemented in Magento, which often happens due to a great effort that is required to understand it. For me, as probably for many other Magento developers, it has been a lot of lessons learned hard.

Before diving into details of the Magento’s EAV, it is necessary to learn a bit about the origins of EAV and its general principles. EAV has quite a long history. Some of its earliest applications were storage systems for clinical data back in 1970s. As a storage method EAV borrows from early object-oriented languages. SIMULA 67 is cited as one such influence. Functional languages such as LISP are also known to have contributed to the development of EAV. They contain storage structures that record object information in attribute-value pairs – a principle fundamental to EAV.

Continue reading

Accessing an External Database from Your Magento Module

In this post I will walk you through building a simple module to show how an external database can be accessed from Magento. Our module will include a model, whose table resides in an external database. We will create this table using Magento setup functionality and use the table to write and read data.

First you have to create the required folder structure:

app
    --code
        --Solvingmagento
            --Externaldb
                --Model
                --controllers
                --etc  
                --sql
    --etc
        --modules

Once ready, add module declaration file Solvingmagento_Externaldb.xml to app/etc/modules/. Its content is standard:

<?xml version="1.0"?>
<config>
    <modules>
        <Solvingmagento_Externaldb>
            <active>true</active>
            <codePool>local</codePool>
        </Solvingmagento_Externaldb>
    </modules>
</config>

Continue reading

Magento Routers: a Look under the Hood

Magento Routing

The centerpiece of Magento, the Front Controller, can sometimes be a challenge for a beginner Magento developer. Just a few years ago most PHP applications where collections of scripts, which were supposed to be accessed by their own URL to perform their function. The MVC and Front Controller patterns change this approach by letting one object to handle all requests. Front Controller instantiates objects, fires events and sets up the application behavior according to the received request. This is a significant paradigm shift that can be a source of much confusion. The purpose of this article is to explain how request dispatching works, how router configuration is compiled and read, and how router settings can be configured.

Routers explained

A quick look into Magento .htaccess file reveals that most requests are routed to the index.php, the one in the root folder of your application. Exceptions are requests for which a matching resource (folder or a file) can be found. To process a typical request Magento calls a Front Controller, an instance of Mage_Core_Controller_Varien_Front class. While being initialized the Front Controller reads router configuration collected from all the config.xml files and builds its router collection. By the point the request is passed to it for dispatching the Front Controller has all the information required to find a matching controller.

You can define routers for your modules in their respective config.xml files. This is also the way the core modules define their routers. Routers can be defined for front end as well as for back end functions. Looking through the config.xml files available for your default installation of Magento we can derive a general structure of a router configuration.

Continue reading

Theme: Esquire by Matthew Buchanan.