Otimizando as URL’s na hora de migrar um site em PHP para CakePHP

Olá pessoal,

nestes dias fui chamado para fazer um refactory de um dos primeiros sites que desenvolvi. Na época eu não me preocupava com URL's amigáveis nem coisa semelhante. Para ser sincero, nem sabia do que se tratava.

O site havia sido desenvolvido inteiramente usando chamadas diretas para os scripts PHP, como por exemplo: noticias_ler.php?id=id_da_noticia.

Como uma das características que seriam agragadas a nova versão do site seria a otimização e uso de URL amigáveis, eu não poderia deixar do jeito que estava. Aliás, eu usaria o CakePHP no projeto, então, sem chances de manter como estava.

A primeira coisa eu me veio a cabeça foi mudar pra CakePHP. Não pensei nas consequências disso. Refletindo um pouco mais, vi que uma mudança radical em todas as URL's do site poderia não ser uma coisa bacana, já que o mesmo já contava com mais de 40.000 notícias dentre outros conteúdos. Já que todos os links antigos deixariam de funcionar. Isso não seria uma boa para motores de busca, nem mesmo para quem colocou uma determinada notícia no favoritos, por exemplo.

Logo, imaginei que eu teria que redirecionar todas as URL's (pelo menos as mais importantes) para o novo formato. Mas eu queria redirecionar algo como: noticia_ler.php?id=10 para /noticias/ler/10/titulo-da-noticia-bonito.

A primeira coisa que fiz foi rotear no routes.php a URL noticia_ler.php para um controller qualquer (ou para o controller Noticias). No exemplo a seguir, redirecionei para o controler redireciona.

PHP:
  1. Router::connect('/noticia_ler.php*', array('controller' => 'redireciona', 'action' => 'noticia'));

O controller Redireciona na verdade não precisaria nem existir, poderia ter feito dentro do próprio noticias. Mas a minha idéia era contralar todos os redirects de um único controller.

Na action noticia do controller Redireciona:

PHP:
  1. $id = $this->params["url"]["id"];
  2. $n = $this->Noticia->findById($id);
  3. $slug = Inflector::slug($n["Noticia"]["titulo"]); // retira acentos e etc
  4. $slug = strtolower($slug); // passa pra minusculo
  5. $slug = str_replace("_", "-", $slug); // troca _ por -
  6. $this->redirect("/noticias/ler/".$id."/".$slug, 301, true);

Detalhe do uso do método slug da classe Inflector, que retira todos os caracteres especiais e espaços para a construção de URL's amigáveis, transformando, por exemplo, "Tulio Faria" em "Tulio_Faria". Em seguida faço algumas transformações para ficar no formato que gosto: "tulio-faria", tudo minúsculo e separado por hífem.

O segundo paramêtro do redirect é o código de redirecionamento a ser usado, no caso do 301 é Movido Permanentemente. O terceiro paramêtro indica que será dado um exit() após o redirecionamento.

Bom pessoal, é isso!

Espero que isso ajude-os assim como me ajudou! Qualquer dúvida, comentem!

Forte abraço!

Comentários (7)

O que um framework NÃO é

Olá pessoal,

sempre deparo com pessoas me perguntando se devem usar o CakePHP ou não... Ou qual a vantagem de usar o CakePHP ao invés do Wordpress ou Joomla (pergunta estranha né).  Tentando esclarecer ainda mais o que é um framework, resolvi escrever o queum framework não é. Vou criar uma lista e explicar o porquê.

  1. Um framework não é um CMS: um framework como o CakePHP não é um CMS, ou seja, ele não gerencia o conteúdo de seu site. Mas nada o impede de criar fazendo uso de um framework.
  2. Um framework não é incompatível com AJAX: se você quer usar esta sigla bonita em seus projetos, um framework não irá te atrapalhar, aliás, em alguns casos, como no CakePHP, ele lhe fornece alguns helpers para trabalhar de forma mais simples com AJAX. Mas se não oferecesse, você poderia escrever seus arquivos JavaScripts na mão e ser feliz da mesma forma, não sendo assim um fator limitante.
  3.  Um framework não te engessa: se você entendeu todos os conceitos e a base de como funciona seu framework preferido, ele não deverá te engessar, pois, sempre você conseguirá criar o que deseja. É claro que se você tentar usar um framework para desenvolvimento web para criar um aplicativo desktop, não vai dar certo.
  4. Um framework não é fácil de aprender: um framework não é simples de aprender e de usar sem o mínimo de entendimento de OOP ou Programação Orientada a Objetos além da arquitetura que o mesmo utiliza. No caso do CakePHP, se você não conhece OOP não saberá a vantagem de criar e usar/não saberá criar e usar, por exemplo, components e helper. Ou o que você poderá fazer usando o app_controller / app_model, uma vez que todos os controllers e models são filhos deles. A arquitetura também lhe ajudará a entender onde colocar o que. Ou seja, quem é o tal model, view e controller e o que colocar dentro de cada um deles.
  5. Um framework não faz mágica sozinho: o framework não sabe se você quer ordenar de forma ascendente ou descendente, a menos que você diga a ele. Lembre-se, um framework te ajuda a manter o código organizado e fornecendo algumas facilidades genéricas, permitindo que você desenvolva cada vez mais rápido.

