Quickshiftin - Clever Crazy Code

Using traits in Magento

March 14th, 2015

So I’ve finally started using Magento and on the whole I’m enjoying it. Magento is very flexible and the code is fairly clean. Some of the nomenclature is misleading and comments can be scant, but it’s still way cleaner than most of the older PHP e-commerce systems I’ve used like Virtuemart, OpenCart, ZenCart etc. As I’ve begun building modules to customize Magento, I discovered Alan Storm’s great website and purchased his e-book No Frills Magento Layout. I’ve also been enjoying PHP’s trait feature, you may remember I recently posted on traits too. Trait’s are useful in Magento, I’ll show you how I’m using them already.

Extending core classes

Often times you need customize an existing a.k.a. core class in Magento. In order to do this you build a module, then extend the class you wish to modify and override the method you wish to customize; this short article shows you how. It’s great that Magento is clean in this way. Your custom code lies outside the Magento core files and you’re able to upgrade the core system independently of your custom module code. With the aforementioned older e-commerce systems, I usually had to hack into core files, then resort to version control to forward port the changes in order to upgrade the application. I gave an illustration a long time ago on the blog using WordPress as an example.

AJAXifying core controllers

One of the tasks on a current Magento project is to move login and registration into a modal that can be displayed in multiple locations across the site. The core classes send plain HTML in response to login or registration form submissions, like a duplicate email during registration or a missing username during login for example, so in order to support the modal I needed to customize the core  Mage_Core_Controller_Front_Action and Mage_Customer_AccountController classes so that they return JSON instead.

I worked on a customized login first, which brought me to the Mage_Core_Controller_Front_Action class’ loginAction method. What I did was to subclass as explained on Short&Grove then among other little tweaks, respond with JSON content instead of HTML.

class Quickshiftin_Quickshiftin_LoginController extends Mage_Core_Controller_Front_Action
{
    /**
     * Try to login an existing user from our custom modal in the checkout area.
     */
    public function loginAction()
    {
        // Restrict to POST request
        if(!$this->getRequest()->isPost()) {
            $this->getResponse()
                 ->setHeader('HTTP/1.1', '403 Forbidden')
                 ->sendResponse();
            return;
        }

        // Prep the response and gather request parameters
        $aRsp  = ['result' => false];
        $oRq   = $this->getRequest();
        $sUser = $oRq->getParam('username');
        $sPass = $oRq->getParam('password');

        // Try to log the user in
        $oSession = Mage::getSingleton('customer/session');

        // If the user is already logged in, just return true and bail
        if($oSession->isLoggedIn() || $this->_login($oSession, $sUser, $sPass))
            $aRsp = ['result' => true];
        else
            $aRsp['message'] = 'Invalid username or password';

        $this->_ajaxResponse($aRsp);
    }

    /**
     * Mage_Customer_Model_Customer throws an Exception upon failure to login.
     */
    private function _login($oSession, $username, $password)
    {
        try {
            $oSession->login($username, $password);
        } catch(Exception $e) {
            return false;
        }

        return true;
    }

    /**
     * json_encode $aData and set it as the response body.
     */
    protected function _ajaxResponse(array $aData)
    {
        $this->getResponse()
             ->clearHeaders()
             ->setHeader('Content-type', 'application/json', true);

        $this->getResponse()->setBody(json_encode($aData));
    }
}

Notice the last method _ajaxResponse in particular. This is the meat and potatoes of converting an array of data to JSON and setting it on the response body for any controller. As soon as I’d finished with the  Quickshiftin_Quickshiftin_LoginController I needed the same function in another controller subclass, my subclass of  Mage_Customer_AccountController to ‘AJAXify’ the registration method createPostAction.