Magento Core Cache Bug
Thanks very much to my colleagues from iWelt who found this bug and allow me to publish it here to get all the reputation ;-)
Magento can overwrite a cached block with a different one.
Magento Cache Key
Magento generates the cache key by default using the array returned by getCacheKeyInfo
:
\Mage_Core_Block_Abstract::getCacheKey
public function getCacheKey()
{
if ($this->hasData('cache_key')) {
return $this->getData('cache_key');
}
$key = $this->getCacheKeyInfo();
...
}
The default implementation of getCacheKeyInfo
only takes the name in the layout in consideration:
\Mage_Core_Block_Abstract::getCacheKeyInfo
public function getCacheKeyInfo()
{
return array(
$this->getNameInLayout()
);
}
So far so good.
What is the name of a block, which is created WITHOUT a name?
Block name if no name is given
public function createBlock($type, $name='', array $attributes = array())
{
...
$block = $this->_getBlockInstance($type, $attributes);
...
$name = 'ANONYMOUS_'.sizeof($this->_blocks);
...
$block->setNameInLayout($name);
...
$this->_blocks[$name] = $block;
...
}
}
As you can see, the name of the block is set automatically. In case you don't know sizeof
: it's an alias for count
.
So the raising number is the current block count of the whole page.
This means, the name of the block is ANONYMOUS_1
, ANONYMOUS_2
, etc.
This means, the cache key is generated from [ANONYMOUS_1]
.
The problem
Now imagine, you have two different pages, which have a block, without a name. These two blocks accidentally have the same sequential number during generation.
Same cache key means: one entry
So in the end you'll get the same cache key and this means: Magento treats it as the same block.
In our case the homepage content block was overwritten by a block of the sidebar.
Solution
My colleague came up with this solution:
We add the current action to the block name:
$name = 'ANONYMOUS_'.sizeof($this->_blocks).Mage::app()->getFrontController()->getRequest()->getPathInfo();
We gave our best to fix the problem itself (which is a wrong generated cache key), but there is no event somewhere in the context of name generation and cache key generation. And because the key is generated in abstract class Mage_Core_Block_Abstract
the only solution would be to copy the class to local/Mage
which is no solution by definition.
So the rewrite of Mage_Core_Model_Layout
is our best bet.