Deploy apps to the Media Temple Grid Service with Capistrano

Last time I upgraded WordPress, I decided it was time to create a deploy process on this blog. Lots can go wrong with upgrades and updates, and I really don’t have a good reason to avoid version control and automated deployments when I can basically do it all for free.

I use Media Temple’s Grid Service, which means the Capistrano deploy recipe for pulling this off has a few customizations needed to work properly, which is why I thought I’d document it here.

For the impatient: the recipe for my Railsless WordPress deploy on Media Temple’s Grid Service. Please note the original version of my recipe, from which my version is forked. The original did almost everything I needed; yay, Github.

Technically Grid Service users do not have full root access, however, users can enable shell access and even create files above the public docroot which was enough for me to get deployments working! I am not going to document it here, but you need to set up ssh access on your Media Temple Grid account.

Prerequisites

You need to have SSH enabled on your Media Temple GS account and be able to successfully SSH into the grid service. Obviously you need to have ruby installed on your local machine, and I recommend using Bundler to manage your gems.

The Developer Setup

My goal was to use my private Git repository to run automated deployments straight from the source code. This means that my capistrano recipe and supporting files are within the project’s version control. That lead to the following project structure to keep my files out of the public folder:

-- bin/     (Contains gem executables)
-- config/  (Capistrano deployment code)
-- htdocs/  (The webroot of the project)
Capfile
Gemfile

Generate the barebones Gemfile to manage your gem dependencies, including Capistrano:

$ bundle init

Now add the following to your newly created Gemfile

source "https://rubygems.org"
gem "capistrano", "~> 2.15"
gem "capistrano-deploytags", "~> 0.7"
gem "railsless-deploy", :require => nil

Note: I may provide a future writeup once I upgrade to Capistrano 3
Update: For Capistrano 3 support (mentioned in the comments) check out capistrano-gridserver.

Next is installing your gems and “capifying” your project:

$ bundle install --binstubs
$ bundle exec capify .

You should have the skeleton needed to flesh out a deployment recipe. The next step is to add/update all files listed in my recipe so you can set up the deployment directories in the next step. Note the environment files (which allow you to deploy to multiple environments) that will reside in config/deploy/dev.rb.

Change the following values to match your account/project:

# config/deploy.rb
set :site, "1234"
set :application, "the-site.com"
# ...
set :repository, "[email protected]:myname/myproject.git"

Environments also require you to create separate config files for each environment. Based on the environment you are deploying, the respective config file will be used in that environment. In this WordPress recipe, I have:

  • wp-config-dev.php
  • wp-config-prd.php

Once you have your environment-specific configs and deploy.rb recipe saved, it’s time to run your first deployment!

# deploy:setup will install cap folders (note the dev env).
bin/cap dev deploy:setup
# Make sure it went well
bin/cap dev deploy:check
# You should see a message like "You appear to have all necessary dependencies installed"

If all went well, you are ready to rock and roll!

The Server Setup

The nice thing about doing this last for me is that I had a live site running. I was able to perfect deploying code first before finally symlinking the Media Temple defined webroot folder. Once you are ready to let capistrano take over you need to symlink the html/ folder to the symlink that capistrano created called current/.

$ ssh mt
$ cd ~/domains/the-site.com
# Move static code to a backup folder in case things go wrong.
$ mv ./html ./html-backup
$ ln -s ./current/ ./html

If you plan on keeping the multi-stage stuff (which I highly suggest) then you will need to set up multiple domains (ie. a subdomain) for each environment in your Media Temple GS account. Then each environment would have a unique :application value configured for each environment:

# config/deploy/dev.rb
set :application, 'dev.your-site.com'
set :branch, 'develop'

The Recipe

I am not going to go over every line of the deployment recipe featured in this article, but I will cover some unique things that needed tweaked to work with Media Temple’s Grid Service.

To get symlinks working properly relative symlinks are required. This requires overriding the deploy:create_symlink task to use a defined relative_path method to symlink paths properly. The create_symlink task points to my /htdocs folder to keep configuration and deployment code out of the webroot.

Secondly, I created a custom task redmonster:symlinks to symlink uploaded images to a shared folder so that all the releases will use the same shared folder for generated media.

Deploying the Thing

After you have verified that releases are being deployed to your Grid Server account, here is the normal workflow using the multistage configuration.

# do some work
git push origin develop
cap dev deploy
# ready for production?
git checkout master && git merge develop
cap prd deploy

Pay attention to the environment-specific Ruby files. They usually tweak things like the domain name you might deploy to and the branch that will be used in deployments. Be sure and check out the documentation for all the things you can do with capistrano.

