Created
April 5, 2011 01:21
-
-
Save meotimdihia/902833 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Copyright 2007-2010, Cake Development Corporation (http://cakedc.com) | |
* | |
* Licensed under The MIT License | |
* Redistributions of files must retain the above copyright notice. | |
* | |
* @copyright Copyright 2007-2010, Cake Development Corporation (http://cakedc.com) | |
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
*/ | |
/** | |
* Utils Plugin | |
* | |
* Utils Tiny Sluggable Behavior | |
* | |
* @package utils | |
* @subpackage utils.models.behaviors | |
*/ | |
class TinySluggableBehavior extends ModelBehavior { | |
/** | |
* Settings to configure the behavior | |
* | |
* @var array | |
*/ | |
public $settings = array(); | |
/** | |
* Default settings | |
* | |
* @var array | |
*/ | |
protected $_defaults = array( | |
'tinySlug' => 'tiny_slug', | |
'codeset' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', | |
'order' => 'created' | |
); | |
/** | |
* Initiate behavior - The Model must have a field for the tiny_slug along with a "created" field | |
* | |
* @param object $Model | |
* @param array $settings Settings for the behavior. Keys: | |
* - tinySlug: name of the tiny slug field in the table [default: tiny_slug] | |
* - codeset: valid characters for tiny slug [default: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ] | |
*/ | |
public function setup(&$Model, $settings = array()) { | |
$this->settings[$Model->alias] = array_merge($this->_defaults, $settings); | |
$Model->tinySlug = $this->settings[$Model->alias]['tinySlug']; | |
$this->settings[$Model->alias]['base'] = strlen($this->settings[$Model->alias]['codeset']); | |
} | |
/** | |
* beforeSave callback | |
* | |
* @param object $Model | |
*/ | |
public function beforeSave(&$Model) { | |
if (empty($Model->data[$Model->alias])) { | |
return; | |
} | |
if (empty($Model->data[$Model->alias][$Model->tinySlug])) { | |
$Model->data[$Model->alias][$Model->tinySlug] = $this->__getNextSlug($Model); | |
} | |
return true; | |
} | |
/** | |
* Calculates the next available slug and returns it | |
* | |
* @return string next avalible tiny slug | |
*/ | |
private function __getNextSlug(&$Model) { | |
$new = ''; | |
$prev = $Model->find('first', array( | |
'contain' => array(), | |
'fields' => array("{$Model->alias}.{$Model->tinySlug}", "{$Model->alias}." . $this->settings[$Model->alias]['order']), | |
'order' => "{$Model->alias}.{$this->settings[$Model->alias]['order']} DESC")); | |
if (empty($prev)) { | |
$new = $this->settings[$Model->alias]['codeset'][0]; | |
} else { | |
$new = $this->__toShort($Model, (string) $this->__toDecimal($Model, $prev[$Model->alias][$Model->tinySlug]) + 1); | |
$attempts = 0; | |
$maxAttempts = 5; // Overriden after the first attempt | |
$new = $prev[$Model->alias][$Model->tinySlug]; | |
// Check if this slug does not already exists | |
do { | |
if ($attempts == 1) { | |
$maxAttempts = $Model->find('count', array( | |
'conditions' => array( | |
$Model->alias . '.' . $this->settings[$Model->alias]['order'] => $prev[$Model->alias][$this->settings[$Model->alias]['order']]))); | |
} | |
$new = $this->__toShort($Model, $this->__toDecimal($Model, $new) + 1); | |
$existing = $Model->find('count', array( | |
'conditions' => array( | |
$Model->alias . '.' . $Model->tinySlug => $new))); | |
$attempts++; | |
} while (!empty($existing) && $attempts < $maxAttempts); | |
} | |
return $new; | |
} | |
/** | |
* Calculates the | |
* | |
* @param int $decimal the decimal to convert | |
* @return string | |
*/ | |
private function __toShort(&$Model, $decimal) { | |
$codeSet = $this->settings[$Model->alias]['codeset']; | |
$base = $this->settings[$Model->alias]['base']; | |
$short = ''; | |
while ($decimal > 0) { | |
$short = substr($codeSet, ($decimal % $base), 1) . $short; | |
$decimal = floor($decimal / $base); | |
} | |
return $short; | |
} | |
/** | |
* Converts a tiny slug into an integer | |
* | |
* @param string $short | |
* @return integer | |
*/ | |
private function __toDecimal(&$Model, $short) { | |
$codeSet = $this->settings[$Model->alias]['codeset']; | |
$base = $this->settings[$Model->alias]['base']; | |
$decimal = 0; | |
for ($i = strlen($short); $i; $i--) { | |
$decimal += strpos($codeSet, substr($short, (-1 * ( $i - strlen($short) )), 1)) * pow($base, $i - 1); | |
} | |
return $decimal; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment