Visualizing Magento Indexer Progress

Magento Reindex Progress

At the Magento Hackathon Zürich 2014, Dima Janzen from Mash2 and I picked up on a previous item on the project ideas list „Visualize reindexing“ (Credits to Tim Bezhashvyly for proposing that). The team that started implementing it last time told us that there was no sane way to determine the progress of processed events, which also would have been our first approach. So we tried to think out of the box and came up with another approach: Estimating the total running time per indexer based on previous times, something that is also used in other software, like build servers.

Luckily, this data is easy to retrieve, Magento already saves start and end time of the current/latest run in the index_process table, we just needed to persist it in a second table to get a history.

Then the large part of the work, was to build a nice user interface around it. The main goals were

  • Unobtrusive integration in the indexer grid
  • Real time information

Read more at integer-net.de

A JSON-RPC Adapter For The Magento API

Going through my old answers on Magento StackExchange, I found this question about using the Magento API via JavaScript and noticed that the link to GitHub that contained an important part of the solution, namely implementing a JSON-RPC adapter for the Magento-API is dead now.

So I decided to publish my complete module myself (the original link was a core hack, I rewrote it as a clean module):

GitHub: SGH_JsonRpc

The whole module is less than 100 lines of code. In config.xml our controller is added to the api route:

    <frontend>
        <routers>
            <api>
                <args>
                    <modules>
                        <sgh_jsonrpc before="Mage_Api">SGH_JsonRpc_Api</sgh_jsonrpc>
                    </modules>
                </args>
            </api>
        </routers>
    </frontend>

The new API adapter is defined in api.xml:

Continue reading “A JSON-RPC Adapter For The Magento API”

Efficiently Increase/Decrease Magento Attributes

Magento.SE Screenshot

This question arose on Magento StackExchange:

I need to decrement a value with an atomic database operation, is it possible using Magento models?

It is in fact possible, with a lesser known technique using Zend_Db_Expr. I’ll share it here as well:

$object->setNumber(new Zend_Db_Expr('number-1'));

For reference:

The method Mage_Core_Model_Resource_Abstract::_prepareDataForSave() contains the following code:

