Full CakePHP 1.2 App Part 9

Cake Catalog Main Index Page

I've been a bit slow on the updates recently, been super busy with life and everything but thats no excuse. In my last article I went through the process of turning a Photoshop design into HTML/CSS and now its time to get CakePHP involved.

In this article I'm going to transfer the design and code over to CakePHP by using a new Layout and making use of some elements, this isn't necessarilly hard to do but the process it quite involved so I'm going to break it down.

Layouts

Have a quick read of the Layouts Chapter, basically a layout acts as a wrapper file with the code contained in your View files gets outputted in the "$content_for_layout" variable.

In essence a layout saves you from writing out the DocType and head section of the HTML including all the links to your CSS and Javascript files. Layouts can also make use of special variables that allow you to change the Title of the page in your Controllers as well as include page specific Javascript. These variables are $title_for_layout and $scripts_for_layout respectively.

I've created a new layout file at /app/views/layout/index.ctp and it includes all the basic code for any HTML page. It has a DocType declaration along with a head and body section. The file also include the $title_for_layout variable and goes on to include all my CSS and Javascript files. As you can see I'm using the Cake helpers to link to the files.

Inside the body I'm using elements (which I'll cover very shortly) to include some header code, then echoing out my View code by using the $content_for_layout variable and finally use another element for a footer and close the body and html tag.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php echo $title_for_layout; ?></title>
<?php
// include css file
echo $html->css('cakecatalog');
// if the javscript helper is set include the javascript library
if(isset($javascript)) {
	echo $javascript->link(array('jquery-1.2.3.pack', 'common'), true);
}
// variable for any other javascript
echo $scripts_for_layout;
?>
</head>

<body>
<?php
// include a header element
echo $this->element('index_header');
// echo out view code
echo $content_for_layout;
// include a footer element
echo $this->element('index_footer');
// if debug is on echo to screen
echo $cakeDebug;
?>
</body>
</html>

To make use of the new layout file and to dynamically set the page title in a controller I can do the following:

// file: /app/controllers/dvds_controller.php

// set page title
$this->pageTitle = 'CakeCatalog - Index Page';
// set layout file
$this->layout = 'index';

At the moment I'm only using the new layout for the index() view of the dvds_controller, if I wanted to use the layout permanently I could either set the layout in the beforeFilter() method of my controller or I could simply rename the file from index.ctp to default.ctp. If a default file is present Cake will automatically use it for.... you guessed it, the default layout across your application.

Elements

Again have a quick read of the Elements Chapter in the Cookbook to get a greater understanding of what they're all about. Basically they work the same way as general PHP includes, small chunks of re-usable code that you can put in a seperate file to save you some time.

I've created two Elements at /app/elements called index_header.ctp and index_footer.ctp and obviously they will contain code for the Header and Footer of my main page.

The Header element looks like this:

// file: /app/views/elements/index_header.ctp

<div id="wrapper-header">
	<div id="header">
		<div class="logo">
			<h1>CakeCatalog</h1>
			<h2>an online application to track and catalog your collection of dvds built using cakephp</h2>
		</div>

		<div class="filters">
			<form action="" method="post">
				<fieldset>
					<div class="input">
						<select>
							<option>Format</option>
							<option>Option 1</option>
							<option>Option 2</option>
							<option>Option 3</option>
						</select>
					</div>
					<div class="input">
						<select>
							<option>Type</option>
							<option>Option 1</option>
							<option>Option 2</option>
							<option>Option 3</option>
						</select>
					</div>
					<div class="input">
						<select>
							<option>Location</option>
							<option>Option 1</option>
							<option>Option 2</option>
							<option>Option 3</option>
						</select>
					</div>
					<div class="input">
						<select>
							<option>Genre</option>
							<option>Option 1</option>
							<option>Option 2</option>
							<option>Option 3</option>
						</select>
					</div>
					<div class="clear"></div>
					<div class="input">
						<input type="text" value="enter search items" />
					</div>
					<div class="input">
						<button type="submit" name="submit">Filter</button>
						<button type="reset" name="reset">Reset</button>
					</div>
				</fieldset>
			</form>
		</div>
	</div>
</div>

The Footer Element looks like this:

// file: /app/views/elements/index_footer.ctp

