3.4.5 Configuração de rotas (routes)
Rotas são funcionalidades que mapeiam URLs em ações do controller. Foi adicionado ao CakePHP para tornar URLs amigáveies mais configuráveis e flexíveis. Não é obrigatório o uso do mod_rewrite para usar rotas, mas usando-o fará sua barra de endereços muito mais limpa e arrumada.
Rotas no CakePHP 1.2 foi ampliada e pode ser muito mais poderosa.
3.4.5.1 Rota Padrão
Antes de você aprender sobre como configurar suas próprias rotas, você deveria saber que o CakePHP vem configurado com um conjunto de rotas padrão. A configuração padrão de rotas do CakePHP deixará as URLs mais bonitas para qualquer aplicação. Você pode acessar diretamente uma ação via URL colocando seu nome na requisição. Você pode também passar paramêtros para suas ações no controller usando a própria URL.
URL para a rota padrão:
http://example.com/controller/action/param1/param2/param3
URL para a rota padrão:http://example.com/controller/action/param1/param2/param3
A URL /noticias/ler mapeia para a ação ler() do controller Noticias (NoticiasController), e /produtos/verInformacoes mapeia para a ação view_informacoes() do controller Produto (ProdutosController). Se nenhuma ação é especificada na URL, a ação index() será chamada.
A rota padrão também permite passar parâmetros para as ações usando a URL. Uma requisição /noticias/ler/12 seria equivalente a chamar o método ler(12) no controller Noticias (NoticiasController), por exemplo.
3.4.5.2 Parâmetros nomeados
Uma novidade no CakePHP 1.2 é a possibilidade de usar parâmetros nomeados. Você pode nomear parâmetros e enviar seus valores usando a URL. Uma requisição /noticias/ler/titulo:primeira+noticia/categoria:esportes teria como resultado uma chamada a ação ler() do controller Noticias (NoticiasController). Nesta ação, você encontraria os valores dos parâmetros título e categoria dentro de $this->passedArgs['titulo'] e $this->passedArgs['categoria'] respectivamente.
Alguns exemplos para a rota padrão:
URL mapeadas para as ações dos controladores, usando rotas padrão:
URL: /monkeys/jump
Mapeado para: MonkeysController->jump();
URL: /products
Mapeado para: ProductsController->index();
URL: /tasks/view/45
Mapeado para: TasksController->view(45);
URL: /donations/view/recent/2001
Mapeado para: DonationsController->view('recent', '2001');
URL: /contents/view/chapter:models/section:associations
Mapeado para: ContentsController->view();
$this->passedArgs['chapter'] = 'models';
$this->passedArgs['section'] = 'associations';
URL mapeadas para as ações dos controladores, usando rotas padrão:URL: /monkeys/jumpMapeado para: MonkeysController->jump();URL: /productsMapeado para: ProductsController->index();URL: /tasks/view/45Mapeado para: TasksController->view(45);URL: /donations/view/recent/2001Mapeado para: DonationsController->view('recent', '2001');URL: /contents/view/chapter:models/section:associationsMapeado para: ContentsController->view();$this->passedArgs['chapter'] = 'models';$this->passedArgs['section'] = 'associations';
3.4.5.3 Defining Routes
Definindo suas próprias rotas permite você definir como sua aplicação irá responder a uma dada URL. Defina suas próprias rotas no arquivo /app/config/routes.php usando o método Router::connect().
O método connect() recebe três parâmetros: a URL que você deseja casar, o valor padrão para os elementos de rota, e regras de expressões regulares para ajudar a encontrar elementos na URL.
O formato básico para uma definição de rota é:
Router::connect(
'URL',
array('paramName' => 'defaultValue'),
array('paramName' => 'matchingRegex')
)
Router::connect('URL',array('paramName' => 'defaultValue'),array('paramName' => 'matchingRegex'))
The first parameter is used to tell the router what sort of URL you’re trying to control. The URL is a normal slash delimited string, but can also contain a wildcard (*) or custom route elements (URL elements prefixed with a colon). Using a wildcard tells the router what sorts of URLs you want to match, and specifying route elements allows you to gather parameters for your controller actions.
Once you’ve specified a URL, you use the last two parameters of connect() to tell CakePHP what to do with a request once it has been matched. The second parameter is an associative array. The keys of the array should be named after the route elements in the URL, or the default elements: :controller, :action, and :plugin. The values in the array are the default values for those keys. Let’s look at some basic examples before we start using the third parameter of connect().
Router::connect(
'/pages/*',
array('controller' => 'pages', 'action' => 'display')
);
Router::connect('/pages/*',array('controller' => 'pages', 'action' => 'display'));
This route is found in the routes.php file distributed with CakePHP (line 40). This route matches any URL starting with /pages/ and hands it to the display() method of the PagesController(); The request /pages/products would be mapped to PagesController->display(‘products’), for example.
Router::connect(
'/government',
array('controller' => 'products', 'action' => 'display', 5)
);
Router::connect('/government',array('controller' => 'products', 'action' => 'display', 5));
This second example shows how you can use the second parameter of connect() to define default parameters. If you built a site that features products for different categories of customers, you might consider creating a route. This allows you link to /government rather than /products/display/5.
For additional flexibility, you can specify custom route elements. Doing so gives you the power to define places in the URL where parameters for controller actions should lie. When a request is made, the values for these custom route elements are found in $this->params of the controller. This is different than named parameters are handled, so note the difference: named parameters (/controller/action/name:value) are found in $this->passedArgs, whereas custom route element data is found in $this->params. When you define a custom route element, you also need to specify a regular expression - this tells CakePHP how to know if the URL is correctly formed or not.
Router::connect(
'/:controller/:id',
array('action' => 'view'),
array('id' => '[0-9]+')
);
Router::connect('/:controller/:id',array('action' => 'view'),array('id' => '[0-9]+'));
This simple example illustrates how to create a quick way to view models from any controller by crafting a URL that looks like /controllername/id. The URL provided to connect() specifies two route elements: :controller and :id. The :controller element is a CakePHP default route element, so the router knows how to match and identify controller names in URLs. The :id element is a custom route element, and must be further clarified by specifying a matching regular expression in the third parameter of connect(). This tells CakePHP how to recognize the ID in the URL as opposed to something else, such as an action name.
Once this route has been defined, requesting /apples/5 is the same as requesting /apples/view/5. Both would call the view() method of the ApplesController. Inside the view() method, you would need to access the passed ID at $this->params[‘id’].
One more example, and you’ll be a routing pro.
Router::connect(
'/:controller/:year/:month/:day',
array('action' => 'index', 'day' => null),
array(
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])',
'day' => '(0[1-9]|[12][0-9]|3[01])'
)
);
Router::connect('/:controller/:year/:month/:day',array('action' => 'index', 'day' => null),array('year' => '[12][0-9]{3}','month' => '(0[1-9]|1[012])','day' => '(0[1-9]|[12][0-9]|3[01])'));
This is rather involved, but shows how powerful routes can really become. The URL supplied has four route elements. The first is familiar to us: it’s a default route element that tells CakePHP to expect a controller name.
Next, we specify some default values. Regardless of the controller, we want the index() action to be called. We set the day parameter (the fourth element in the URL) to null to flag it as being optional.
Finally, we specify some regular expressions that will match years, months and days in numerical form.
Once defined, this route will match /articles/2007/02/01, /posts/2004/11/16, and /products/2001/05 (remember that the day parameter is optional?), handing the requests to the index() actions of their respective controllers, with the custom date parameters in $this->params.
3.4.5.4 Passing parameters to action
Assuming your action was defined like this and you want to access the arguments using $articleID instead of $this->params['id'], just add an extra array in the 3rd parameter of Router::connect().
// some_controller.php
function view($articleID = null, $slug = null) {
// some code here...
}
// routes.php
Router::connect(
// E.g. /blog/3-CakePHP_Rocks
'/blog/:id-:slug',
array('controller' => 'blog', 'action' => 'view'),
array(
// order matters since this will simply map ":id" to $articleID in your action
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
)
// some_controller.phpfunction view($articleID = null, $slug = null) {// some code here...}// routes.phpRouter::connect(// E.g. /blog/3-CakePHP_Rocks'/blog/:id-:slug',array('controller' => 'blog', 'action' => 'view'),array(// order matters since this will simply map ":id" to $articleID in your action'pass' => array('id', 'slug'),'id' => '[0-9]+'))
And now, thanks to the reverse routing capabilities, you can pass in the url array like below and Cake will know how to form the URL as defined in the routes.
// view.ctp
// this will return a link to /blog/3-CakePHP_Rocks
<?= $html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => Inflector::slug('CakePHP Rocks')
)) ?>
// view.ctp// this will return a link to /blog/3-CakePHP_Rocks<?= $html->link('CakePHP Rocks', array('controller' => 'blog','action' => 'view','id' => 3,'slug' => Inflector::slug('CakePHP Rocks'))) ?>
3.4.5.5 Prefix Routing
Many applications require an administration section where privileged users can make changes. This is often done through a special URL such as /admin/users/edit/5. In CakePHP, admin routing can be enabled from within the core configuration file by setting the admin path for Routing.admin.
Configure::write('Routing.admin', 'admin'); Configure::write('Routing.admin', 'admin');
In your controller, any action with an admin_ prefix will be called. Using our users example, accessing the url /admin/users/edit/5 would call the method admin_edit of our UsersController passing 5 as the first parameter.
You can map the url /admin to your admin_index action of pages controller using following route
Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true)); Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true));
You can use the Router to use custom prefixes for uses beyond admin routing, too.
Router::connect('/profiles/:controller/:action', array('prefix' => 'profiles', 'profiles' => true)); Router::connect('/profiles/:controller/:action', array('prefix' => 'profiles', 'profiles' => true));
Any calls to the profiles section would look for the profiles_ prefix on the method calls. Our users example would have a URL structure that looks like /profiles/users/edit/5 would call the profiles_edit method within the UsersController. Also important to remember, using the HTML helper to build your links will help maintain the prefix calls. Here's an example link being built using the HTML helper:
echo $html->link('Edit your profile', array('controller' => 'users', 'action' => 'profiles_edit', 'profiles' => true)); echo $html->link('Edit your profile', array('controller' => 'users', 'action' => 'profiles_edit', 'profiles' => true));
You can set up multiple prefixed routes using this approach to create a flexible URL structure for your application.