if ($object->hasData($field)) {
    $fieldValue = $object->getData($field);
    if ($fieldValue instanceof Zend_Db_Expr) {
        $data[$field] = $fieldValue;
    } else {
        ... [normal value processing follows]

EAV Models:

Note that you only can reference the attribute by its name (“number” in the example) if it’s a real column of the main table, not an EAV attribute.

Although the abovementioned method is only used by models with flat tables, Zend_Db_Expr can be used for EAV attributes as well, the method that handles it is Varien_Db_Adapter_Pdo_Mysql::prepareColumnValue().

BUT you always have use the column name “value“:

$product->setNumber(new Zend_Db_Expr('value-1'));

You don’t need to specify a table alias because during save each attribute gets processed with its own query, so “value” is not ambiguous.

Spryker vs. Magento

Recently I had the opportunity to take a peek into the source code of Spryker, the e-commerce framework that’s composing itself to be the new player in the enterprise area. Spryker was originally developed by the Berlin based incubator Project A to be used in the companies that they build up and is supposed to be released to the public this year. While “public” is not enirely true, I can say so much in advance: An open source version is not planned, licenses will cost about 100.000 € / year. Agencies can register as partner, to get access to source code and documentation without a license. With the first sold license they get access to additional training material. Freelancers are not addressed. Already listed as partner are the agencies CommercePlus and Symmetrics that are well-known in the German Magento scene.

What is special about Spryker?

Spryker doesn’t consider itself as ready-to-use product but as framework that provides the building blocks for an individual e-commerce solution from which you can choose and extend for your project. This takes the reality into account that no project is equal to the next and each shop has its own processes and infrastructure, which you have to address individually.

The core of Spryker are two separate applications, Yves and Zed. In short, Yves is a lightweight application for the frontend, Zed the big gun for the backend.

Discover Spryker
Image: http://spryker.com/product/

Yves (in the first version developed with Yii, now with Silex) reads any needed data from an in-memory NoSQL backend such as Redis.
Zed (Zend Framework 2) handles communication with MySQL, message queue and external systems, and contains the business logic for order processes and so on.

Read more at magenticians.com Continue reading “Spryker vs. Magento”

Magento: Direct Link To Tab in Adminhtml Tab Widgets

For an extension I was recently working on, I wondered if there was a built-in way to link directly to a tab on a backend page. My research didn’t result in anything useful (read: my Google foo had failed me), so I dug into the core code to see where to start. I’ll share what I found out.

The Problem

In particular, I wanted to link to the “Manage Label / Options” tab on the “Edit Product Attribute Page”:

Screenshot

The Solution

Actually it’s possible with a URL parameter ?active_tab=$id.

How To Find The Right Tab ID

Find the responsible tab container class. This is a child class of Mage_Adminhtml_Block_Widget_Tabs, in my case, Mage_Adminhtml_Block_Catalog_Product_Attribute_Edit_Tabs.

You’ll find calls to $this->addTab(), usually in the methods _beforeToHtml(), or _construct(). The first parameter of addTab() is the tab id:

    $this->addTab('labels', array(
        'label'     => Mage::helper('catalog')->__('Manage Label / Options'),
        'title'     => Mage::helper('catalog')->__('Manage Label / Options'),
        'content'   => $this->getLayout()->createBlock('adminhtml/catalog_product_attribute_edit_tab_options')->toHtml(),
    ));

So, the URL is /admin/catalog_product_attribute/edit/attribute_id/123/?active_tab=labels, generated with this code (within an adminhtml block):

    $this->getUrl('adminhtml/catalog_product_attribute/edit',
        array('attribute_id' => 123, '_query' => array('active_tab' => 'labels'));

How it works

Let’s have a look at the responsible code:
Continue reading “Magento: Direct Link To Tab in Adminhtml Tab Widgets”

Magento ACL: No More “Log Out And Back In” After Installing Extensions

In almost every Magento extension installation guide you find the step “Log out and log in again” which is necessary to gain access to new sections in the backend menu or system configuration. But why exactly do we put up with it? The problem is that the access control list (ACL) is loaded only on login and then cached in the session. Loading it on every request is no viable alternative because it would slow down the backend too much.

But with just a few lines of code we can make reloading the ACL a little more comfortable.

The Code

This controller action reloads the ACL by request:

class SSE_AclReload_Adminhtml_Permissions_AclReloadController
    extends Mage_Adminhtml_Controller_Action
{
    public function indexAction()
    {
        $session = Mage::getSingleton('admin/session');
        $session->setAcl(Mage::getResourceModel('admin/acl')->loadAcl());

        Mage::getSingleton('adminhtml/session')->addSuccess(
            $this->__('ACL reloaded'));
        $this->_redirectReferer();
    }
}

This template provides a button that links to the new controller:

<?php
$request = Mage::app()->getRequest();
?>
<a href="<?php echo $this->getUrl('adminhtml/permissions_aclReload/index'); ?>">
<?php echo $this->__('Reload ACL'); ?>
</a>

And this layout update adds the button to error 404 pages in the backend (those that you get when you don’t have access to a page):

    <adminhtml_noroute>
        <reference name="content">
            <block type="adminhtml/template" name="content.aclReload"
                after="content.noRoute" template="sse_aclreload/button.phtml" />
        </reference>
    </adminhtml_noroute>

The Result

Screenshot Magento Admin 404

Continue reading “Magento ACL: No More “Log Out And Back In” After Installing Extensions”

TranslationHints 0.2 For Magento Published

Screenshot: Translation Hint

I released version 0.2 of my Magento extension SSE_TranslationHints, a developer tool that shows the source of translations together with alternative overridden translations for the same string directly in the frontend.

The configuration is still done in the same way as template hints:

Screenshots: Translation Hints Configuration

News

Together with the source of the translation you see alternative translations that have been overridden by the actual source, and some additional data.

In the following example you see the scope of the translation (Mage_Customer), the translation for this scope, as well as the translation that would be used for global scope, i.e. if there was no scope specific translation. The CACHED tag tells us that the translations have been loaded from translation cache:

Screenshot: Translation Hint

Continue reading “TranslationHints 0.2 For Magento Published”

Mock Admin Session With EcomDev_PHPUnit In Magento Enterprise

In integration tests with EcomDev_PHPUnit_Test_Case_Controller there is a useful helper method adminSession(), to test requests in the Magento backend. With Magento Enterprise you might get this error message if you use it:

Exception: Warning: in_array() expects parameter 2 to be array, null given in /home/vagrant/mwdental/www/app/code/core/Enterprise/AdminGws/Model/Role.php on line 83

As seen on Magento EE 1.14.1.

Without disclosing details about the Enterprise modules, here a solution where the responsible observer gets mocked:

$adminObserverMock = $this->getModelMock(
    'enterprise_admingws/observer',
    array('adminControllerPredispatch'));
$adminObserverMock->expects($this->any())
    ->method('adminControllerPredispatch')
    ->will($this->returnSelf());
$this->replaceByMock('singleton', 'enterprise_admingws/observer',
    $adminObserverMock);
$this->adminSession();

Magento: Lost Block Content After core_block_to_html_after Event

Be careful if you use Mage_Core_Block_Abstract::toHtml() inside an observer for core_block_to_html_after. I did that to inject HTML from another block into an existing block with the result that everything except this new block was removed from output.

Digging through the core, I found the cause in how the event is dispatched:

        /**
         * Use single transport object instance for all blocks
         */
        if (self::$_transportObject === null) {
            self::$_transportObject = new Varien_Object;
        }
        self::$_transportObject->setHtml($html);
        Mage::dispatchEvent('core_block_abstract_to_html_after',
            array('block' => $this, 'transport' => self::$_transportObject));
        $html = self::$_transportObject->getHtml();

As you see, the transport object that is used to allow modification of the HTML in observers, is a class variable of Mage_Core_Block_Abstract, so basically acts like a singleton. I cannot think of a good reason for this, but it smells ridiculously like premature optimization.

Now what’s happening is, that during the event is processed, the new block sets its own output to the same transport object in its toHtml() method and the original output is lost, if you didn’t save it before.

The solution to my particular problem was to generate and pre-render the new block elsewhere but if you don’t, you need to copy the output at the very beginning:

$html = $observer->getTransport()->getHtml(); // should be the first statement

// now you can do what you want, create other blocks, modifiy $html ...

$observer->getTransport()->setHtml($html); // should be the last statement

Retrospective: The Blog 2014

A personally and businesswise successful year has gone by and the new one is still starting slowly. Time to look back how the blog has been doing since I relaunched my site last February and set some new goals for 2015.

Hot topics

Some topics that sticked out in one way or the other:

Unit Testing

My all-time top article from 2011 [PHP] Mocking Built-in Functions Like time() In Unit Tests was still the second most visited in 2014 and I am happy to say that the concept that it introduced got some new attention:

PHP 5.3 Death March

The most controversional, most discussed and most clicked article of 2014 was my announcement to drop PHP 5.3 support wherever possible to force adaption of current PHP versions (5.3 reached its end of life in August 2014 and does not get any security fixes anymore since then).

I feel in good company because soon after, Anthony Ferrara (@ircmaxell) kicked of the same discussion on larger scale on Twitter and elsewhere with his articles about PHP versions:

  1. On PHP Version Requirements
  2. Being A Responsible Developer
  3. PHP Install Statistics

Vagrant

puphpet-vagrant-puppet-magentoI wrote a series on articles on Vagrant, specifically to introduce it for Magento developers, published on integer-net.de. Until now it is only available in German but I published an English summary in the Webguys advent calendar that covers everything to get you started: Türchen 19: Kickstart your Magento Dev System with Vagrant. Two of the four teasers on this blog made it into the top ten of 2014 (see numbers below).
Continue reading “Retrospective: The Blog 2014”