Urls usando ’slug’

Posted: December 18th, 2007 | Author: andre | Filed under: CakePHP | No Comments »

Vo mostrar aqui como utilizar urls em estilo slug como o wordpress. As razões de utilizar esse tipo de recurso é simples, as urls ficam mais apresentáeis e intuitivas e tornando-se mais atraentes. O precesso de adaptação é bem simples, utilizando mais um field ’slug’ na tabela do banco e usando esse campo ao invés do id para procura.

CREATE TABLE contents (  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,images_id INTEGER UNSIGNED NOT NULL,title VARCHAR(45) NULL,
 
slug VARCHAR(100) NULL,
 
text TEXT NULL,
 
created DATETIME NULL,
 
updated DATETIME NULL,
 
PRIMARY KEY(id),
 
UNIQUE INDEX contents_index1129(slug)
 
);

Com a table já pronta, podemos editar o controler. Para isso vamos mudar a function “view” do contents_controller.php.
A seguir o code original criado a partir do bake.php:

function view($id = null) {
if (!$id) {
$this->Session->setFlash('Invalid id for Content.');
$this->redirect('/contents/index');
}
$this->set('content', $this->Content->read(null, $id));
}

Agora a modificação, e então ocorre a mágica:

function view($slug = null) {
if (!$slug) {
$this->Session->setFlash('Invalid id for Content.');
$this->redirect('/contents/index');
}
$this->set('content', $this->Content->findBySlug(null, $slug));
}

Com o método ‘findBy’ vc escolhe qual campo vc deseja usar para a procura, no caso nosso campo ’slug’ da tabela.
Então para completar a mudança só é preciso agora alterar as views de modo que nos links seja indicado não a ID e sim o Slug da página requisitada:

...
<td class="actions">
<?php echo $html->link('View','/contents/view/' . $contents['Content']['slug'])?>
<?php echo $html->link('Edit','/contents/edit/' . $contents['Content']['slug'])?>
<?php echo $html->link('Delete','/contents/delete/' . $contents['Content']['slug'], null, 'Are you sure you want to delete id ' . $contents['Content']['slug'])?>
</td>
...

Agora uma última implementação, reparam que usamos na tabela a campo ’slug’ como UNIQUE, obviamente é necessário que essa entrada seja única no banco de dados para que duas páginas não tenham o mesmo ’slug’ perdendo assim a funcionalidade que mostramos aqui. Só é necessário alterar a function ‘add’ no próprio controller:

function add() {
if (empty($this->data)) {
$this->render();
} else {
$this->cleanUpFields();
 
/*aqui preencho o campo slug com o title + a data pra formar uma entrada unica */
 
$this->data['Content']['slug'] = $this->Common->title_slug($this->data['Content']['title'].'-'.date('Y-m-d H:i:s'));
 
if ($this->Content->save($this->data)) {
$this->Session->setFlash('The Content has been saved');
$this->redirect('/contents/index');
} else {
$this->Session->setFlash('Please correct errors below.');
}
}
}

Repare que foi utilizado um component ‘Common’ cujo codigo é disponibilizado a seguir, basta criar o arquivo /controllers/components/Common.php com ele e chama-lo usando “var $components = array(‘Common’);”.

 
class CommonComponent extends Object{
function title_slug( $title )
{
$slug = $title;
 
$bad = array( 'Š','Ž','š','ž','Ÿ','À','Á','Â','Ã','Ä','Å','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ñ',
'Ò','Ó','Ô','Õ','Ö','Ø','Ù','Ú','Û','Ü','Ý','à','á','â','ã','ä','å','ç','è','é','ê',
'ë','ì','í','î','ï','ñ','ò','ó','ô','õ','ö','ø','ù','ú','û','ü','ý','ÿ',
'Þ','þ','Ð','ð','ß','Œ','œ','Æ','æ','µ',
'"',"'",'“','"',"n","r",'_');
 
$good = array( 'S','Z','s','z','Y','A','A','A','A','A','A','C','E','E','E','E','I','I','I','I','N',
'O','O','O','O','O','O','U','U','U','U','Y','a','a','a','a','a','a','c','e','e','e',
'e','i','i','i','i','n','o','o','o','o','o','o','u','u','u','u','y','y',
'TH','th','DH','dh','ss','OE','oe','AE','ae','u',
'','','','','','','-');
 
// replace strange characters with alphanumeric equivalents
$slug = str_replace( $bad, $good, $slug );
 
$slug = trim($slug);
 
// remove any duplicate whitespace, and ensure all characters are alphanumeric
$bad_reg = array('/s+/','/[^A-Za-z0-9-]/');
$good_reg = array('-','');
$slug = preg_replace($bad_reg, $good_reg, $slug);
 
// and lowercase
$slug = strtolower($slug);
 
return $slug;
}
 
}