Simple Sluggable Behavior for CakePHP

November 18, 2009 by Adam · Leave a Comment 

For quite a while now pretty much the defacto standard for generating automagic slugs in CakePHP has been the Sluggable Behavior by Mariano Iglesias (mariano) in the Cake Bakery (http://bakery.cakephp.org/articles/view/sluggable-behavior). I’ve never quite gotten on with this behavior, it’s not that it doesn’t do what it says, it just seems like it uses a lot of code to do it, and I prefer all of my code to be as simple as possible.

I’ve been using my own Sluggable Behavior for a while, and today I found myself needing a little more customisation, I made a few changes and now it works in exactly the same way as Mariano Iglesias’s, but using less code (and CakePHP’s built in Inflector::slug). So here is my Sluggable Behavior.

<?php
class SluggableBehavior extends ModelBehavior {
/**
 * Defaults
 *
 * @var array
 * @access protected
 */
	var $_defaults = array(
		'seperator' => '-',
		'label' => 'title',
		'field' => 'slug',
		'extension' => '.html',
		'length' => 100,
		'overwrite' => false
	);
/**
 * Initiate Sluggable behavior
 *
 * @param object $Model instance of model
 * @param array $config array of configuration settings.
 * @return void
 * @access public
 */
    function setup(&$Model, $config = array()) {
        $settings = array_merge($this->_defaults, $config);
        $this->_settings[$Model->alias] = $settings;
	}
/**
 * Before save method. Called before all saves
 *
 * Overriden to transparently manage creating and populating the slug field
 *
 * @param AppModel $Model Model instance
 * @return boolean true to continue, false to abort the save
 * @access public
 */
	function beforeSave(&$Model) {
		extract($this->_settings[$Model->alias]);

		if(!empty($Model->data[$Model->alias][$Model->primaryKey]) && !$overwrite) {
			return true;
		}

		if(!is_array($label) && empty($Model->data[$Model->alias][$label])) {
			return false;
		}

		if(is_array($label)) {
			$slug = '';
			foreach($label as $key) {
				$slug .= ife(!empty($slug), ' ', '') . $Model->data[$Model->alias][$key];
			}
		} else {
			$slug = $Model->data[$Model->alias][$label];
		}

		$slug = Inflector::slug($slug, $seperator);
		$slug = low($slug);

		if(strlen($slug) > $length) {
			$slug = substr($slug, 0, $length-1);
		}

		if(!empty($extension)) {
			$slug = $slug . $extension;
		}

		$i = 1;
		while($Model->find('count', array('conditions' => array($Model->alias . '.' . $field => $slug))) != 0) {
			if (!preg_match ('/'.preg_quote($seperator).'{1}[0-9]+$/', $slug)) {
				if(!empty($extension)) {
					$slug = $slug . $seperator . ++$i . $extension;
				} else {
					$slug = $slug . $seperator . ++$i;
				}
			} else {
				$slug = preg_replace('/[0-9]+$/', ++$i, $slug);
			}
		}

		$Model->data[$Model->alias][$field] = $slug;

		return parent::beforeSave($Model);
	}
}
?>

Usage

	var $actsAs = array(
		'Sluggable' => array(
			'label' => 'name',
			'extension' => false
		)
	);

// or

	var $actsAs = array('Sluggable');

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks

Related posts:

  1. Simple “MVC” Javascript for CakePHP
  2. Integrating the Auth Component with a bespoke 3rd party Single Sign-On Service in CakePHP
  3. Easy Multi Page Forms (or Wizards) with CakePHP

About Adam
Adam is senior developer for Image+ Ltd in Coventry, England. He has been developing websites for over 10 years, and currently freelances through his own company, Votive Media. Follow him on twitter for more!

Comments are closed.