Bom pessoal, essas são algumas das coisas que vi muita gente confundindo. Caso alguém saiba de mais um fato, comente!

Forte abraço e até a próxima!

Comentários (5)

URL amigáveis em sites multi-idiomas no CakePHP

Olá pessoal,

este post é sobre algumas idéias sobre como organizar as URL's em site multi-idiomas, mais especificamente no nome dos controllers. Não sou dono da verdade, então, comentem dizendo o que vocês acham.

Esta semana me deparei com um problema em um site com versões em inglês e português. A URL em português ficava:

/produtos/informacoes/1/nome-do-produto

Isso sempre funcionou para mim, pois faz sentido para mim otimizar e ligar termo produtos, informacoes e o nome-do-produto na mesma URL. Mas o que acontece quando o site estava em inglês? Simplesmente a URL ficava:

/produtos/informacoes/1/product-name

Ou seja, estaria produtos, informacoes com a nome do produto em inglês na URL. Fato que me deixou encabulado, por misturar português e inglês.

Resolvi fazer um pouco diferente. Ao invés de usar o nome do controller como produtos, resolvi usar apenas p e deixei o nome da action como i.

/p/i/1/nome-do-produto

Ou melhor:

/p/i/produto/informacoes/1/nome-do-produto

Sendo que os dois primeiros paramêtros da action, eu simplesmente ignoro e mudo de acordo com o idioma. Em inglê ficaria:

/p/i/product/details/1/product-name

E eu sempre mantenho o id (no caso dos exemplos 1) em todas as URL's.

Levando em consideração as boas práticas de programação não é recomendável usar como nome para uma classe P e de um método (action) como i, mas para SEO creio que resolve.

O que vocês acham?

Forte abraço!

Comentários (7)

CakePHP 1.2 - generateList agora é find(”list”)

Olá pessoal,

esta é uma dica rápida. O antigo Model->generateList agora virou find("list"), sendo que o seu uso foi simplificado ainda mais.

Agora basta adicionar o atributo $displayField no model com o nome do campo que será mostrado em uma lista desses valores. Se tivessemos um model Estado (id, nome e abrev) com todos os estados brasileiros e decidimos mostrar o campo nome, bastaria no model:

PHP:
  1. class Estado extends AppModel{
  2.  
  3. var $name = "Estado";
  4.  
  5. var $displayField = "nome";
  6.  
  7. }

E no controller:

PHP:
  1. $this->set("estados", $this->Estado->find("list"));

Simples não?

Até a próxima pessoal!

Comentários (10)

CakePHP 1.2: Corrigindo erro estranho na Dreamhost

Olá pessoal,

a medida que passei a usar mais o CakePHP 1.2, passei a me deparar com mais problemas. (Não são muitos. Mas alguns são bem chatos.)

Estava instalando um novo site na Dreamhost, quando me deparei com o seguinte erro:

Missing Controller

Error: InternalError.htmlController could not be found.

Error: Create the class InternalError.htmlController below in file: app/controllers/internal_error.html_controller.php

<?php
class InternalError.htmlController extends AppController {

	var $name = 'InternalError.html';
}
?>

Notice: If you want to customize this error message, create app/views/errors/missing_controller.ctp

Percebam que nem mesmo o nome deste controlle solicitado é coerente. Depois de muito ajeitar o routes sem muito sucesso, acabei descobrindo na lista oficial que deveria trocar a conta para PHP 4. Não entendi o porquê do erro, mas felizmente a Dreamhost me permitiu fazer isso!

Abraços e espero que ninguém passe por isso em um servidor de hospedagem que não dá a mesma liberdade que a DH!

Comentários (7)

CakePHP 1.2: carregando model, controller e component dinâmicamente

Olá pessoal,

continuando a série de posts sobre o CakePHP 1.2 e das mudanças que ele trouxe, neste post irei falar como carregar dinâmicamente model', controller's e component's.

No Cake 1.1, era comum usármos:

PHP:
  1. loadModel("nomeDoModel");
  2. loadComponent("nomeDoComponent");
  3. loadControllers("nomeDoController");

No Cake 1.2 todos os esses loads viraram App::import, que seria usado assim:

PHP:
  1. App::import("Model", "nomeDoModel");
  2. App::import("Component", "nomeDoComponent");
  3. App::import("Controller", "nomeDoController");

