Türchen 13: Magento Template Facade Technique

I’m working with Magento for about 3 years. What I really like about it is that you always learn something new about it. Recently I was surprised to find another hidden gem in the place that I pass along almost daily. Amazing that I was not noticing it is for all that time. I made a small presentation out of it and performed it in November in front of quite experienced Magento developers at 5th Magento Stammtisch in Zurich. You can imagine how surprised was I to find out that none of them were sure about the subject. So give a warm welcome to Magento Facades.

I guess every Magento developer worked with template/catalog/product/view.phtml
template. I guess most of them stumbled upon those two blocks:

<?php echo $this->getChildChildHtml('container1', '', true, true) ?>

and

<?php echo $this->getChildChildHtml('container2', '', true, true) ?>

The following article will reveal where do they come from and how they work.
Our research have to start from Magento blocks hierarchy. After the quick look into
catalog.xml one can spot those two block declarations:

<block type="core/template_facade" name="product.info.container1" as="container1">
	<action method="setDataByKey">
		<key>alias_in_layout</key>
		<value>container1</value>
	</action>
	<action method="setDataByKeyFromRegistry">
		<key>options_container</key>
		<key_in_registry>product</key_in_registry>
	</action>
	<action method="append">
		<block>product.info.options.wrapper</block>
	</action>
	<action method="append">
		<block>product.info.options.wrapper.bottom</block>
	</action>
</block>

and

<block type="core/template_facade" name="product.info.container2" as="container2">
	<action method="setDataByKey">
		<key>alias_in_layout</key>
		<value>container2</value>
	</action>
	<action method="setDataByKeyFromRegistry">
		<key>options_container</key>
		<key_in_registry>product</key_in_registry>
	</action>
	<action method="append">
		<block>product.info.options.wrapper</block>
	</action>
	<action method="append">
		<block>product.info.options.wrapper.bottom</block>
	</action>
</block>

They are absolutely identical except their names. Let’s take a closer look at their structure.
The first thing that falls into a glance is their type which is core/template_facade. That
means the class of both blocks is Mage_Core_Block_Template_Facade. This is a very
simple class with only three methods. It extends Mage_Core_Block_Template class so
besides of those methods any block with core/template_facade type will act absolutely
same as a block of core/template type. Let’s take a look at those three methods which make
core/template_facade blocks so special.

The first one is setDataByKey:

public function setDataByKey($key, $value)
{
	$this->_data[$key] = $value;
}

It just sets the a property with specified $key to a specified $value on a block. Easy as that.
So in our case alias_in_layout property is set to container1 and container2 for each
of two block correspondingly.
The second function is setDataByKeyFromRegistry:

public function setDataByKeyFromRegistry($key, $registryKey)
{
	$registryItem = Mage::registry($registryKey);
	if (empty($registryItem)) {
		return;
	}
	$value = $registryItem->getData($key);
	$this->setDataByKey($key, $value);
}

It gets an object from a registry by $registryKey, gets its property named $key and then sets
it as a property on a block object with same setDataByKey method. So in our case it sets the
options_container property to value which is stored in Mage::registry(‘product’)
->getData(‘options_container’). This value is defined in admin interface for each
product at the Design tab:

Screen-shot-2012-12-02-at-8.20.42-PM-650x390

So after those instructions in catalog.xml are applied we have two blocks with two properties
set on each. Further in same XML one can find two interesting actions:

<action method="unsetCallChild">
	<child>container1</child>
	<call>ifEquals</call>
	<if>0</if>
	<key>alias_in_layout</key>
	<key>options_container</key>
</action>
<action method="unsetCallChild">
	<child>container2</child>
	<call>ifEquals</call>
	<if>0</if>
	<key>alias_in_layout</key>
	<key>options_container</key>
</action>

The only difference is again only the name of a child node. What this action does is it kill
the block that was just created if ifEquals method returns false. And as you may already
guessed this is the third method of Mage_Core_Block_Template_Facade class.

public function ifEquals($conditionKeys)
{
	if (!is_array($conditionKeys)) {
		$conditionKeys = func_get_args();
	}
	// evaluate conditions (equality)
	if (!empty($conditionKeys)) {
		foreach ($conditionKeys as $key) {
			if (!isset($this->_data[$key])) {
				return false;
			}
		}
		$lastValue = $this->_data[$key];
		foreach ($conditionKeys as $key) {
			if ($this->_data[$key] !== $lastValue)
			{
				return false;
			}
		}
	}
	return true;
}

What it does, it takes passed conditions and compares them. Number of conditions can be
variable which is served by func_get_args function. In our case alias_in_layout is
compared to options_container.
So what happens is two (or more) blocks are added and then some of them are removed
depending on result of equation. Sounds a little be weird but as long as this functionality is
already there you can use it in cases you want some blocks to be displayed or not depending on
per-product based settings.

Spoiler

Unfortunately this technology has no future. Magento core team possibly evaluated that it is
currently used only in one case which is described in this article and deprecated it in Magento 2.



Ein Beitrag von Tim Bezhashvyly
Tim's avatar

Tim Bezhashvyly is an ex-Magento developer passionate about new technologies and their implication in the real web projects.

Alle Beiträge von Tim

Kommentare
Josh am

Ahh, in response to my comment above, the template that renders the configurable product options is:

catalog/product/view/type/options/configurable.phtml

Josh am

Great article. I've always wondered how "container1" and "container2" worked. This was super informative.

Unfortunately, I am trying to track down the templates that build out the actual HTML for rendering those options. If anyone knows where I can find that, let me know for sure.

Nader am

Thanks Mate, It was really great. :)

Ladeneinrichter am

Great Article!!! Exactly this i was searching for....

kruti am

Hello,

How to add product custom option tab in Tabbing? Also I want one add one option "Show in tab" after "Block after info column" in "Display Product options in".

I want when i select Show in tab that time automatically product option add in tabbing.

I implement code and also i got success. i created successfully option in drop down and also add in tabbing.

But i have no idea how i check when user select "Show in tab" option in "Display Product options in". That time it display otherwise it does not display in tabbing. Please give me some idea.

Thanks in Advance.

Tobias Vogt am

Many thanks tim. It is really great that you have contributed to our Adventskalender :-)

Zyava am

There is such thing as helper attribute. It was introduced in Magento 1.x in 2008. It can be used on arguments of actions.


    paypal/hss/review/button.phtmlcheckout.onepage.review.button

See also Mage_Core_Model_Layout::_extractArgs()

Dein Kommentar