This post is the first of a series of small CakePHP tips and snippets that I'd like to share with fellow CakePHP developers reading this blog. Having been developing in CakePHP for almost a year now, I've found (as I'm sure you have too) that there are very few days that go by without discovering something new about the framework or without developing some reusable code to benefit the application and hopefully other CakePHP applications. Often even the smallest snippets are immensely useful, but they can easily go unshared.

The blogs of teknoid and cakebaker are examples of invaluable resources that provide these kinds of snippets and sample code to help others. Having been constantly aided by their writings and those of others in the community, I thought I'd try to give back what I can.

Today's tip is around making CakePHP's named parameters strongly defined and easier to use by having a method that processes them and ensures all mandatory ones exist and substitutes missing optional ones with default values. The idea around this is to make them behave more like function parameters that clearly define what they accept and what is optional. The solution below combines the strength of strongly defined parameters with prettier looking URLS.

First, to illustrate the problem we'll look at two URLs that add a new user.

	
// Non-named parameter URL
// The URL makes it hard to understand what each parameter is
/users/add/bruce+wayne/bruce%40example.com/Gotham+City
// However it can use the strongly defined function
function add($name, $email, $address = null) { ... }

// Named parameter URL
// Easier to read, parameters can be in any order or can can even be left out
/users/add/name:bruce+wayne/email:bruce%40example.com/address:Gotham+City
// Unfortunately though it has to use
function add() { ... }
	

So lets bring the power a strongly defined function has to named parameter URLs.

Here's the method to do it. Add it anywhere in app_controller.php

	
/**
 * Takes array of named params, compares them to mandatory and optional fields.
 * All mandatory must be present else returns false.
 * Any optional fields that aren't present will use the default value in the associative array.
 */
function extractNamedParams($mandatory, $optional = array()) {
	$params = $this->params['named'];

	// return false immediately if no params are passed in
	if(empty($params)) {
		return false;
	}

	// convert to named index array
	$mandatory = array_flip($mandatory);
	// define array with all keys to be present
	$all_named_keys = array_merge($mandatory, $optional);
	// extract valid keys from passed params
	$valid = array_intersect_key($params, $all_named_keys);
	// fill valid array with any missing optional params
	$output = array_merge($optional, $valid);
	// check that all keys are present in final output
	$diff = array_diff_key($all_named_keys, $output);

	if (empty($diff)) {
		return $output;
	} else {
		return false;
	}
}
	

You can now use the method at the top of any controller action.

	
$named = $this->extractNamedParams(
	array('name','email'), // mandatory
	array('address' => null) // optional
);
	

An example of the users/add action would be the following.

	
function add() {
	$named = $this->extractNamedParams(
		array('name','email'), // mandatory
		array('address' => null) // optional
	);

	if(!empty($this->data) || $named) {
		if($named) {
			$this->set('user_data', $named);
		} else {
			$this->set('user_data', $this->data['User']);
		}
	}
}
	

That's all there is to it.

By the way, I just started joining in on the CakePHP questions on StackOverflow and have found it to be a cool place for being part of the community - reading problems and solutions from people using the framework, as well as a great place to help others. Hopefully I'll see you around there too.