Doctrine provides a stock Sluggable template behavior that can be applied to models, generating a slug based on one or more columns for a Doctrine_Record instance.
In most cases it is best practice not to modify a slug after it is generated, since one or more external sources may be referencing a URL to the Doctrine_Record instance by the original slug. If the slug is modified, those URLs referencing the original slug will become broken. For this reason, Doctrine’s default behavior is to have the canUpdate option for the Sluggable template be set to false.
There may however be reason to override this disabled canUpdate behavior under certain conditions. Doctrine 1.2 does not seem to provide an easy way to access a specific Doctrine_Record_Listener and modify an option associated with that listener for a given Doctrine_Record instance. Assuming there is only a single instance of any given listener associated with a Doctrine_Record, it’s fairly straightforward to find the desired listener within the Doctrine_Record_Listener_Chain. Applying this search conditionally to a Doctrine_Record::preUpdate() hook would look something like is shown below.
// In your Doctrine_Record class
public function preUpdate($event){
if (true) { // Conditions to check against for whether or not to allow the slug to be modified go here
try {
SomeUtilityClass::getListener($event->getInvoker()->getListener(), 'Sluggable')->setOption('canUpdate', true);
} catch (Exception $e) {
// Silently fail
}
}
}
// In SomeUtilityClass
class SomeUtilityClass {
static public function getListener(Doctrine_Record_Listener_Chain $chain, $search) {
$i = 0;
do {
if ($chain[$i] == null) {
throw new InvalidArgumentException('The requested Doctrine_Record_Listener is not associated with this Doctrine_Record instance');
}
if (get_class($chain[$i]) === sprintf('Doctrine_Template_Listener_%s', $search)) {
return $chain[$i];
}
} while (++$i);
}
}
The above getListener() method is required since it appears the only access to Doctrine_Record_Listener is via an implementation of PHP’s predefined ArrayAccess interface. Since the Doctrine_Record_Listener_Chain class only implements the set() and get() methods from the ArrayAccess interface, the only way to access the listeners is via their automatically assigned numeric keys. There is no way to directly request a specific listener by name through the Doctrine 1.2 API, thus the necessity for the do...while loop.