Fancy URLs with Inflector::slug
Motivated by my recent tweet i thought i share my method of replacing the old SluggableBehavior with core functions.
Sometimes we have more than one model that uses slugs. For example: Tags, Posts, Categories. That’s why i add the following to AppModel which allows me to call it on any model.
function slugify($text) {
return low(Inflector::slug($text, '-'));
}
But because i am lazy i just use one of the model callbacks to automate the “slugification(tm)”.
function beforeSave() {
if ($this->hasField('slug') && isset($this->data[$this->alias][$this->displayField])) {
$this->data[$this->alias]['slug'] = $this->slugify($this->data[$this->alias][$this->displayField]);
}
}
So on any model that has a “slug” field in the associated table we always slugify the displayField (usually “name”) and keep it fresh. Dead simple.


Thanks alot for this!
I didn’t realise it could be so automagic :)
However i did have to include a return true; in the beforeSave call.
Also extended it to test if a custom slug has been included!
Thanks again!
If the ’slug’ column is unique to your table, then you’ll need to do something more like the following (pseudoCode):
function slugify($text) {
$slug = low(Inflector::slug($text, ‘-’));
$slugs = $this->find(’all’, array(
‘fields’ => array(’slug’),
‘conditions’ => array(’slug LIKE’ => ‘%’ . $slug),
));
if ($slugs) {
$slugs = Set::extract($slugs, “/{$this->alias}/slug”);
// loop through $slugs while incrementing $i to see if current($slugs) === “$slug-$i”, returning the new value of $slug when they’re not equal.
} else {
return $slug;
}
}