# Sluggable behavior extension for Doctrine 2
**Sluggable** behavior will build the slug of predefined fields on a given field
which should store the slug
Features:
- Automatic predifined field transformation into slug
- ORM and ODM support using same listener
- Slugs can be unique and styled
- Can be nested with other behaviors
- Annotation, Yaml and Xml mapping support for extensions
- Multiple slugs, diferent slugs can link to same fields
[blog_reference]: http://gediminasm.org/article/sluggable-behavior-extension-for-doctrine-2 "Sluggable extension for Doctrine 2 makes automatic record field transformations into url friendly names"
[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
Update **2012-02-26**
- Remove slug handlers were removed because of complications it brought together
Update **2011-09-11**
- Refactored sluggable for doctrine2.2 by specifieng slug fields directly in slug annotation
- Slug handler functionality, possibility to create custom ones or use built-in
tree path handler or linked slug through single valued association
- Updated documentation mapping examples for 2.1.x version or higher
Update **2011-04-04**
- Made single listener, one instance can be used for any object manager and any number of them
Update **2010-12-23**
- Full support for unique index on slug field,
no more exceptions during concurrent flushes.
**Note:**
- There is a reported [issue](https://github.com/l3pp4rd/DoctrineExtensions/issues/254) that sluggable transliterator
does not work on OSX 10.6 its ok starting again from 10.7 version. To overcome the problem
you can use your [custom transliterator](#transliterator)
- You can [test live][blog_test] on this blog
- Public [Sluggable repository](http://github.com/l3pp4rd/DoctrineExtensions "Sluggable extension on Github") is available on github
- Last update date: **2012-02-26**
**Portability:**
- **Sluggable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
This article will cover the basic installation and functionality of **Sluggable**
behavior
Content:
- [Including](#including-extension) the extension
- Entity [example](#entity-mapping)
- Document [example](#document-mapping)
- [Yaml](#yaml-mapping) mapping example
- [Xml](#xml-mapping) mapping example
- Basic usage [examples](#basic-examples)
- Custom [transliterator](#transliterator)
- Advanced usage [examples](#advanced-examples)
- Using [slug handlers](#slug-handlers)
## Setup and autoloading
Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
on how to setup and use the extensions in most optimized way.
## Sluggable Entity example:
### Sluggable annotations:
- **@Gedmo\Mapping\Annotation\Slug** it will use this column to store **slug** generated
**fields** option must be specified, an array of field names to slug
**Note:** that Sluggable interface is not necessary, except in cases there
you need to identify entity as being Sluggable. The metadata is loaded only once then
cache is activated
**Note:** 2.0.x version of extensions used @Gedmo\Mapping\Annotation\Sluggable to identify
the field for slug
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
public function getSlug()
{
return $this->slug;
}
}
```
## Sluggable Document example:
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
public function getSlug()
{
return $this->slug;
}
}
```
## Yaml mapping example
Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
```
---
Entity\Article:
type: entity
table: articles
id:
id:
type: integer
generator:
strategy: AUTO
fields:
title:
type: string
length: 64
code:
type: string
length: 16
slug:
type: string
length: 128
gedmo:
slug:
separator: _
style: camel
fields:
- title
- code
indexes:
search_idx:
columns: slug
```
## Xml mapping example
**Note:** xml driver is not yet adapted for single slug mapping
``` xml
```
## Basic usage examples:
### To save **Article** and generate slug simply use:
``` php
setTitle('the title');
$article->setCode('my code');
$this->em->persist($article);
$this->em->flush();
echo $article->getSlug();
// prints: the-title-my-code
```
### Some other configuration options for **slug** annotation:
- **fields** (required, default=[]) - list of fields for slug
- **updatable** (optional, default=true) - **true** to update the slug on sluggable field changes, **false** - otherwise
- **unique** (optional, default=true) - **true** if slug should be unique and if identical it will be prefixed, **false** - otherwise
- **separator** (optional, default="-") - separator which will separate words in slug
- **style** (optional, default="default") - **"default"** all letters will be lowercase, **"camel"** - first word letter will be uppercase
### Example
``` php
setTitle('the title');
$article->setCode('my code');
$this->em->persist($article);
$this->em->flush();
echo $article->getSlug();
// prints: The_Title_My_Code
```
## Custom transliterator
To set your own custom transliterator, which would be used to generate the slug, use:
``` php
setTransliterator($callable);
// or use a closure
$callable = function($text, $separatorUsed, $objectBeingSlugged) {
// ...
return $transliteratedText;
};
$sluggableListener->setTransliterator($callable);
```
## Advanced examples:
### Regenerating slug
In case if you want the slug to regenerate itself based on sluggable fields.
Set the slug to **null** or empty string.
``` php
find('Entity\Something', $id);
$entity->setSlug('');
$em->persist($entity);
$em->flush();
```
### Setting the slug manually
Sometimes you might need to set it manually, etc if generated one does not look satisfying enough.
Sluggable will ensure uniqueness of the slug.
``` php
setSluggableField('won't be taken into account');
$entity->setSlug('the required slug, set manually');
$em->persist($entity);
$em->flush();
echo $entity->getSlug(); // outputs: "the-required-slug-set-manually"
```
### Using TranslationListener to translate our slug
If you want to attach **TranslationListener** also add it to EventManager after
the **SluggableListener**. It is important because slug must be generated first
before the creation of it`s translation.
``` php
addEventSubscriber($sluggableListener);
$translatableListener = new \Gedmo\Translatable\TranslationListener();
$translatableListener->setTranslatableLocale('en_us');
$evm->addEventSubscriber($translatableListener);
// now this event manager should be passed to entity manager constructor
```
And the Entity should look like:
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
public function getSlug()
{
return $this->slug;
}
public function getUniqueSlug()
{
return $this->uniqueSlug;
}
}
```
Now the generated slug will be translated by Translatable behavior
Any suggestions on improvements are very welcome