Capistrano Plugins

As demonstrated, my recipe is using the railsless-deploy gem and the capistrano-deploytags gem for creating tags for each deploy. The capistrano-deploytags gem is completely optional, but I find it provides a nice deployment history built right into my version control system.

WordPress Stuff

To ease configuration of WordPress options in multiple environments, I define the WP_SITEURL and WP_HOME constants. This allows database syncronization later on without having to manually update these options in the database.

Here is how I do it in wp-config.php:

// ...
if (getenv('SERVER_NAME')) {
    $server_name = getenv('SERVER_NAME');
    $site_url = sprintf("http://%s", $server_name);
    define('WP_SITEURL', $site_url);
    define('WP_HOME', $site_url);
}

I hope this writeup was helpful, I was really excited to have working deployments. It has already been helpful. Hope you enjoyed!

Update: For Capistrano 3 support (mentioned in the comments) check out capistrano-gridserver.

Creating JavaScript Functions Faster in TextMate

TextMate’s JavaScript bundle has been getting some love from me this week. I am not presenting anything new here, but I often find gems hidden within the Bundles in TextMate that speed up my development.

f + tab

This creates an anonymous function, which is great when using jQuery or many other JS libraries out there. I tweaked mine to remove the semi-colon at the end.

functionname+shift+return

If you type out the name of your function, then immediately hit Shift + Return, TextMate will convert it into a function.

fun+tab

Construct a function with tab stops.

Five Great Resources for Beginning PHP Programmers

Build Your Own Database Driven Web Site Using PHP & MySQL

Author Kevin Yank is a seasoned writer, who delivers a masterful explanation of how to program with PHP, in a tutorial-style format. The book is easy to follow and is specifically written for beginners. Sitepoint books are known in the community for their paramount quality of books on web technologies. This book will help you grasp core fundamentals of the PHP language and MySQL. Check out Kevin Yank’s article related to the newest edition of the book, with four tutorials.

PHP Solutions: Dynamic Web Design Made Easy

PHP solutions is a wonderful resource for beginners, and I personally find the PHP installation section invaluable for beginners. If you’re on Windows, this book walks through the process of setting up the PHP environment from source and configuring Apache.

David focuses on PHP as a language without introducing database logic until later in the book – which helps the reader focus on PHP without even worrying about MySQL. Readers will also gain important insight on how forms are processed, manipulating images, creating a dynamic photo gallery, and a number of core concepts beginners need to learn on the way to mastering PHP.

Zend – The PHP Company

Zend is the keystone to the PHP community in many regards. The PHP 101 articles are great beginner tutorials cover the most essential parts of learning PHP. Become familiar with the Zend developer zone.

PHP Manual

This resources is an obvious one, but keep the PHP manual handy. Firefox has a search engine plugin for the PHP manual which makes it really easy to search, and in Google Chrome you can type “php.net” + space + function and Chrome will automatically take you to search results.

Be cautious of the user examples on php.net; some are useful, but don’t copy code blindly from commenters without learning exactly what the code is doing. There are code examples which are part of the official documentation – these are separate from user comments.

Online Forums

Online forums are not the fastest way to find what you are looking for if you need help; but if you don’t personally know anyone familiar with PHP, forums are a great way to ask questions to experienced developers. I particularly like Sitepoint’s PHP forum and devshed.

Next Steps

Once you’ve mastered the essentials of PHP, you need to learn about Object Oriented Programming. David Power’s PHP Object Oriented Solutions is a perfect companion to the aforementioned PHP Solutions.

Coupling and Frameworks

Around the same time that the Ruby on Rails framework was released as open-source, programmers have been going nuts about frameworks and code libraries.

I love using frameworks, but, I have been thinking about how much code I have released over the last couple years that really didn’t need to rely on the work of others. When I write JavaScript that mixes in JQuery or MooTools, a quiet voice in my head reminds me that my scripts are now tightly coupled to a framework. Doh!

Sure, frameworks make us work faster and add very convenient features, but they can abstract us from the core languages we use everyday. We can become numb to the core language.

Have a javascript file that needs to various id attributes? JQuery offers very attractive way of finding nodes in the DOM.

var nav = $('#nav');

As opposed to vanilla JavaScript:

var nav = document.getElementById('nav');

We saved ourselves 22 letters using JQuery. That’s awesome! I’m sold! But now one line has bound client code to an external library. This is a small price to pay, but when your company starts using YUI instead of JQuery, how much code will you have to change in the overall scheme of things? Answering this question will tell you how tightly coupled your code is to external sources.

