Question

Does someone know why Magento likes to load products when being asked to just load the layout ?

I just are walking through some Magento code from 1.9.2. And i have writen a controller with just: loadLayout en renderLayout. So i tought that i could change blocks between the two functions, but it turns out that is not the case for most of the 'core' blocks. For example in this block filling in the HTML Header is done if you say: "loadLayout".

Does anyone have experience with removing blocks that already 'changed' the global Magento world ?

For example: Mage_Catalog_Block_Product_View

/**
 * Retrieve current product model
 *
 * @return Mage_Catalog_Model_Product
 */
public function getProduct()
{
    if (!Mage::registry('product') && $this->getProductId()) {
        $product = Mage::getModel('catalog/product')->load($this->getProductId());
        Mage::register('product', $product);
    }
    return Mage::registry('product');
}
/**
     * Add meta information from product to head block
     *
     * @return Mage_Catalog_Block_Product_View
     */
    protected function _prepareLayout()
    {
        $this->getLayout()->createBlock('catalog/breadcrumbs');
        $headBlock = $this->getLayout()->getBlock('head');
        if ($headBlock) {
            $product = $this->getProduct();
            $title = $product->getMetaTitle();
            if ($title) {
                $headBlock->setTitle($title);
            }
            $keyword = $product->getMetaKeyword();
            $currentCategory = Mage::registry('current_category');
            if ($keyword) {
                $headBlock->setKeywords($keyword);
            } elseif ($currentCategory) {
                $headBlock->setKeywords($product->getName());
            }
            $description = $product->getMetaDescription();
            if ($description) {
                $headBlock->setDescription( ($description) );
            } else {
                $headBlock->setDescription(Mage::helper('core/string')->substr($product->getDescription(), 0, 255));
            }
            if ($this->helper('catalog/product')->canUseCanonicalTag()) {
                $params = array('_ignore_category' => true);
                $headBlock->addLinkRel('canonical', $product->getUrlModel()->getUrl($product, $params));
            }
        }

        return parent::_prepareLayout();
    }

This is my test:

<?php
include_once('../initMage.php');
initMage();

$controller = initController('Gn_Test_IndexController');
$product = Mage::getModel('catalog/product')->load(1);
Mage::register('product', $product);
$controller->loadLayout();
Was it helpful?

Solution

Explaining in this in full goes beyond a single Stack Exchange answer, the layout system could fill a small book (and I've written that book).

In short -- when you call loadLayout you're telling Magento

  1. Merge all the Layout XML Update files (app/design/area/theme/layout) into one tree
  2. Find the specific parts of that tree to use for this request
  3. Use those specific parts of the tree to determine which block objects to instantiate, and then instantiate the block objects

It's the last part of #3 that's throwing you -- when Magento instantiates a block via the layout it calls _construct and and _prepareLayout in the block. These methods, in turn, will often do things like load a product collection.

To finish the above, when you call renderLayout you're telling Magento "call the root block's toHtml method, which renders the root block's phtml template, which cascades to the other block's phtml templates via getChildHtml (this also sometimes triggers direct instantiation and rendering of other block objects)

Does anyone have experience with removing blocks that already 'changed' the global Magento world ?

In general, you probably don't want to do this. Other blocks and code may rely on that state you're looking to alter, and removing it may cause fatal errors.

If you really want to do this, I'd look into the following events

controller_action_layout_load_before
controller_action_layout_generate_xml_before
controller_action_layout_generate_blocks_before

and then directly modifying the layout and/or layout update object (from the passed in observer) to remove the XML responsible for creating the block you want to remove.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top