Magento custom category page template

One of Magento’s weaknesses is that there often different ways to customize your installation. When several developers work on a site this often leads to inconsistencies and some ways of customizing are better than others. I was doing some research on adding a custom category template for an individual category and all solutions I found were centered around Magentos “Custom Layout Update” option which allows to overwrite the layout structure via a XML snippet in the Magento admin (Catalog > Manage Categories).

Mageno_custom_category_template

This option has several disadvantages:

  • It’s a pain to write XML in a textarea
  • There is no way of keeping track of the change in source control
  • You have to deploy this change by writing custom SQL queries or manually in your dev and staging instances

A much cleaner option is to simply do your overwrites in your themes catalog layout file catalog.xml (app/design/frontend/[package]/[theme]/layout/catalog.xml).

<!-- Category id goes here -->
<CATEGORY_[category id]>
    <reference name="root">
        <!-- Switch to 1 column layout -->
        <action method="setTemplate"><template>page/1column.phtml</template></action>
    </reference>
    <reference name="content">
        <!-- Overwrite the view template -->
        <block type="catalog/category_view" name="category.products" template="catalog/category/[template name].phtml" />
    </reference>
</CATEGORY_[category id]>

This approach offers the same flexibility and is much easier to deploy and maintain.

Magento custom category page template

ZF2 Service Manager Aware Objects

In one of my previous posts I explained how to set up Dependency Injection in Zend Framework 2. Even though this approach is highly flexible it doesn’t always fit your project needs. Sometimes it is more suitable to fetch object instances from the service manager directly within the object. This post will explain how to implement this.

ZF2 automatically calls the setServiceManager method for objects implementing the ServiceManagerAwareInterface interface when instanciating these objects via the service manager. To set this up 2 steps are necessary:

  1. The class which needs to have access to the service manager needs to implement ServiceManagerAwareInterface
  2. The service manager needs to have the factory methods for the object that consumes the service manager and for the objects which are to be instanciated by the service manager

To implement the ServiceManagerAwareInterface the class needs to simply have a setServiceManager method which takes a ServiceManager object as an argument. This class needs to populate a property which gives other functions access to the service manager.

module/User/src/User/Model/User.php

<?php
namespace User\Model;

use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;

abstract class User implements ServiceManagerAwareInterface {
    protected $serviceManager;

    /*
     * Populate service manager property
     */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;
    }

    /*
     * Do some foo
     */
    protected function foo()
    {
        $foo = $this->serviceManager->get('Foo');
        $foo->bar();
    }
}

Now when creating instances of objects which implement the ServiceManagerAwareInterface using service manager factory methods, the service manager will be automatically made available.

module/User/Module.php

<?php
namespace User;

class Module
{
    ...

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'User' => function($sm)
                {
                    $user = new Model\User();
                    return $user;
                },
                'Foo' => function($sm)
                {
                    $foo = new \Foo();
                    return $foo;                    
                },
            )
        );
    }

    ...
}
ZF2 Service Manager Aware Objects

Zend JSON Server

I implemented Zend JSON RPC Server today. The documentation on the Zend website left a lot of room for guesswork and none of the online resources I could find provided the complete picture. Here a step by step guide on how to set it up.

Most users probably use this API to perform JS calls from their front-end to their own back-end. For this use case you need 3 components.

  • An API controller
  • A class to handle the API calls
  • and some JS code to perform the call

The API controller (application/controllers/ApiController.php):

<?php
/*
 * Controller for JSON API calls
 *
 * API methods are defined in library/Test/Api.php
 */
class ApiController extends Zend_Controller_Action
{
    private $server;
    
    /*
     * Initilaize
     */
    public function init()
    {
        // Initialize Zend_Json_Server
        $this->server = new Zend_Json_Server();
        $this->server->setClass('Test_Api');

        // Disable layout
        $this->_helper->layout->disableLayout();
    }

    /*
     * Handle the API request
     */
    public function indexAction()
    {
        $request = $this->getRequest();

        // Return the service mapping description for GET requests
        if ($request->isGet()) {
            $controller = $request->getControllerName();
            $module = $request->getModuleName();

            // Set the API url and envelope
            $this->server
                ->setTarget('/' . $module . '/' . $controller)
                ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
         
            // Return the SMD to the client
            header('Content-Type: application/json');
            echo $this->server->getServiceMap();
        } 
    
        // Call the API
        else {
            // Handle the request
            $this->server->handle();
        }
    }
}

This basically returns the RPC service mapping description for GET requests and dispatches POST requests to the class which handles the API calls.

