Site Templates with CakePHP

I started with cakePHP a few months ago and was impressed by their documentation. I could find answers to most of my questions fairly quickly. However, I couldn't find a good tutorial on adding a site-wide template. Hopefully this will help other people with the same problem.

First start with an HTML template. If you don't feel like making one from scratch, any div layout will work fine. Open Source Web Design (http://oswd.org) has tons of free templates that work perfectly with CakePHP. Here's a simplified version of one of their templates:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>

<head>
<link rel='stylesheet' href='style.css'/>
<title>CakePHP</title>
</head>

<body>
<div class="site_container">
 <div class="main_content">
  <div class="top_header">
   <div class="site_title">
    <h1>CakePHP</h1>
   </div>
  </div>

  <div class="content">
   <!-- Main Site Content -->
  </div>

  <div class="sidenav">
   <h1>Navigation</h1>
   <a href='#'>Link 1</a>
   <a href='#'>Link 2</a>
  </div>
 </div>
</div>
</body>

</html>

Copy this template to app/views/layouts/default.ctp. If that file doesn't exist, create it.

The first thing we have to change is the stylesheet. We are currently including the stylesheet with:

<link rel='stylesheet' href='style.css'/>

We need to copy the file style.css to app/webroot/css/style.css. Then replace the above code with:

<?php
 echo $html->css('style');
?>

The next step is to include the page content. Edit the template as follows:

<!-- Main Site Content -->
<?php 
 $session->flash(); 
 echo $content_for_layout; 
?> 

$session->flash(); prints error messages and alerts.
echo $content_for_layout; prints the page content.

Now for the side navigation. To keep the code clean, let's create a new file that just holds the navigation bar. Create the file app/views/elements/menus/sidenav.ctp. Here's some sample data for that page.

<?php
 echo $html->link("Home","/pages/home");
 echo $html->link("About Us","/pages/about"); 

 //if user is logged in
 if($this->Session->check('User'))
  echo $html->link("Sign Out","/users/logout"); 
 else
  echo $html->link("Sign In","/users/login"); 
?>

Here is the current code for the side navigation bar:

<div class="sidenav">
 <h1>Navigation</h1>
 <a href='#'>Link 1</a>
 <a href='#'>Link 2</a>
</div>

Change this to:

<div class="sidenav">
 <h1>Navigation</h1>
 <?php echo $this->renderElement('menus/sidenav'); ?> 
</div>

You can add other page elements the same way you did the side navigation bar.

Hopefully this gives you an idea of how templates work in CakePHP.

My Experience with JQuery

I had a project recently where I needed to make an online contact management website with similar functionality to Outlook and ACT!.

I wrote all the javascript from scratch for the first version of the site. I ended up writing over 1000 lines of code to add various features, such as ajax search, autocomplete, input masking, and security.

The code was getting too complex to manage so I decided to look for an alternative. I came across several javascript libraries, including mootools and YUI. I tried each of these, but the learning curve was too steep. I would spend hours just trying to implement a simple feature. This ended up being worse than my custom code.

The next library I tried was jQuery. At first this looked just as bad as the others, but after fooling around with it for a few hours, I fell in love. The language is very simple to understand. It all consists of a single $() function that replaces and improves document.getElementById(). Here are some examples.

//Select the element with id "test"
$("#test")
//Select elements with a class of "style1"
$(".style1")
//Select all <p> and <blockquote> tags
$("p, blockquote")
//Select all input fields inside of a form
$("form input")

Most selections that works in CSS work with the $() function. All jQuery functions start with a selection like this. Different functions are chained together after this to perform tasks. For example:

//Change the color of all <p> tags to red and 
//add the word "hello" to the end of each.
$("p").css('color','red').append('hello');

In the previous example, this paragraph would turn into:

In the previous example, this paragraph would turn into:hello

The built-in functions can acomplish a lot, but the real power of jQuery comes from the plugins. jQuery is one of the few frameworks that completely supports 3rd part plugins. Some common ones add things like tabs, accordions, autocomplete, tooltips, rich text editing, and so on.

All you need to use one of these plugins is to include the script. Here's an example using the tooltips plugin.

<script type='text/javascript' src='jquery.js'></script>
<script type='text/javascript' src='jquery.tooltips.js'></script>
<script type='text/javascript'>
//Add a tooltip to every element with class 'tooltip'
$(".tooltip").tooltip();

//Add a tooltip with custom options
$(".custom").tooltip({ 
    track: true, //follow the mouse
    delay: 0, //show tooltip instantly
    fade: 250 //fade tooltip out
});
</script>

Here's a list of the plugins I used for my contact management site:

  • Meio Mask - This conforms entered input to a specified format or "mask". For example, if you enter a phone number, no matter how you enter it, it will always look like "(123) 456 - 7890". I used this to standardize entered data and to make searching easier.
  • Tooltip - This plugin lets you add tooltips to any element. They can be anywhere from simple text to advanced layouts with images. I used this on any icons to provide a nice user interface.
  • Autocomplete - Provides an easy way to add autocomplete fields to your site. I used this for my ajax search and to suggest city and country names to reduce misspellings and standardize data.
  • Editable Combo Box - This lets you type your own value in a select box. I used this along with some server side scripting to allow users to easily add options to drop down menus.
  • Date Picker - This creates pop-up calendars for entering dates. I used this on all my date fields to provide an alternate way to enter data.
  • Tabs - This creates an element with tabs containing different content. I used this to fit more information in a single place.

The uncompressed jQuery framework with these plugins is close to 200kb. This is a little much to load for every page. Luckily, there are ways to reduce the size by more than half. The easiest way is to use the Javascript Minifier. This removes all comments and unnecessary spaces and linefeeds.