Continue using your frameworks. This post isn’t trying to convince readers to ditch frameworks. This post is a reminder that programmers should try to make code as framework-agnostic as possible.

Serious PHP debugging With XDebug

Any serious PHP developer should use a debugging tool. Applications are becoming more complex, using OOP, and spanning more files. This post will quickly bring you up to speed and give you the most awesome debugging tools on the planet.

I have been using Zend Server CE for local development. It has all the bells and whistles you need, and you can pick from 5.2 or 5.3. Zend Server CE comes with the Zend debugger, but I prefer to use XDebug. You can follow this tutorial to get XDebug working with Zend Server CE on OS X.

Once you have XDebug installed, you should see it listed in PHP info by calling

<?php phpinfo(); ?>

in a PHP script or

php -i

from the command line.

Configuring XDebug

Once you have XDebug working and you have restarted Apache, you need to add a few things to your php.ini file if you want to actually step through your code line-by-line. If you are using Zend Server CE, it is probably located at

/usr/local/zend/etc/php.ini

Add the following lines to your php.ini file under zend_extension (add lines in bold):

[xdebug]
zend_extension="/usr/local/zend/lib/php_extensions/xdebug.so"
xdebug.remote_enable=On
xdebug.remote_autostart=On

Restart Apache again, and you can double-check php info to see the changes to remote_enable and remote_autostart were set correctly.

These php.ini settings allow debugging to start automatically in an external application, as you will see below…

MacGDBp – Debugging Software for XDebug

Users of OS X can install a program called MacGDBp to step through PHP code and debug variables. This application intercepts browser requests made to your application, and allows you to set breakpoints and debug your code much faster.

Windows users have a couple software options for xDebug, such as Ultraedit Studio, Komodo Edit, Aptana (although I have never got it working correctly with Aptana), Eclipse, et al.

With MacGDBp open, load a page from your web browser in a PHP application hosted on localhost, and your browser will look like it’s hanging (if you set up xDebug correctly). You should see the first part of your application code in MacGDP.

You can also add breakpoints by browsing to files with the breakpoint window. In MacGDBp, open Breakpoints by going to Window > Breakpoints or Shift + Command + B. Click the plus button to browse through your files.

Once the file appears in the breakpoints window, you can click line numbers to add breakpoints. Breakpoints will appear as blue arrows. At the time of this writing, clicking the correct line number was somewhat difficult for me, but it just takes some getting used to. The application will halt execution at your breakpoints after you click “Run” in MacGDBp.

MacGDBp_breakpoints

Assuming the file you add is loaded during the page request, if you click “Run”, MacGDBp will let the browser request resume until it hits your breakpoint. From here, you can step in/out/over of functions. You can also browse variables and make sure they are being set properly.

If you need to step through the code again, click the “Reconnect” button on the top right in MacGDBp, and click refresh in your browser. You can also leave MacGDBp disconnected and develop your application normally until you need to debug again. When you reconnect macGDBp, it will then stop at the first line of code, allowing you to step through again or run to your next breakpoint.

MacGDBp_step

Step In, Step Out, Step Over

When you start debugging a request with MacGDBp, you will be presented with the first executable line of code. At this point, you can determine how to proceed. If the line is a function, you can click “Step In” and MacGDBp will take you to the function being called.

While in that function, you will step through that function line-by-line. You can continue to step through functions called within other functions, which can get you lost in a hurry if you’re not careful. If you want to stay inside the current function, you can click “step over” at a function to go to the next line.

Stepping out will bring you back to the original code where you stepped into the current function originally. This is helpful if you accidentally step into a function and you want to go back.

Modifying UI

I recommend modifying the icons in MacGDBp, to include Icons and text. You can do this by right-clicking in the gray icon area of the application. You can select Icons and text, which makes it easy to understand the icons and what you are doing until you become a seasoned debugger.

icons_text

Better Than Grep

A co-worker recently introduced me to a sweet Unix terminal command “ack.” Ack is a grep replacement (or supplement) that allows you to search your file system, but ignores folders like .svn, cvs, and other folders you would not want to search on a version-controlled project. Ack is fast, cross-platform, and easy to use.

Test Drive Ack

Lets say you are working on a project that was passed on to you by another developer, and you are having trouble finding a template to change some simple HTML. Lets also pretend that your templates are smarty template files (.tpl) and some are PHP. Finding a unique attribute in the source of your HTML browser, you could do an ack search in your terminal to locate your template:

cd /path/to/project
ack myUniqueId -G ".tpl|.php"

