CakePHP: Dynamic Content in Layout

I was working on my first CakePHP project. I created a layout for the project and I realized that the layout was the same for multiple pages in the application – only the content was different. At first, I began to duplicate the layout for the other pages and changed the content accordingly. This didn’t make sense – I hate repeating the same code. CakePHP did not seem to have a way to create dynamic content within a layout. My first thought was to create the project using CodeIgniter’s, but I really wanted to create a web application using CakePHP.

After struggling to find a solution, I finally found the the correct way to create dynamic content with CakePHP.

Note: This post has been rewritten. When I first created this post, I was new to CakePHP. The original post did not display the best solution for creating dynamic content, so I rewrote it.

The Controller

First I created my controller method.

function index() {
	// get title from configuration file
        $title = Configure::read('Settings.web20_site_title');
        // set page title
	$this->pageTitle = $title . ': Web 2.0 Domain Name Generator';
        // set header title
	$this->set('headerTitle', $title . ': Web 2.0 Domain Name Generator'); 
	$this->set('sideBar', 'web20_sidebar');
	$this->set('footerAds', 'web20_footer_ads');
	$this->set('frameworkStyles', 'jquery-ui/custom-theme/jquery-ui-1.7.2.custom');
	$this->set('pluginStyles', 'imdomainsearch/imDomainSearch');
	$this->layout = 'default';
}

You should notice that I am creating variables using CakePHP’s set method.

Note:

Configuration file and Bootstrap.php

You should also notice that I used Configure::read. This file is not necessary when creating dynamic content in a layout with CakePHP, but I used it because I want to display specific information that is to be loaded on a sub domain of the site. This can be done multiple ways, but I want to show how to do it using Cake’s configuration and bootstrap files.

I created a custom configuration file. I named the file my_config.php and saved it under app/config.

<?php
$config['Settings'] = array(
		'web20_site_title' => 'web20.DigitalVillage.com',
		'jqtheme_url' => 'http://jqueryui.com/themes/base/ui.all.css'
	);	
?>

I then opened app/bootstrap.php. This file will load after all other CakePHP files have been loaded. I added the following to the bottom of the file:

Configure::load('my_config');

This tells Cake to load the my_config.php file that we created after all other files have been loaded.

Default.ctp

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
		<title><?php echo $title_for_layout ?></title>
		<?php echo $html->meta('keywords', 'Ajax Domain Search, Web 2.0 Domain Generator, Web 2.0 Color Generator, Brain Storming');?>
		<?php echo $html->css('web20_styles');?>
		<?php echo $html->css($frameworkStyles);?>
		<?php echo $html->css($pluginStyles);?>
		<?php echo $scripts_for_layout ?>
	</head>
	<body>
		<div class="header">
			<h3><?php echo $headerTitle; ?><!--Brainstorming Tools For the Web--></h3>
			<div class="menu"><?=$html->link('Color Picker', array('controller'=>'colorpalettes', 'action'=>'index'));?></div>
			<div class="menu_selected"><?=$html->link('Domain Name', array('controller'=>'domainnames', 'action'=>'index'));?></div>
		</div>
		<div id="page">
			<div id="leftSideTop">
			<?php 
			if (isset($showLayoutContent)) {
				echo $content_for_layout; 
			}
			?>
			</div>
			<div id="sideBar">
				  <?php echo $this->element($sideBar); ?>
			</div>
			<div id="leftSideBot">
				<?php echo $this->element($footerAds); ?>	
			</div>
		</div>
	</body>
</html>

content_for_layout

The first thing to notice is $content_for_layout. It is used to display any content that is contained within the relevant view file. Because the controller method is named strong>index, CakePHP will automatically look in the index view file to get the content to be loaded. In the index method displayed above, the $showLayoutContent variable does not exist, so no content will be displayed.

I have another controller in my application where the index method sets the showLayoutContent variable:

$this->set('showLayoutContent', true);

Cake will automatically display the content for this view (app/views/colorpalettes/index.ctp):

<h3>Select a Color to View Color Harmonies</h3>
<div id="tab_cntnr">
	<ul>
		<li><a href="#" class="ui-corner-all">Web 2.0</a></li>
		<li><a href="#" class="ui-corner-all">Web 216</a></li>
		<li><a href="#" class="ui-corner-all">From Image</a></li>
	</ul>
</div>
<div id="harmonyResults"></div>
<div id="tabs">
	<div id="tabWeb20" class="tab_content tab_cnt_2"></div>
	<div id="tabWeb216" class="tab_content tab_cnt_2"></div>
	<div id="tabImage" class="tab_content">
		<p>Enter the URL of the image</p>
		<input type="text" id="tImageName"></input> <button id="btnGetImage" class="fg-button ui-state-default ui-corner-all">Get Image</button><br />
		<p>Or select a random Flickr image <button id="btnFlickr" class="fg-button ui-state-default ui-corner-all">Flickr</button></p>
		<div id="swatch216Cntnr"></div>
	</div>
</div>

So if the $showLayoutContent variable does not exist, then no content will be displayed in the layout file.

Elements

Another way to display dynamic content is using CakePHP’s elements function. Elements are small bits of presentation code that need to be repeated from page to page. Elements are stored under app/views/elements. In my application, I want to create dynamic content in the sidebar and the footer ads of my website:

<div id="sideBar">
    <?php echo $this->element($sideBar); ?>
</div>
<div id="leftSideBot">
  <?php echo $this->element($footerAds); ?>  
</div>

I have set dynamic variable names that represent the file names in my controller.

$this->set('sideBar', 'web20_sidebar');
$this->set('footerAds', 'web20_footer_ads');

So CakePHP will display the contents of the files app/views/elements/web20_sidbar.ctp and app/views/elements/web20_footer_ads.ctp. Pretty neat.

So now all of your controllers that use the same layout are now able to display dynamic content without having to create duplicate code. Cool.

Personal Comment

Before I end, I have to say that my original blog post did not create the best solution for creating dynamic content using CakePHP (but it worked). I received a few comments that were very insightful and pointed me in the right direction, but I also received comments that were arrogant, demeaning, and religious in nature (and therefore not helpful).

I created this site so that all developers can benefit from what I (and others) have learned (as I learn, I hope that you learn). When someone posts a comment that is short on details and only says that only says that one should read the book, I ask: Remember when. Remember when you first started. Remember when you didn’t have all the answers. Don’t be an ass. Share.

“When you can pull the pebbles from my hand..”.

Be Sociable, Share!

Checkout My New Site - T-shirts For Geeks