Getting Started With CakePHP


This week I’m starting to dip my toe into CakePHP, the framework we’ve chosen to use for our first PHP application. We liked it’s age/stability, large community, MVC nature, and the wealth of documentation for it. Following along with the Cake Cookbook, I was going to try it on my local system, but there was no windows binaries that I could find to install our version of PHP and newer versions seem to have some weird stuff going on (no longer installing as an Apache module?).  So working on our dev server instead, using my little test/learning site 🙂

My partner had already gotten Cake installed on that box, so I didn’t have to do any of that part. I still skimmed it to have some idea of how it worked though.  Of course, we’re using the set up that lets multiple apps share the core Cake code since we hosts all of our apps on the same server. I wasn’t sure how to do all the bake stuff, so I just opened the Cake install zip and copying the contents of the “app” folder to my test site.  After fixing some permissions and setting up the .htaccess and the www/index.php files, using my partner’s work on the new app as a guide, I was able to get the initial page to load. Yay!

When you first make a new CakePHP app and navigate to it, it gives you a useful status page about your installation and some more getting started info/links.  My status page had a few warnings to customize the cipher seed and the salt values, fix the tmp directory to be writable, set up my DB stuff, and suggested that I install the DebugKit. I like that the warnings give clear instructions on how to fix things – i.e. which files to find the config options you need to change, the folder that needed permission fixes, etc.  The Debug Kit was also very easy to install using its installation instructions.

With that done, yay, green!

Now I can start their tutorial, which walks you through building a basic blog with cake.  I’ll resist the urge to shudder at the DB creation stuff…following along (for now) to get the Cake stuff.  They do note they did some of the names and like on purpose, per their conventions (so pause to go read that). Following the conventions automate quite a few things, avoiding the need to do config files and the like.  I can see the benefit, for sure, but still glad the option to override exists.  For now, again, suppressing the shudders and back to the tutorial. 🙂

One thing they don’t note in their docs that I kind of wish they would, considering some of the oddities in other files, is that all their code samples presume you have <?php ?> in the file already, except for the ctp files.  Once I realized that, I was able to get the first tasks, a basic list of posts, working 😀

BTW, their debug info is very…colorful 🙂

After having me do a page showing a list of posts, it then has me pull up post details. On the whole straight forward, except it doesn’t explain why some of the items in the view have an h in front of them:

<h1><?php echo h($post['Post']['title']); ?></h1>

<p><small>Created: <?php echo $post['Post']['created']; ?></small></p>

<p><?php echo h($post['Post']['body']); ?></p>

See, the h($post… stuff? There are none in the first view it had me do.

<h1>Blog posts</h1>
<table>
	<tr>
		<th>Id</th>
		<th>Title</th>
		<th>Created</th>
	</tr>

	<!-- Here is where we loop through our $posts array, printing out post info -->

	<?php foreach ($posts as $post): ?>
	<tr>
		<td><?php echo $post['Post']['id']; ?></td>
		<td>
			<?php echo $this->Html->link($post['Post']['title'],
array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>
		</td>
		<td><?php echo $post['Post']['created']; ?></td>
	</tr>
	<?php endforeach; ?>
	<?php unset($post); ?>
</table>

What is that h? What does it mean?  Nothing even references it in the section of code at all…Google to the rescue!  Apparently h() is a Cake specific wrapper as a short form of htmlspecialchars, so you don’t have to write it all out.  Okay then.

BTW, I should note that at this point, I’ve not written a single SQL statement or even close. Getting the list of all posts or the details of an individual posts was all done automagically by CakePHP based on the use of the find and findbyid methods, which are automatically generated for controllers that extend AppController.  Be interesting to see how that will work for search functions, but that comes later. 🙂  One thing seems certain, though – learning Cake is really learning a lot of its built in methods. 

So far, there has been little room for really doing anything creative or coding your own stuff, just call this to do this. Even for the add function added to the Controller, no real major thing, just call more Cake methods.

<?php
class PostsController extends AppController {
	public $helpers = array('Html', 'Form', 'Session');
	public $components = array('Session');

	public function index() {
		$this->set('posts', $this->Post->find('all'));
	}
	
	public function view($id = null) {
		if (!$id) {
			throw new NotFoundException(__('Invalid post'));
		}

		$post = $this->Post->findById($id);
		if (!$post) {
			throw new NotFoundException(__('Invalid post'));
		}
		$this->set('post', $post);
	}
	
	public function add() {
		if ($this->request->is('post')) {
			$this->Post->create();
			if ($this->Post->save($this->request->data)) {
				$this->Session->setFlash(__('Your post has been saved.'));
				return $this->redirect(array('action' => 'index'));
			}
			$this->Session->setFlash(__('Unable to add your post.'));
		}
	}
}
?>

It even automatically does any data validation when calling the save function.  I guess it enables faster development, but then its’ like…so what am I needed for again? 😛 From the docs: “CakePHP goes a long way toward taking the monotony out of form input validation. Everyone hates coding up endless forms and their validation routines” – clearly they have not met any control freak developers LOL

So then the add post view…

<h1>Add Post</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->end('Save Post');
?>

Oh come on…you don’t even code the form??  Nope, you just call yet more helper functions. And you define the validation rules in your model, similar to how the dataValidation plug-in in jQuery works. It is customizable, which is good because even with a robust system, sometimes you just have weird business rules to implement.

The editing works in a similar manner, though the function is a litlte more involved as it includes making sure it’s a valid post first.

public function edit($id = null) {
	if (!$id) {
		throw new NotFoundException(__('Invalid post'));
	}

	$post = $this->Post->findById($id);
	if (!$post) {
		throw new NotFoundException(__('Invalid post'));
	}

	if ($this->request->is(array('post', 'put'))) {
		$this->Post->id = $id;
		if ($this->Post->save($this->request->data)) {
			$this->Session->setFlash(__('Your post has been updated.'));
			return $this->redirect(array('action' => 'index'));
		}
		$this->Session->setFlash(__('Unable to update your post.'));
	}

	if (!$this->request->data) {
		$this->request->data = $post;
	}
}

For the delete action, they don’t have you make a view as it does it via Ajax (with a confirmation dialog).  Obviously not something you’d normally do in a public site, but for the purposes of learning its fine. It does, however, do all of the JS for you too, so you don’t even have to write that part either.  Anyway, the end display, for the “home” page ended up like this.

I did change the layout of the view a bit to more closely match something that would be our design style (separator between edit & delete links and said links being the last column). 

So most of that initial stuff was copy/paste from the tutorial, running, then trying to match code to what happened, and getting a general idea of what goes where for the basic elements of apps. Going by what I learned today, so far it would seem like the appropriate “translation” of our CF/Mach-II apps to CakePHP would be along these lines.

If I’m understanding it all correctly, then Controllers are like Listeners & the Config File(s) in Mach-II, the Model takes the place of the Service Layer, the DAO, and the bean, and then views are similar.  Also, while technically a Mach-II app is framework independent once you hit the service layer (i.e. you can take out Mach-II and pop on another framework with minimal code change to the service/DAO/bean), it seems that from the intense level of automation that a CakePHP app is a CakePHP app period.  Changing to another framework would be essentially a complete rewrite.

I’m still not sure how I feel about all the automation, but for now, I’ve gotten started with it, so yay.  And if any of my presumptions/conclusions are off, by all means, let me know!