The above search will return and highlight search in all files and line numbers that match “myUniqueId” in files that have “.tpl” or “.php” in them. This is not to say that only php and tpl files will be returned, but all types of files that contain “.tpl” or “.php”. Chances are good that only php and tpl files would be returned in this case, but -G is not matching file extensions exclusively.

Let’s break this command down:

  • This references ack, make sure ack was properly setup (see the ack homepage for more info on setup)
  • The second argument matches a regex pattern and serves as your search string.
  • -G “.tpl|.php” matches filenames that contain “.php” and “.tpl”.

Ack also has built-in support for various file types. If you were doing the same search above, but only cared about PHP files, you could execute the following command:

ack myUniqueId --php

The possibilities are rather endless :). If you find this helpful and interesting, let me know, I may do a follow-up post with more in-depth examples.

Update 4/20/2010: As pointed out in the comments, I had a typo in the first example and the explanation was incorrect. Sorry about that :/

Making CakePHP Templates in TextMate

I finally got around to exploring templates in the TextMate bundle editor. The PHP bundle does not have any templates, and so I set out to create a few to improve my workflow. I thought it would be helpful information for PHP developers using TextMate. I actually used the Ruby interpreter to power my templates, but you can definately use PHP, or any other interpreter you like (Python, Perl, etc.). You might want to check out Environment Variables in the TextMate manual.

For the impatient: download the bundle. You should go through this post and make sure you set up shell variables properly. They are useful and worth understanding.

Most of my PHP development is done using the CakePHP framework, and I prefer to create my own files rather than using the Bake console. Just a personal preference. My templates are already proving to save time I would spend copying/pasting code.

Automating the creation of templates will save you time. Expensive time that you don’t need to waste on repetitive stuff. You can even modify the existing templates provided in the bundle editor. I know virtually every HTML document I create will need at least one stylesheet, meta data, and scripts.

The Bundle Editor

The bundle editor provides amazing functionality to TextMate. I’m convinced that the reason I work on a Mac is TextMate and the many customizable, automated features like bundles ;).

To get our bundle started, fire up the bundle editor in Bundles > Bundle Editor > Show Bundle Editor. You could also use the shortcut, Control + Option + Command + B (the bottom three modifier keys + B). The bundle editor allows you to create snippets, macros, drag commands, templates, etc.
TextMate Bundle Editor

Creating the Bundle and Template

Templates require a few things to work. Firstly, a script that actually processes the template, allowing you to generate dynamic template elements on the fly—you’ll see how cool this feature is in a minute. Secondly, the actual template file that we will populate with our code.

  1. Create a new bundle by clicking the “+” icon on the bottom left of the TextMate bundle editor window and select “New Bundle”. Type in the name of the bundle; mine is called “CakePHP.”
  2. Now that the bundle is created, highlight it, click the “+” icon again, and select “New Template.” Enter the name of your template; mine is “Controller.”
  3. Highlight the template you just created and click the “+” icon one last time. Select “New template file”. It will be highlighted, name it something that matches the template and has the extension you want (in my case “.php”)

cakephp-textmate-bundle

Your bundle should look similar to mine. Now that the template script and template file are created, highlight the template file (mine is controller.php). Paste in the following code, I’ll explain it afterwards:

<?php
/**
 * Description
 * 
 * Copyright ${TM_YEAR}, ${TM_ORGANIZATION_NAME}. All Rights Reserved.
 *
 * @author ${TM_FULLNAME} <${AUTHOR_EMAIL}>
 * @created ${TM_DATE_FULL}
 */
class ${TM_CLASSNAME} extends AppController {
	/**
	 *
	 */
	public $name = '${TM_NAME_PARAM}';
	/**
	 *
	 */
	public $helpers = array();
	/**
	 *
	 */
	public $components = array();
	
	## Public Actions
	
	/**
	 *
	 */
	public function index() {}

	/**
	 *
	 */
	public function view($id=null){}
	
	## Admin Actions

	/**
	 *
	 */
	public function admin_index() {}

	/**
	 *
	 */
	public function admin_edit($id=null){}

	/**
	 *
	 */
	public function admin_delete($id=null){}

}

In my controller template, you will notice some dynamic elements and various actions/params that I use frequently in almost every controller.

The actual class name is generated by the file’s basename (the files name minus the extension) and is called ${TM_CLASSNAME} in the template. The basename variable is automatically available to templates. Those of you familiar with CakePHP will know that controller filenames use underscores. So the “UsersController” class file would be “users_controller.php” and the basename would be “users_controller”.

The template contains a variable called ${TM_FULLNAME} which is generated by the full name of your TextMate licence. You can see this name by clicking TextMate > Registration from the menu. The field is called “Owner”.

