Categories


Archives


Recent Posts


Categories


Magento’s Block Transport Object

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Here’s a fun little heisenbug I had to deal with. I was working in a Magento block observer — specifically the core_block_abstract_to_html_after event. If the block was a specific block, I wanted to change its output slightly.

$transport = $observer->getTransport();
$block = $observer->getBlock();
if($block->getNameInLayout() != 'foo')
{
    return;
}

$new_output = Mage::getSingleton('core/layout')->createBlock('group/class')
->setTemplate('foo/baz/bar.html')

$new_html = str_replace('to find', $new_output , $transport->getHtml());

$transport->setHtml($new_html);

Pretty standard stuff, if a little simplified for the sake of pseudo code. This sort of transformation is often necessary when a particular Magento block/template doesn’t have a method to rewrite, and the block template is complex enough that you don’t feel comfortable creating your own version of the template.

When Magento fires core_block_abstract_to_html_after, it sends along the transport object specifically so you can do stuff like this. Here’s the spot in the code where that happens.

#File: app/code/core/Mage/Core/Block/Abstract.php    
self::$_transportObject->setHtml($html);
Mage::dispatchEvent('core_block_abstract_to_html_after',
        array('block' => $this, 'transport' => self::$_transportObject));

However, for reasons that weren’t obvious to me, instead of replacing the to find string, this observer changed the entire output of the block to the output of the group/class block, but with none of the original block’s content.

Can you spot my bad assumption? Take a look at the transport object

#File: app/code/core/Mage/Core/Block/Abstract.php    
'transport' => self::$_transportObject

It’s a static property of the abstract block class —

#File: app/code/core/Mage/Core/Block/Abstract.php    
private static $_transportObject;

This means every block uses the same transport object. Which means if you render a block inside core_block_abstract_to_html_after, the transport in your observer no longer contains the html for block you’re observing, it contains the html for the block you just rendered.

Once I realized this, the problem was easy enough to solve — just extract the HTML before rendering the new block

//get the HTML
$old_html = $transport->getHtml();

//render the block
$new_output = Mage::getSingleton('core/layout')->createBlock('group/class')
->setTemplate('foo/baz/bar.html')
//teh transport now contains html for the group/class block

//which doesn't matter, because we already extracted the HTML into a 
//string primitive variable
$new_html = str_replace('to find', $new_output , $old_html);    
$transport->setHtml($new_html);

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 5th May 2014