O Cake 1.2 está se tornando OO de verdade.

Abraços pessoal e até a próxima!

Comentários (12)

CakePHP 1.2 - Named params

Olá pessoal,

um recurso bem interessante do CakePHP 1.2 é o chamado named params, ou parâmetros nomeados, que consiste em enviar informações pela URL mas sem precisar ter uma "ordem" para isso.

Por exemplo:
www.dominio.net/controller/método/nome:Tulio/cidade:Pouso Alegre/

Assim podemos recuperar estes valores dentro do controller usando o seu nome e não mais dependendo da posição que ela está na URL.

Todos os parâmetros nomeados chegam ao controller dentro de $this->params["named"], neste exemplo acima, teriamos $this->params["named"]["nome"] e $this->params["named"]["cidade"].

Vale lembrar que como o parâmetro nomeado pode ou não vir na URL, devemos verificar sua existência com isset antes de usá-lo.

Até a próxima pessoal, qualquer dúvida, comentem!

Comentários (5)

CakePHP 1.2 - Salvando registros

Olá pessoal,

atendendo a pedidos e aproveitando que por se tratar de um assunto interessante, vou falar sobre a inserção e atualização de dados no CakePHP 1.2.

A primeira mudança que encontramos é a inclusão do método set para o model, assim antes de salvarmos, validarmos e etc, devemos definir os dados usando o mesmo.

Como todos sabem o Cake usa um único método para criar e atualizar registros (o método save). Mas como diferenciar um do outro? Com o ID :) Se nos dados passados (setados) houver o id, será efetuado um update, senão um insert. Simples, não?

Exemplo:

PHP:
  1. $dados = array("Usuario"=>
  2. "id"=>1,
  3. "nome"=>"Tulio Faria"
  4. )
  5. );
  6.  
  7. $this->Usuario->set($dados);
  8. $this->Usuario->save();

Como em $dados tem o id (chave primária), neste caso, seria feito um update setando o nome para "Tulio Faria" do Usuario de id = 1.

Para fazermos o insert, bastaria tirar o id de dados.

Para atualizar um único campo, podemos usar um outro método, o saveField.

PHP:
  1. $this->Usuario->id = 1;
  2. $this->Usuario->saveField("nome", "Tulio Faria");

Neste caso, faria o mesmo efeito do exemplo do save, atualizando o nome para "Tulio Faria" para o Usuario de id = 1.

Bom é isso pessoal, qualquer dúvida comentem!

Abraços,

Comentários (13)

CakePHP 1.2: helper para paginação, simples, rápido e indolor

Olá pessoal,

eu venho usando o CakePHP 1.2 nos meus projetos recentes, e confesso que o quer já era bom ficou muitíssimo melhor.

Uma das novas características incorporadas ao core do CakePHP 1.2 é o helper para paginação e que salvou minha pele em um projeto, onde do dia para noite 10 registros viraram 6000, e resolvido com uma paginação em menos de 2 minutos.

Para usá-lo, começamos definindo os parâmetros da paginação, que pode ser feito de modo genérico para todos os models usados do controller (código aplicado no controller que terá paginação):

PHP:
  1. var $paginate = array('limit' => 50);

Neste caso definimos o tamanho da página de registros com o tamanho 50. Podemos ainda, adicionar conditions, fields, order, page e recursive, assim como é feito no findAll de um model.

Essa configuração será usada para todos os models deste controller. Se quisermos configurações diferentes para models diferentes, usaríamos:

PHP:
  1. var $paginate = array(
  2.  
  3. 'Model1'=> array('limit' => 50),
  4.  
  5. 'Model2'=> array('limit' => 20)
  6.  
  7. );

Depois de configurado, na hora de enviarmos os dados para o view, ao invés de usar findAll ou similares, usaremos:

PHP:
  1. $this->set("dados", $this->paginate("NomeDoModel"));

Pronto, agora só falta mostrar as páginas no view com:

PHP:
  1. Mostrando página: <?php echo $paginator->counter(array("separator"=>" de ")); ?>
  2.  
  3. ...
  4.  
  5. <?php echo $paginator->prev("Anterior"); ?>
  6.  
  7. <?php echo $paginator->numbers(); ?>
  8.  
  9. <?php echo $paginator->next("Próxima"); ?>

Depois disso é só testar e correr pro abraço :)

Bom pessoal, qualquer dúvida comentem! Abraços e até a próxima!

Comentários (24)

Vídeo: Palestra no CONISLI 2007

Olá pessoal,

depois de muita briga com softwares de edição de vídeo :) . Finalmente consegui editar o vídeo de minha apresentação sobre CakePHP no CONISLI 2007.

É minha primeira palestra, então me desculpem por qualquer falha :)

Assistir agora!

Se possível, comentem com suas opiniões.

Abraços,

Comentário (1)