The class which handles the API calls (library/Test/Api.php):

<?php
/*
 * JSON API for requests to /api/
 */
class Test_Api {
    /*
     * @param int $bar
     */
    public function foo($bar) {
        return $bar;
    }

    // Add more functions here
}

Make sure the have the Test namespace registered in your application.ini and your library path points to the correct place.

includePaths.library = APPLICATION_PATH "/../library"
autoloaderNamespaces[] = "Test_"

For the frontend JS you need to download Douglas Crockford’s JSON-js library. Copy this to public/js/libs/json2.js.

In whatever view script you want to use the API add:

$this->inlineScript()->appendFile('/js/libs/json2.js'); 

You can also add this to the layout if you want to be able to access the API on every page.

Once you got this in place you can call the API from your JS:

/*
 * JS API Test 
 */
function JsApi() {
    /*
     * Test call
     */
    this.testApi = function() {
        // Request parameters
        var request = {};
        request.method = 'foo';
        request.params = { 'bar': 'baz' };
        request.jsonrpc = '2.0';
        
        // Perform API call
        $.post(
            '/api/',
            JSON.stringify(request), 
            function(response) {
                
                if (!response.result.length) {
                    // API returned nothing; do something
                    return; 
                }

                // Process the response
                $.each(response.result, function () {
                    // Do something
                });
            }
        );
    }

}

$(document).ready(function() {
    // Perform a test call
    var jsApi = new JsApi();
    jsApi.testApi();
});

This relies on the jQuery library. If you are using other JS libraries you need to adjust this accordingly.

Zend JSON Server

Timer class to profile code sections

To profile the code base of a large-scale website I wrote a simple helper class to determine processing times of certain code sections. In general I find XDebug and KCachegrind very helpful for code profiling but this has proven very helpful for realtime profiling.

<?php
// Define TIMER_RUNTIME_START for total script timing
// This will also automatically be defined on inclusion of
// class_timer.php
define('TIMER_RUNTIME_START', microtime(true));

require_once('class_timer.php');
$timer = Timer::singleton('/tmp/logfile', array('precision' => 2));

// Timers can be nested too
$timer->start('wrapper_timer');

$timer->start('first_timer');
// Do something slow
sleep(1);
$timer->stop('first_timer');

$timer->start('second_timer');
// Do something slow
usleep(200000);
$timer->stop('second_timer');

$timer->stop('wrapper_timer');
?>

The output can be logged to a dedicated file or the standard error log. Here the output of the example above:

=== 2012-11-29 10:05:46 ===
wrapper_timer => total 1.20, count 1, max. 1.20, avg. 1.20
first_timer => total 1.00, count 1, max. 1.00, avg. 1.00
second_timer => total 0.20, count 1, max. 0.20, avg. 0.20
=== 2012-11-29 10:05:46 ===

It is also possible to log the percentage of the total script execution time for each section.

To do so set the percent flag

$timer = Timer::singleton('/tmp/logfile', array('percent' => true));

The output will look something like this:

=== 2012-11-29 10:32:14 ===
wrapper_timer => total 99.24%, count 1, max. 99.24%, avg. 99.24%
first_timer => total 82.62%, count 1, max. 82.62%, avg. 82.62%
second_timer => total 16.57%, count 1, max. 16.57%, avg. 16.57%
=== 2012-11-29 10:32:14 ===

To get the most precise output define the TIMER_RUNTIME_START constant as early as possible in the script:

define('TIMER_RUNTIME_START', microtime(true));

If you don’t define this constant it will be automatically defined on inclusion of class_timer.php.

Download the code here.

Timer class to profile code sections

PHP Syntax error testing in VIM

Please see my article about the Syntastic Vim Plugin for a better way of syntax checking in VIM.

I find it really helpful to be able to test for syntax errors from within VIM. VIM offers this option via filetype plugins and the :make command. To enable this functionality 2 small config changes are necessary.

~/.vimrc

# Map the make command to CTRL+t 
map <C-T> :w<CR>:make <CR>

~/.vim/ftplugin/php.vim

# Set the make command to execute the PHP syntax checker
set makeprg=php\ -l\ %
# Update error formatting
set errorformat=%m\ in\ %f\ on\ line\ %l

This will only change the make command for .php  files and keep other files unaffected.

Once you changed those 2 files you can hit CTRL+t and you will see if you have any syntax errors in your code:

PHP Parse error:  syntax error, unexpected ';' in test.php on line 3
Errors parsing test.php

Note: Executing the syntax test will save the file before testing.

PHP Syntax error testing in VIM