Question

I want to know how these two methods from the "core/template" block work and in wich case we need to use them, which we practically don't use often.

This is the code from app/code/core/Mage/Core/Block/Template.php:

    /**
     * Retrieve block view from file (template)
     *
     * @param   string $fileName
     * @return  string
     */
    public function fetchView($fileName)
    {
        Varien_Profiler::start($fileName);

        // EXTR_SKIP protects from overriding
        // already defined variables
        extract ($this->_viewVars, EXTR_SKIP);
        $do = $this->getDirectOutput();

        if (!$do) {
            ob_start();
        }
        if ($this->getShowTemplateHints()) {
            echo <<<HTML
<div style="position:relative; border:1px dotted red; margin:6px 2px; padding:18px 2px 2px 2px; zoom:1;">
<div style="position:absolute; left:0; top:0; padding:2px 5px; background:red; color:white; font:normal 11px Arial;
text-align:left !important; z-index:998;" onmouseover="this.style.zIndex='999'"
onmouseout="this.style.zIndex='998'" title="{$fileName}">{$fileName}</div>
HTML;
            if (self::$_showTemplateHintsBlocks) {
                $thisClass = get_class($this);
                echo <<<HTML
<div style="position:absolute; right:0; top:0; padding:2px 5px; background:red; color:blue; font:normal 11px Arial;
text-align:left !important; z-index:998;" onmouseover="this.style.zIndex='999'" onmouseout="this.style.zIndex='998'"
title="{$thisClass}">{$thisClass}</div>
HTML;
            }
        }

        try {
            $includeFilePath = realpath($this->_viewDir . DS . $fileName);
            if (strpos($includeFilePath, realpath($this->_viewDir)) === 0 || $this->_getAllowSymlinks()) {
                include $includeFilePath;
            } else {
                Mage::log('Not valid template file:'.$fileName, Zend_Log::CRIT, null, null, true);
            }

        } catch (Exception $e) {
            ob_get_clean();
            throw $e;
        }

        if ($this->getShowTemplateHints()) {
            echo '</div>';
        }

        if (!$do) {
            $html = ob_get_clean();
        } else {
            $html = '';
        }
        Varien_Profiler::stop($fileName);
        return $html;
    }

    /**
     * Render block
     *
     * @return string
     */
    public function renderView()
    {
        $this->setScriptPath(Mage::getBaseDir('design'));
        $html = $this->fetchView($this->getTemplateFile());
        return $html;
    }
Was it helpful?

Solution

Those are methods used by Magentos layout framework and they are called by _toHtml.

The process is:

  • Mage_Core_Block_Template::_toHtml() calls renderView if the block has a template.
  • renderView() basically is the method to render the HTML, but it assumes that a template exists. It finds the full path to the template according to theme fallback rules and then calls fetchView($fileName)
  • fetchView($fileName) in turn contains the actual rendering, given a path to a template file. It adds template hints if configured, extracts assigned variables (a feature that probably nobody uses) and includes the template. Then it returns the rendered output, or directly echoes it, if the layout has been configured with setDirectOutput(true) (usually not the case).

renderView() and fetchView() are not really meant to be used directly, although Magento itself does it in a few edge cases. Take these as an example:

Core examples:

  • fetchView() can be used to render the same block but with a different template. This is used in \Mage_Adminhtml_Block_Customer_Edit_Tab_Cart::getGridParentHtml(). But I would not say that it's a particularly good example. Usually you'll want to create a new block instance to render something else.
  • renderView() is used in Mage_Usa_Block_Adminhtml_Dhl_Unitofmeasure::_getElementHtml() because the block doubles as form element renderer (implements \Varien_Data_Form_Element_Renderer_Interface) and as such can be rendered outside of the layout. Using toHtml() would have added unwanted overhead and _toHtml() would have worked, but they probably preferred using a public method.

A real extension use case

Adding blocks to the order view in the backend without rewriting core files is hard, but here's a solution I came up with:

Replace the template of an existing block:

ordercomment.xml

<adminhtml_sales_order_view>
    <!--
    We hijack the gift_options block to not modify templates or fiddle with the HTML output.
    The original template gets included
    -->
    <reference name="gift_options">
        <action method="setTemplate">
            <file>integernet_ordercomment/comment.phtml</file>
        </action>
    </reference>
</adminhtml_sales_order_view>

Then in that template, add new content and in the end, render the original template:

comment.phtml

<?php
/** @var $this Mage_Adminhtml_Block_Template */
$comment = nl2br(trim($this->escapeHtml(Mage::registry('current_order')->getComment())));
if (!empty($comment)):
?>
<div class="entry-edit">
    <div class="entry-edit-head">
        <h4 class="icon-head"><?php echo $this->helper('integernet_ordercomment')->__('Customer Comment') ?></h4>
    </div>
    <fieldset>
        <?php echo $comment ?>
    </fieldset>
</div>
<?php endif;
/*
 * Now include the original gift options
 */
$this->setTemplate('sales/order/giftoptions.phtml');
echo $this->renderView();

Again, the protected method _toHtml() would have worked as well.

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