Skip Navigation

Layouts with Content Variables

Phillip Harrington

What is Fusebox 4.1?

For the purpose of this article, I'm going to assume you are familiar with Fusebox 4.1. If not, check out the official Fusebox web site, the Fusebox PHP list archives, the new Fusebox PHP Wiki, and perhaps (ahem) my other articles.

What are Content Variables?

Content Variables are way to capture the results of a DO statement and (as of Fusebox 4.1) an INCLUDE statement into a variable, instead of having those results output to the screen.

Lets look at an example. Imagine we have an article database with a web interface made in Fusebox. In the circuit "articles" we have a fuseaction named "oneArticle."

<!-- articles circuit.xml -->
<circuit access="public">
	<fuseaction name="oneArticle">
		<set name="attribute.article_id" value="1" overwrite="false" />
		<include template="qryArticle" />
		<include template="dspArticle" />
	</fuseaction>
</circuit>

In qryArticle, we simply query for an article in the database with the article id passed in attributes:

<?php
# assume $db is already set...
$sql="select * from articles where article_id = " . (int)$attributes['article_id'];
$qry=mysql_query($sql, $db);
?>

In dspArticle.php we make that query into HTML

<?php
$row=mysql_fetch_assoc($qry);
?>
<h2><?=$row['title']?></h2>
<?=$row['body']?>

If you run the above code w/ the url: http://yoursite.com/index.php?fuseaction=articles.oneArticle&article_id=5. Fusebox will go to the "articles" circuit," find the fuseaction "oneArticle," and include the files "qryArticle.php" and "dspArticle.php". The "qryArticle" file outputs nothing. The contents of "dspArticle.php" file will get output to the browser.

If you modify this a bit, you can catch the contents of dspArticle.php into a variable, instead of having them be output to the browser. How? All we do is change our circuit.xml code a bit.

<!-- articles circuit.xml -->
<circuit access="public">
	<fuseaction name="article">
		<set name="attributes['article_id']" value="1" overwrite="false" />
		<include template="qryArticle" />
		<include template="dspArticle" contentvariable="layout" />
	</fuseaction>
</circuit>

We provided a valid variable name to the contentvariable attribute.

Note: We didn't provide a variable in the form contentvariable="$layout" with a leading dollar sign. This is one way that the Fusebox 4.1 XML tries to be non language-specific. This XML will carry over to ColdFusion nicely. In ColdFusion, we similarly would not say contentvariable="#layout#".

If you run the new code, nothing will get output. Why not? Ultimately, all we did was set a variable. But once we have a variable we can use it. We'll come back to doing something with it later.

Content Variables with DO

We can do this same trick with the DO verb. Say for example's sake that we have our articles application in an MVC style set up. We have a controller circuit, a model circuit and a view circuit.

First, we move our two fuses above into their respective places in model and view circuits.

<!-- model circuit.xml -->
<circuit access="internal">
	<fuseaction name="getArticle">
		<include template="qryArticle" />
	</fuseaction>
</circuit>
<!-- view circuit.xml -->
<circuit access="internal">
	<fuseaction name="showArticle">
		<include template="dspArticle" />
	</fuseaction>
</circuit>

Then in our controller circuit, we make the following changes so we're using DO instead of INCLUDE.

<!-- controller circuit.xml (was articles circuit.xml) -->
<circuit access="public">
	<fuseaction name="article">
		<set name="attribute.article_id" value="1" overwrite="false" />
		<do action="model.getArticle" />
		<do action="view.showArticle" contentvariable="layout" />
	</fuseaction>
</circuit>

In this example we've queried for the article in the model.getArticle fuseaction (which included qryArticle) and captured the result of view.showArticle DO statement into a variable called "layout".

What does this have to do with Layouts?

In many Fusebox applications I've seen, developers commonly make use of the global fuseactions to implement layouts. They use a header and a footer file. Consider the following fusebox.xml code:

<globalfuseactions>
	<prefuseaction>
		<do action="layouts.header">
	</prefuseaction>
	<postfuseaction>
		<do action="layouts.footer">
	</postfuseaction>
</globalfuseactions>

This means we must have a circuit called "layouts." In the layouts circuit we need to have two fuseactions:

<!-- layouts circuit.xml -->
<circuit access="internal">
	<fuseaction name="header">
		<include template="layHeader" />
	</fuseaction>
	<fuseaction name="footer">
		<include template="layFooter" />
	</fuseaction>
</circuit>

In layHeader.php we have the top half of a basic layout (these layout examples are boring on purpose):

<html>
<head>
<title>My Web Site</title>
</head>
<body>

In layfooter.php we have the bottom half of a basic layout:

</body>
</html>

A Better Way

So what? What's wrong with this set up? Um, nothing is really wrong with it, unless you don't want your header and footer on every single fuseaction. Also with this set up, you're stuck maintaining two files for one layout, layHeader.php and layFooter.php. Let's try taking the contentvariable $layout that we set above and using it in a layout file. Make the following changes:

First take the global fuseactions out of fusebox.xml:

<globalfuseactions>
</globalfuseactions>

Then change the layouts circuit so it only has one fuseaction:

<!-- layouts circuit.xml -->
<circuit access="internal">
	<fuseaction name="main">
		<include template="layMain" />
	</fuseaction>
</circuit>

Then take all the html in the layHeader.php and layFooter.php files and past them into a new file, layMain.php. You can delete layHeader.php and layFooter.php. This new file should look like this (remember this example is boring on purpose):

<html>
<head>
<title>My Web Site</title>
</head>
<body>
</body>
</html>

Now, add the following line between the BODY tags:

<?=$layout?>

The whole thing should look like this:

<html>
<head>
<title>My Web Site</title>
</head>
<body>
<?=$layout?>
</body>
</html>

With our new layouts circuit and layMain.php in place, let's go back to our controller circuit from before and make some changes:

<!-- controller circuit.xml (was articles circuit.xml) -->
<circuit access="public">
	<fuseaction name="article">
		<set name="attributes['article_id']" value="1" overwrite="false" />
		<do action="model.getArticle" />
		<do action="view.showArticle" contentvariable="layout" />
		<do action="layouts.main" />
	</fuseaction>
</circuit>

What did we do? We kept the contentvariable="layout" attribute on our DO view.showArticle statement, and we added a DO statment to the layouts.main circuit/fuseaction. Now when we run it, we get output! Hooray!

What happened?

First we gave $attributes['article_id'] a default value of 1 (by setting it w/ overwrite="false", which will not set it if it's already set), but that's not important right now.

We then used DO to run model.getArticle. Stepping into that circuit/fuseaction, we end up including the qryArticle.php file in the model circuit.

Next, we used DO to run view.showArticle. Stepping into that circuit/fuseaction, we end up including the dspArticle.php file. However, since we provided a contentvariable, that output is captured to a variable, $layout.

Finally, we used DO to run layous.main. Stepping into that circuit/fuseaction, we know that layMain.php is included. This file has a reference to the $layout variable. The $layout variable was set by the previous DO statement, so it's value is output in the middle of layMain.php's HTML. Pretty slick.

This is just a basic overview to help you get started. There are crazier things you can do with contentvariables. I'll try to write more as soon as possible to help you out :-).

This page has been viewed at least 2356 times, since we started counting, which was years after this page was up in the first place.

"Look for the ridiculous in everything, and you will find it." - Jules Renard