= Sluggable Behavior = The `sluggable` behavior allows a model to offer a human readable identifier that can be used for search engine friendly URLs. == Basic Usage == In the `schema.xml`, use the `` tag to add the `sluggable` behavior to a table: {{{ #!xml
}}} Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has an additional getter for its slug, which is automatically set before the object is saved: {{{ #!php setTitle('Hello, World!'); $p1->save(); echo $p1->getSlug(); // 'hello-world' }}} By default, the behavior uses the string representation of the object to build the slug. In the example above, the `title` column is defined as `primaryString`, so the slug uses this column as a base string. The string is then cleaned up in order to allow it to appear in a URL. In the process, blanks and special characters are replaced by a dash, and the string is lowercased. '''Tip''': The slug is unique by design. That means that if you create a new object and that the behavior calculates a slug that already exists, the string is modified to be unique: {{{ #!php setTitle('Hello, World!'); $p2->save(); echo $p2->getSlug(); // 'hello-world-1' }}} The generated model query offers a `findOneBySlug()` method to easily retrieve a model object based on its slug: {{{ #!php findOneBySlug('hello-world'); }}} == Parameters == By default, the behavior adds one columns to the model. If this column is already described in the schema, the behavior detects it and doesn't add it a second time. The behavior parameters allow you to use custom patterns for the slug composition. The following schema illustrates a complete customization of the behavior: {{{ #!xml
}}} Whatever `slug_column` name you choose, the `sluggable` behavior always adds the following proxy methods, which are mapped to the correct column: {{{ #!php getSlug(); // returns $post->url $post->setSlug($slug); // $post->url = $slug }}} The `slug_pattern` parameter is the rule used to build the raw slug based on the object properties. Any substring enclosed between brackets '{}' is turned into a getter, so the `Post` class generates slugs as follows: {{{ #!php getTitle(); } }}} Incidentally, that means that you can use names that don't match a real column phpName, as long as your model provides a getter for it. The `replace_pattern` parameter is a regular expression that shows all the characters that will end up replaced by the `replacement` parameter. In the above example, special characters like '!' or ':' are replaced by '-', but not letters, digits, nor '/'. The `separator` parameter is the character that separates the slug from the incremental index added in case of non-unicity. Set as '/', it makes `Post` objects sharing the same title have the following slugs: {{{ 'posts/hello-world' 'posts/hello-world/1' 'posts/hello-world/2' ... }}} A `permanent` slug is not automatically updated when the fields that constitute it change. This is useful when the slug serves as a permalink, that should work even when the model object properties change. Note that you can still manually change the slug in a model using the `permanent` setting by calling `setSlug()`; == Further Customization == The slug is generated by the object when it is saved, via the `createSlug()` method. This method does several operations on a simple string: {{{ #!php createRawSlug(); // truncate the slug to accomodate the size of the slug column $slug = $this->limitSlugSize($slug); // add an incremental index to make sure the slug is unique $slug = $this->makeSlugUnique($slug); return $slug; } protected function createRawSlug() { // here comes the string composition code, generated according to `slug_pattern` $slug = 'posts/' . $this->cleanupSlugPart($this->getTitle()); // cleanupSlugPart() cleans up the slug part // based on the `replace_pattern` and `replacement` parameters return $slug; } }}} You can override any of these methods in your model class, in order to implement a custom slug logic.