How Blocks And PHTML Work Together

来源:互联网 发布:药家鑫 知乎 编辑:程序博客网 时间:2024/05/22 17:25

Early on in my Magento-coding days, I struggled with the relationship between the block classes and the phtml files. Which came first? Who owned who? Do you need blocks? Do you need phtml? First and foremost, we need to understand that the complexity of the layout/block/phtml relationship is necessary, powerful, and flexible. Those three pieces allow for the ability to "theme" Magento and to easily override pieces of the store's look and feel without messing with the default layout/theme.

So where do we start? How about with this statement: Phtml files are owned and used by blocks. In the code, however, they are called "templates", not "phtml". Each block instance has 0-1 templates assigned to it (either through the layout XML files or hard coded in the block code itself).

Assigned in the layout file:

?
1
<blocktype="catalog/product_view"name="product.info"template="catalog/product/view.phtml">

Assigned in the code:

?
1
2
3
4
5
public function __construct()
{
        parent::__construct();
        $this->setTemplate('catalog/product.phtml');
}

So how does the flow work? It all starts with the layout files. Calling them layout files make sense in some cases, but the layout files don't always define the "layout" of the page. Actually, more often than not, the phtml does that. With that said however, the layout files define WHAT can be blocks/phtml are AVAILABLE. For example, lets say you have a snippet of your layout file that looks like this:

?
1
2
3
4
5
<referencename="content">
    <blocktype="awesome/outer_view"name="outer.view"template="awesome/outer/view.phtml">
        <blocktype="awesome/inner_view"name="inner.view"template="awesome/inner/view.phtml"/>
    </block>
</reference>

What this IS saying is:

  1. We are going to add the "outer.view" block to the already existing "content" block (aka: outer.view is now a child of content).
  2. outer.view's phtml WILL be rendered automatically (because content's block renders ALL of it's child blocks)
  3. Because "inner.view" is within the ""outer.view" block, the "inner.view" is now a child of "outer.view"

What this IS NOT saying:

  1. inner.view's phtml will automatically be rendered (This depends on it's parent - outer.view).

So how do we know what phtml will be rendered, and what won't? The answer is -it ALWAYS depends on the parent block. The initial loading and rendering of the block(s) is done in the controller action. The action will generally contain something like:

?
1
2
$this->loadLayout();
$this->renderLayout();

The loadLayout() looks through all of the appropriate layout files and creates one big layout of the page. Open up page.xml right now to aid in the understanding of the rest of this article. The block "root" is the Great Great Great Great Great Grandparent block. It all starts with him.

The renderLayout() begins by

  1. Calling the toHtml() function on the "root" block (Mage_Page_Block_Html)
  2. The toHtml() ends up rendering the phtml that was assigned to the "root" block (page/3columns.phtml)
    • While rendering the page/3columns.phtml, the rendering agent comes across the line: echo $this->getChildHtml('head'). Whenever we see $this inside phtml, it is always referring to the block that the phtml has been assigned to.
  3. So now we need to see if "head" is a child block of $this (which is "root"). If we look at the page.xml we see that "head" IS a child, so we will now call the toHtml() function on the "head" block (Mage_Page_Block_Html_Head)
  4. The toHtml() ends up rendering the phtml file that is hard-coded in the block's constructor which is (page/html/head.phtml).
  5. This type of flow goes ON and ON until we pick it up again at the "content" block which happens to be a Mage_Core_Block_Text_List block.
  6. The toHtml() function will be called on this block, but there is no phtml assigned to it anywhere. Instead, the toHtml() function just says "loop through all of my children and render them one right after another".
  7. If we are sticking with our example up above, we have added 1 child block to "content": "outer.view". We will assume that "awesome/outer_view" maps to Super_Awesome_Block_Outer_View and that Super_Awesome_Block_Outer_View extends Mage_Core_Block_Template.
  8. So now the toHtml() gets called on Super_Awesome_Block_Outer_View so as long as we haven't overridden the _toHtml() function it will render the phtml that is assigned to it (awesome/outer/view.phtml).

Assuming awesome/inner/view.phtml looks like this:

?
1
<div>Inner View</div>

If the awesome/outer/view.phtml looks like this:

?
1
2
<div>Start Outer</div>
<div>End Outer</div>

It will NEVER render the inner.view and will look like this:

Start Outer
End Outer

If the awesome/outer/view.phtml looks like this:

?
1
2
3
<div>Start Outer</div>
<?php echo $this->getChildHtml('inner.view') ?>
<div>End Outer</div>

It WILL render the inner view in between the two Start and End divs like this:

Start Outer
Inner View
End Outer

If the awesome/outer/view.phtml looks like this:

?
1
2
3
<div>Start Outer</div>
<?php echo $this->getChildHtml() ?>
<div>End Outer</div>

It WILL render the inner view (and any other child blocks) in between the two Start and End divs like this:

Start Outer
Inner View
End Outer

We can't assume that just because the block is defined in the layout that it will be rendered. Either the toHtml() needs to explicitly render the child blocks, or the phtml assigned to the block must render the child blocks via the getChildHtml() function.

So, recapping what we learned:

  • Block are what drive the output to the browser.
  • Templates/Phtml are assigned to blocks
  • The parent/child relationships of blocks are defined in the layout files (but can be in the code to if a block calls the setChild() function in itself).
  • The parent block determines how/when/if the child block is rendered (generally through the "echo $this->getChildHtml()" functionality.
  • Any time you see $this in a phtml file, the $this object is the instance of the block you are currently rendering.

原创粉丝点击