<div id="wrapper-footer">
	<div id="footer">
		<div class="box top-rated">
			<h2>Top Rated</h2>
			<ol>
				<li><a href="">Desperado</a></li>
				<li><a href="">From Dusk Till Dawn</a></li>
				<li><a href="">Kill Bill Vol.1</a></li>
				<li><a href="">Pulp Fiction</a></li>
				<li><a href="">Reservior Dogs</a></li>
			</ol>
		</div>
		<div class="box recently-added">
			<h2>Recently Added</h2>
			<ol>
				<li><a href="">Desperado</a></li>
				<li><a href="">From Dusk Till Dawn</a></li>
				<li><a href="">Kill Bill Vol.1</a></li>
				<li><a href="">Pulp Fiction</a></li>
				<li><a href="">Reservior Dogs</a></li>
			</ol>
		</div>
		<div class="box top-genres">
			<h2>Top Genres</h2>
			<ol>
				<li><a href="">Desperado</a></li>
				<li><a href="">From Dusk Till Dawn</a></li>
				<li><a href="">Kill Bill Vol.1</a></li>
				<li><a href="">Pulp Fiction</a></li>
				<li><a href="">Reservior Dogs</a></li>
			</ol>
		</div>
		<div class="box most-active box-last">
			<h2>Most Active</h2>
			<ol>
				<li><a href="">Desperado</a></li>
				<li><a href="">From Dusk Till Dawn</a></li>
				<li><a href="">Kill Bill Vol.1</a></li>
				<li><a href="">Pulp Fiction</a></li>
				<li><a href="">Reservior Dogs</a></li>
			</ol>
		</div>
		<div class="clear"></div>

		<div class="copyright">
			<p>built using <a href="http://www.cakephp.org" target="_blank">CakePHP</a> by 
			<a href="http://www.jamesfairhurst.co.uk" target="_blank">James Fairhurst</a></p>
		</div>
	</div>
</div>

Currently these elements are static and don't do very much, this will change in my next article when I'll hook up the form functionality and start grabbing DVD's from the database to fill in the footer lists.

DVD's Index

In order to make the main contents work I need to wrap the entire View in my "wrapper" and "contents" divs so that when the View is rendered it will be placed inside the Layout and the CSS will kick in.

<div id="wrapper-contents">
	<div id="contents">
		<!-- dvd index page goes here -->
	</div>
</div>

Now I need to deal with looping through all the DVD's and displaying them inside "shelf" divs. I can do this by using some nifty PHP and check if the current DVD's number is divisible by 8, if it is I can assume that this DVD is the last one on the shelf. Basically I'm splitting up the DVDs into blocks of 8. If it is the 8th DVD then I also need to close the current "shelf" div and open up a new one.

<div class="shelf">

	<?php foreach($dvds as $key=>$dvd): ?>
		<?php
		// calculate if this dvd is the last on the shelf
		// if dvd number can be divided by 8 with no remainders
		$last_dvd = ( (($key+1) % 8 == 0)? 'dvd-last' : '' );
		?>

		<div class="dvd <?php echo $last_dvd; ?>">

		</div>

		<?php
		// if this is the last dvd, close the shelf div and create a new one
		if(!empty($last_dvd)) {
			echo '<div class="clear"></div>';
			echo '</div>';
			echo '<div class="shelf">';
		}
		?>
		
	<?php endforeach; ?>

	<div class="clear"></div>
</div>

This bit of code is also quite useful for displaying picture galleries by calculating the last one in the row. The DVD index now looks like this:

// file: /app/views/dvds/index.ctp

<div id="wrapper-contents">
	<div id="contents">

		<div class="dvds index">
			<?php
			// check $dvds variable exists and is not empty
			if(isset($dvds) && !empty($dvds)) :
			?>
			<div class="shelf">
				
				<?php foreach($dvds as $key=>$dvd): ?>
					<?php
					// calculate if this dvd is the last on the shelf
					// if dvd number can be divided by 8 with no remainders
					$last_dvd = ( (($key+1) % 8 == 0)? 'dvd-last' : '' );
					?>

					<div class="dvd<?php echo $last_dvd; ?>">
						<a href="/dvds/view/<?php echo $dvd['Dvd']['slug']; ?>">
						<img src="/<?php echo $dvd['Dvd']['image']; ?>" alt="DVD Image: <?php echo $dvd['Dvd']['name'] ?>" width="100" height="150" />
						</a>
					</div>

					<?php
					// if this is the last dvd, close the shelf div and create a new one
					if(!empty($last_dvd)) {
						echo '<div class="clear"></div>';
						echo '</div>';
						echo '<div class="shelf">';
					}
					?>
					
				<?php endforeach; ?>
					
				<div class="clear"></div>
			</div>
		
			<?php
			else:
				echo 'There are currently no DVDs in the database.';
			endif;
			?>
		</div>

	</div>
</div>

CSS File and Images

To successfully reference your CSS and image files in CakePHP you must place the files in the /app/webroot directory, and I've organised the CSS, Images, Javascript into their own folders for organisation sake. You can then link to your images files in CSS as normal using the relative url:

// file: /app/webroot/css/cakecatalog.css
#wrapper-header 	{ background:url(../img/bg_header.png) repeat-x;}

The webroot folder acts as the new root directory of the site and so you can create folders here and place files in and access them directly via the browser using: htpp://dvdcatalog/folder-name.

Wrapping Up

Ok this has been just a quick article and introduces you to Layouts and Elements, pretty simple concepts when you get your head round them but its always good to start at the beginning and hopefully this has been a good example on how to use them.

Source Code

The source code for this article can be downloaded using this link. If these articles are helping you out why not consider donating I can always use a beer! :)

Next Article

In my next article I'm going to finish off the Header and Footer on the main page and hopefully get all the functioanlity up and running depending on how large the article ends up. I'm also going to polish off a few things such as defining a default controller action so that when the application loads it will automatically display the main DVDs page along with a few other tweaks.

Posted on 27th June 2008
8 years, 10 months, 4 weeks ago

comments powered by Disqus