The other variables will be created in the template script and through shell variables (Section 9.2). Shell variables are reusable variables assigned in the preferences. These are really cool, because you can use them throughout the TextMate application. You can also create project-specific shell variables in your TextMate projects. Don’t think that they merely apply for this template only!

Let’s go ahead and create/update the shell variables this template will use:

  1. Navigate to TextMate > Preferences > Advanced and select Shell Variables.
  2. You should see a built-in shell variable called TM_ORGANIZATION_NAME with a made-up name. Edit the value of this field with the organization you want to appear in the block comment.
  3. Create a new shell variable called “AUTHOR_EMAIL” and put in your email.

TextMate shell variables

You can now use ${TM_ORGANIZATION_NAME} and ${AUTHOR_EMAIL} in your templates.

Template Script

The template script is where the real magic happens in our template. Select the template script of your bundle, and you will see a few fields. Update the fields with the following (see source code below image to copy):

Controller bundle script

Here is the source for the Command(s) field:

#!/usr/bin/env ruby -wKU

# METHODS
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
	if first_letter_in_uppercase
         lower_case_and_underscored_word.to_s.gsub(/\/(.?)/)
             { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
    else
    	lower_case_and_underscored_word.first.downcase + 
            camelize(lower_case_and_underscored_word)[1..-1]
    end
end

f = open(ENV["TM_NEW_FILE"], 'w')
template = open("controller.php").read

ENV["TM_YEAR"] = `date +%Y`.chomp
ENV["TM_DATE"] = `date +%Y-%m-%d`.chomp
ENV["TM_DATE_FULL"] = Time.now.strftime("%m-%d-%Y %I:%M %p")
basename = ENV['TM_NEW_FILE_BASENAME']

ENV["TM_CLASSNAME"] = camelize(basename)
ENV["TM_NAME_PARAM"] = camelize(basename.split('_controller').join)

if ENV["TM_SOFT_TABS"] == "YES"
	tab_size = ENV["TM_TAB_SIZE"].to_i
	tab_size = tab_size ? tab_size : 4
	template = template.gsub(/\t/, " "*tab_size)
end

template = template.gsub(/[$]\{([^}]+)\}/){|match| "#{ENV[$1]}" }
f.write template
f.close

Note that I’m borrowing the camelize method from the Rails API

You don’t have to fully understand the ruby script I’m using, but there are a few things I’ll touch on to help you understand what is going on.

  1. I wanted to customize the date to include the exact time the file was created, so I used Ruby’s Time class to create ENV["TM_DATE_FULL"] with the strftime method. I can now use it in my template as ${TM_DATE_FULL}.
  2. To follow CakePHP’s convention of camel-case class names, I use the camelize method to camelize the basename of the file and assign to ENV["TM_CLASSNAME"].
  3. The $name param of a CakePHP controller is the same as the class name, but omits “controller”, so I am splitting the file basename at ‘_controller’ and joining the first part back to a string; this string is also camel-cased using the camelize method.

The names match the custom fields in the template file—remember that they are case-sensitive.

Now when you create a new controller in a CakePHP project you can take advantage of your new template. Make sure all your template settings match my code above. You can test a template by clicking the “Test” button in the bundle editor template script.

We’re done. Create a new file in your TextMate project (Shift + Command + N in a project), select the template we just created from the dropdown, and click “create”.
textmate_new_from_template

I hope this is useful for others, it really improved my workflow. My bundle download also contains a model template too, so be sure to check out the bundle code in your new friend, the bundle editor.

Other Great Textmate Bundles

Some other textmate bundles I really cannot live without:

Introduction to CakePHP for Designers: Part II

In the first tutorial, I covered basic foundations of views, and set out create a simple task management application. This tutorial will focus on controllers, which interact with both views and models. The process of the MVC framework is a simple paradigm, where controllers handle requests, get data from the model as needed, and process the request by giving feedback to the user through views. Controllers play an important middle-man role in MVC applications.

To help illustrate the role controllers play, consider a bank. Customers request information from the bank through ATMs, online banking websites, and bank employees. Customers don’t have direct access to the bank’s safe, they must request this information from ATMs and bank tellers, etc. ATMs and tellers represent the controller in our analogy. They facilitate the requests of customers by accessing account information and money. This information is then processed and returned to the customer. In the same way, users of an MVC application make requests to the controller through views. These requests are received by the controller. The controller requests data from the database through models. Controllers then return data to views.

CakePHP controllers work closely with models to facilitate data from the database. This means we need to create a database and a table to get our controller working. We could bypass the model (controllers don’t technically need models in some cases) and just use our controller, but that would only be confusing to those learning the importance of controllers in working with both models and views.

Lets start by creating a database. For simplicity, lets name the database “taskmaster” (I know, totally cheezy :-/). You should have a working MySQL database server running. This tutorial will not go into the details of setting up MySQL and PHP. Fire up your favorite MySQL management tool, or use the handy terminal if that suits you. I’m going to type the following to login via the terminal:

mysql -u root -p

MySQL will prompt you for a password. Once you type in your password (default is blank, or no password) you will see the mysql prompt. Type in:

create database taskmaster;

Don’t forget the semi-colon! Verify that the database was created by typing in:

show databases

Now that we have our database created, lets create a table. Enter the following query to create your first table.

CREATE TABLE `tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `description` varchar(255) NOT NULL,
  `completed` tinyint(1) DEFAULT '0',
  `created` datetime,
  `modified` datetime,
  PRIMARY KEY (`id`)
);

This might seem like a simple table, but there are a few important conventions that CakePHP will reward. The table name “tasks” will ensure that we can create a controller called “TasksController” and a model called “Task”. We don’t have to do much configuration to start working with our data if we use these naming conventions. The lowercase id field is standard on any table in CakePHP. Created and modified columns will be automatically updated by CakePHP when we save a new record or update one. We don’t even have to worry about these columns when saving data.

Lets create a few records so we have actual data to retrieve from our model via the controller. Run the following queries to get some tasks in the tasks table:

INSERT INTO tasks (description, created, modified)
    VALUES ('Take out the trash.', NOW(), NOW());
INSERT INTO tasks (description, created, modified)
    VALUES ('Wash the car.', NOW(), NOW());

Note: I added NOW() twice to simulate what CakePHP will do when we create a new task within the application.

Now that our table is created and has a few tasks entered, lets jump over to our CakePHP application. The first order of business is telling CakePHP about our database. Navigate to app/config/database.php and change the default connection to match your database information. Mine looks like the following:

var $default = array(
	'driver' => 'mysql',
	'persistent' => false,
	'host' => 'localhost',
	'login' => 'root',
	'password' => '',
	'database' => 'taskmaster',
	'prefix' => '',
);

Create a new file in app/controllers called tasks_controller.php and populate with the following code:

<?php
class TasksController extends AppController {
	public $name = ‘Tasks’;
	
	public function index() {

	}
}

I’ve added an empty function for our default action. As you will see shortly, functions in controllers are actions requested by users through a URL. Index is the default action for any controller unless you specify otherwise in app/config/routes.php. Controller class names are camel-cased, and the file names use underscores, which is why TasksController’s filename is tasks_controller.php. Controllers are generally named the same as the name of the database table.

Now we need to create a model file. Create a new file in app/models called task.php and populate with the following:

<?php
class Task extends AppModel {
	public $name = ‘Task’;
}

We now have a skeleton model and controller. Since we have data, lets write our controller code to get our tasks from the database and then display them in the view. Our controller will request tasks from the tasks table, and for now, we will request all tasks (we only have two so far after all). Your tasks controller will look like this:

<?php
public function index() {
	$tasks = $this->Task->find('all');
	$this->set('tasks', $tasks);
}

We are getting all tasks in the database, using the Task model. $this->Task represents the model we just created. Both our controllers and models inherit a bunch of built-in functionality from AppController and AppModel.
$this->Task->find() is one such method. The controller then sets a variable for the view called “tasks” and is populated with an associative array that was returned from the find method. We have everything we need to display model data in the view…let’s get going!

Create a folder in app/views called tasks. This folder name also matches the controller name, which keeps our views organized. In the newly created folder, create a file called index.ctp, which matches our index function in TasksController, and paste the following:

<h1>Tasks</h1>
<table>
	<thead>
		<tr>
			<th scope="col">Id</th>
			<th scope="col">Description</th>
			<th scope="col">Complete?</th>
			<th scope="col">Created</th>
			<th scope="col">Modified</th>
		</tr>
	</thead>
	<tbody>
	<?php foreach($tasks as $task):
		$completed = $task['Task']['completed'] == FALSE ? 'No' : 'Yes';
	?>
		<tr>
			<td><?php echo $task['Task']['id']; ?></td>
			<td><?php echo $task['Task']['description']; ?></td>
			<td><?php echo $completed; ?> </td>
			<td><?php echo $task['Task']['created']; ?></td>
			<td><?php echo $task['Task']['modified']; ?></td>
		</tr>
	<?php endforeach; ?>
	</tbody>
</table>

You can now see the index action of our controller by navigating to the url of your application. Mine is http://localhost/cakephp-designers/tasks. The url contains our controller name “tasks”. You can omit the “index” action from the url because, like I mentioned above, index is the default action.

To illustrate how URLs match functions in a controller, you can navigate to http://localhost/cakephp-designers/tasks/index and get the same page. An add action might have this URL: http://localhost/cakephp-designers/tasks/add and would call a function called “add” in the TasksController class.

Our plain vanilla table has a foreach loop that loops through the data supplied from the controller that was assigned to a variable called tasks. It is important to understand the array structure that CakePHP returns when retrieving data from models. You can view the array by adding debug($tasks); in the view. You must have debugging turned on to see the array. You will notice that each record is contained in an associative array, where the key matches the model, or “Task”.

We now have a very simple, but functional controller. Our next tutorial will focus on learning about the form helper, getting data into our database from a form, validating that data through the model, and furthering your understanding of models and controllers in general. Until next time!

Introduction to CakePHP for Web Designers

CakePHP for web designers, is a series of hands-on tutorials that help new programers and those with a design background understand the basics of CakePHP. There is plenty of theory and API documentation out there on the web; I’d rather spend my time writing about hands-on examples of how you can start using CakePHP today.

CakePHP hits the sweet-spot for many of my projects. The conventions and “baked” in classes are huge productivity boosters. Even if you just intend of working with visual elements on a CakePHP project (views), this series will walk you through hands-on lessons of building a simple task management application with CakePHP.

Installing CakePHP

This series is focused on working with CakePHP, so I don’t want PHP installation interfering with the content of this series. I’ve included installation notes at the bottom of this tutorial to get Apache, PHP, MySQL going. For a full explanation of how to get CakePHP set up properly, see section 3.1, 3.2, 3.3 and 3.4 of the CakePHP book.

In a nutshell, you will download CakePHP’s latest stable version at http://cakephp.org and upload the files somewhere inside the apache document root on your development machine. I’ve installed a fresh version on http://localhost/cakephp-designers/

cakephp_designers_01

What you see in screenshot #1 is the default CakePHP page with info about your environment configuration. Obviously, we don’t want this to be the homepage of our website, but it’s nice to see something when we get CakePHP installed correctly. This page has useful information about your configuration, and potentially, gives you warnings of steps you missed during setup.

CakePHP applications follow the MVC software design pattern which we will tackle later in this series. Learning the MVC software paradigm is essential to using CakePHP, and the payoff is clean code that is more secure and easier to maintain. This post will be focusing on the “V” in MVC, or the View.

Navigate to your project’s app > views folder. Create a folder called “pages” and inside pages, create a file called “about.ctp”. The file extension “.ctp” is CakePHP view files and accepts HTML and PHP code. Lets add a basic placeholder for our about page in about.ctp:

<h1>About</h1>
<p>This is the about page for our application</p>

Navigate to your newly create page by navigating to your project url. Mine is http://localhost/cakephp-designers/pages/about Notice that our page is displaying much more than our simple HTML. View the source and you will see the entire HTML structure of your project. The doctype and other HTML code belong to the layout.

Your Layout

Right now our project is using the built-in CakePHP layout, but we want to work with our own layout. By default, CakePHP looks for default.ctp in app > views > layouts but if you look in your project you will not find default.ctp anywhere. Create default.ctp and throw in the following HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>Tasks</title>
</head>
<body>
	<?php echo $content_for_layout; ?>
</body>
</html>

Nothing special here except $content_for_layout. This variable is the output of your view. If you browse to your about page now, you will see the new template in action, and and unstyled site.

Create two more pages, in app > views > pages called index.ctp and contact.ctp and paste in the following:

<h1>Contact Us</h1>
<p>Contact info for our application will go here.</p>

and

<h1>Welcome!</h1>
<p>Welcome to my task management site.</p>

Linking

Now we have three separate pages, but no way to navigate between each page. CakePHP has a built-in helper called the HTML Helper that makes navigation links within a CakePHP application a breeze; and you can be certain that your links will always work when you follow conventions, no matter where the application resides.

We could easily create static anchor tags and call it a day, but we would be penalized in the future when we update our routes.php file or if we moved the application to another location. With static HTML links, all links would have to be manually updated each time routes.php was modified with a custom URL pattern.

Lets build the navigation using CakePHP conventions. Open default.ctp and add the navigation to this file so it will always appear in any view using default.ctp:

<div id="navigation">
	<?php echo $html->link('Home', 
            array('controller' => 'pages', 'action' => 'index')); ?> |
	<?php echo $html->link('About', 
            array('controller' => 'pages', 'action' => 'about')); ?> |
	<?php echo $html->link('Contact Us',
            array('controller' => 'pages', 'action' => 'contact')); ?>
</div>

cakephp_designers_02

If you view your project in a web browser, you will notice the magic that CakePHP performed. All the links were generated with the correct url. Unfortunately, if you click on the home link, it goes to the default CakePHP screen. We can fix that with routes.php.

Routes

Routes are an advanced topic, so we will only lightly touch on their power. Routes enable you to do magical things with your URLs and how those URLs relate to your application logic. For now, we only want our index.ctp file to be the homepage our our application. Open routes.php in app > config folder. Around line 34, you should see the default route for the homepage. Lets modify it from this:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

to this:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'index'));

Save and close routes.php. Make sure you only modify the above code–this file is critical to CakePHP. The routes.php file now considers index.ctp the homepage of the application, and you will now see your homepage in your web browser.

Styling Your Application

To conclude this tutorial, lets add some basic styles to our application. Your website assets are all located in app > webroot in their respective folders. The Webroot folder is the webroot of your application, so http://localhost/cakephp-designers/css in our project points to app > webroot > css.

Browse to app > webroot > css and create a file called style.css. You will also notice cake.generic.css which is the default css file used on the default homepage.

Add the following CSS rules to style.css:

body {
	background: #ddd;
	font: 12px "Lucida Grande", "Trebuchet Ms", sans-serif;
}
#wrap {
	margin: 20px auto;
	background: #fff;
	width: 800px;
}
#navigation, #footer {
	background: #333;
	padding: 8px 10px;
	color: #fff;
}
#navigation a {
	color: #fff;
	text-decoration: none;
	font-size: 14px;
	margin: 0 15px;
}
#content {
	padding: 5px 20px;
}
#content h2 {
	margin: 0;
}
#footer {
	font-size: 11px;
}

Update default.ctp to match the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>Tasks</title>
	<?php echo $html->css(array('style.css')); ?>
</head>
<body>
	<div id="wrap">
		<div id="navigation">
			<?php echo $html->link('Home', 
                            array('controller' => 'pages',
                            'action' => 'index')); ?> |
			<?php echo $html->link('About',
                            array('controller' => 'pages',
                            'action' => 'about')); ?> |
			<?php echo $html->link('Contact Us',
                            array('controller' => 'pages',
                            'action' => 'contact')); ?>
		</div>
		<div id="content"><?php echo $content_for_layout; ?></div>
		<div id="footer">
                    Copyright © <?php echo date("Y"); ?>. All Rights Reserved.
                </div>
	</div>
</body>
</html>

cakephp_designers_03

There are some new things in default.ctp that you might have noticed. In the of the document, I used another HTML helper method called “css” which generates a link tag to each css file listed in the array. This method automatically links to our css files in the webroot folder. This requires no additional configuration in the future, and is an important convention in CakePHP. I also threw in a date() function to show off vanilla PHP in our templates =).

Now our application is beginning to look alive, but in a boring, static way. Our next tutorial in this series will fix that, as we cover models and controllers. We must cover both simultaneously as models and controllers work closely together to deliver dynamic data in view files.

Conclusion

We just tapped the surface of the powerful features of CakePHP views. CakePHP has made it easier to create a consistent workflow for designers and developers. As you will begin to understand, following CakePHP and MVC conventions make life easier for future developers working on your applications.

We’ve covered a vast amount in a short span, but most of the learning will come from experimenting and diving into the code. Please feel free to ask questions in the comments or email me directly.

Notes:
CakePHP has a few requirements (http://book.cakephp.org/view/28/Requirements), which will work with pretty much any machine. In a nutshell, you need to configure Apache (enable mod_rewrite), PHP 5, and MySQL to get CakePHP going. CakePHP is flexible and compatible with both PHP 4 and PHP 5. Please use PHP 5. Please? Thank you.

My favorite guide for installing Apache, PHP, and MySQL is contained in PHP Solutions by David Powers. I recommend purchasing this book if you are just learning how to program PHP. David Powers is a wonderful instructor, and the book does a marvelous job of teaching new programmers PHP. Other more simple solutions include MAMP (mac) and PHP on Windows for Windows users. I am assuming Linux users can get LAMP going and don’t need advice :D

Depending on your configuration, you might need to add RewriteBase /path/to/your/cake/files/ to each of your .htaccess files to get CakePHP url rewriting to work properly. If you give up on getting this working, you can open app > config > core.php and uncomment line #57 //Configure::write(‘App.baseUrl’, env(‘SCRIPT_NAME’));. You must also delete all .htaccess files to not use mod_rewrite.