3.4.5 Configurazione del sistema di Routing
Il Routing é una caratteristica che permette di mappare gli URL in azioni dei controller. é inserita in CakePHP per rendere piú gradevoli, configurabili e flessibili gli URL. Non é necessario usare la funzione mod_rewrite di Apache, anche se sarebbe consigliato per rendere ancora piú gradevole la barra dell'indirizzo.
In CakePHP 1.2 il routing é stato potenziato e ora offre molte caratteristiche aggiuntive.
Prima di iniziare a configurare il routing, devi sapere che CakePHP ha delle impostazioni di default, che funzionano piuttosto bene nella maggior parte delle applicazioni. Puoi accedere a una azione direttamente dall'URL semplicemente scrivendo il suo nome. Puoi anche passarle dei parametri, sempre tramite l'URL.
Ecco come é composto il meccanismo di routing di default:
http://example.com/controller/action/param1/param2/param3
Ecco come é composto il meccanismo di routing di default:http://example.com/controller/action/param1/param2/param3
L'URL /posts/view richiama l'azione view() del controller PostsController, e /products/viewClearance richiama l'azione view_clearance() del controller ProductsController. Se l'URL non specifica una azione, viene richiamata automaticamente l'azione index().
Il setup di default permette anche di passare dei parametri alle tue azioni tramite l'URL. Per esempio, la richiesta di /posts/view/25 equivale al chiamare l'azione view(25) del PostsController.
Novitá: in CakePHP 1.2 si puó anche nominare i parametri. Puoi dare un nome ai parametri e inviare i rispettivi valori tramite URL. Per esempio la richiesta di /posts/view/title:first+post/category:general diviene una chiamata all'azione view() del PostsController. In questa azione puoi accedere ai valori dei parametri title e category tramite la notazione $this->passedArgs['title'] e $this->passedArgs['category'].
Ecco alcuni esempi per spiegare meglio.
URL alla azione del controller, mappata nel modo di default:
URL: /monkeys/jump
Richiama: MonkeysController->jump();
URL: /products
Richiama: ProductsController->index();
URL: /tasks/view/45
Richiama: TasksController->view(45);
URL: /donations/view/recent/2001
Richiama: DonationsController->view('recent', '2001');
URL: /contents/view/chapter:models/section:associations
Richiama: ContentsController->view();
$this->passedArgs['chapter'] = 'models';
$this->passedArgs['section'] = 'associations';
Definire le proprie regole di routing permette di controllare come l'applicazione risponderá a determinati URL. Le regole di routing si definiscono nel file /app/config/routes.php utilizzando il metodo Router::connect().
Il metodo connect() richiede tre parametri: l'URL che vuoi mappare, i valori di default per gli elementi personalizzati, e l'espressione regolare che permette di aiutare il router a comprendere quali URL sono validi.
Il formato di base per definire una regola di routing é:
Router::connect(
'URL',
array('nomeParametro' => 'valorePredefinito'),
array('nomeParametro' => 'espressioneRegolare')
)
Router::connect('URL',array('nomeParametro' => 'valorePredefinito'),array('nomeParametro' => 'espressioneRegolare'))
Il primo parametro è utilizzato per dire al router che tipo di URL deve controllare. L'URL é una normale stringa delimitata da slash, ma puó contenere anche un carattere qualsiasi (*) un un elemento personalizzato (gli elementi sono contraddistinti dall'uso dei due punti nell'URL). Quando usi un nome indichi al router a che tipo di URL fa riferimento, e specificando degli elementi puoi settare dei parametri dell'azione del controller.
Una volta specificato l'URL, si utilizzano gli ultimi due parametri del metodo connect() per indicare a CakePHP cosa fare quando la richiesta soddisfa la regola impostata. Il secondo parametro é un array associativo. Le chiavi dell'array possono essere richiamate dopo il primo elemento dell'URL, oppure puoi usare gli elementi di default: :controller, :action e :plugin. I valori delle chiavi sono i valori che imposti di default. Ecco qualche esempio su come si usa il secondo parametro del metodo connect().
Router::connect(
'/pages/*',
array('controller' => 'pages', 'action' => 'display')
);
Router::connect('/pages/*',array('controller' => 'pages', 'action' => 'display'));
Questa regola si trova alla linea 40 del file routes.php. Indica che tutti gli URL che iniziano con /pages/ richiamano la funzione display() del controller PagesController(); per esempio, la richiesta /pages/products richiama PagesController->display('products').
Router::connect(
'/government',
array('controller' => 'products', 'action' => 'display', 5)
);
Router::connect('/government',array('controller' => 'products', 'action' => 'display', 5));
In questo secondo esempio si vede come puoi usare il secondo parametro di connect() per definire dei valori di default. Se stai costruendo una sito che reggruppa i prodotti in diverse categorie di clienti, puoi considerare di creare una regola di routing. Questo ti permette di usare /government al posto di /products/display/5.
Per aggiungere flessibilitá puoi specificare degli elementi personalizzati. In questo modo puoi definire in che posizione dell'URL devono trovarsi determinati parametri. Quando viene effettuata una richiesta, i valori di ciascun elemento sono disponibili in $this->params all'interno del controller. Questo é un modo diverso da come sono trattati i parametri con un nome spiegati prima, infatti nota la differenza: i parametri con un nome (/controller/action/name:value) si rirovano in $this->passedArgs, mentre i valori degli elementi personalizzati delle regole di routing si trovano in $this->params. Quando definisci un elemento di routing personalizzato, puoi anche identificarlo con una espressione regolare, che indichi a CakePHP come riconoscere se l'URL é valido o no.
Router::connect(
'/:controller/:id',
array('action' => 'view'),
array('id' => '[0-9]+')
);
Router::connect('/:controller/:id',array('action' => 'view'),array('id' => '[0-9]+'));
Questo semplice esempio illustra come creare un modo rapido per visualizzare i modelli da tutti i controller, tramite un elegante URL come /controllername/id. L'URL descritto con connect() specifica due elementi: :controller e :id. L'elemento :controller é un elemento di default di CakePHP, quindi il router sa come funziona e quindi é in grado di identificare il nome del controller nell'URL. L'elemento :id é un elemento personalizzato, e deve essere definito tramite l'espressione regolare che si trova nel terzo parametro. In questo modo si indica a CakePHP come riconoscere l'ID nell'URL, piuttosto che qualcos'altro, come per esempio il nome di un'azione.
Quando hai definito questa regola, richiedendo /apples/5 ottieni lo stesso che richiedendo /apples/view/5. Ambedue le richieste richiamano il metodo view() del controller ApplesController. All'interno del metodo view(), puoi accedere al valore di ID tramite $this->params['id'].
Un altro esempio, da vero professionista.
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])'));
Stavolta é piuttosto complesso, ma questo indica quanto potente puó essere il sistema di routing. L'URL in questione ha quattro elementi. Il primo é ormai noto: é l'elemento standard che indica a CakePHP il nome del controller.
Poi specifichiamo alcuni valori. Indipendentemente dal controller, vogliamo richiamare l'azione index(). Impostiamo il parametro day (il quarto elemento nell'URL) a null per indicare che é opzionale.
Infine specifichiamo l'espressione regolare che identifica l'anno, i mesi e i giorni in formato numerico.
Alla fine questa regola valida richieste come /articles/2007/02/01, /posts/2004/11/16, e /products/2001/05 (il parametro day é opzionale, ricordi?), richiamando l'azione index() nei rispettivi controllers, con i parametri personalizzati della data, disponibili in $this->params.
3.4.5.1 Default Routing
There is no translation yet for this section. Please help out and translate this.. More information about translations
Before you learn about configuring your own routes, you should know that CakePHP comes configured with a default set of routes. CakePHP’s default routing will get you pretty far in any application. You can access an action directly via the URL by putting its name in the request. You can also pass parameters to your controller actions using the URL.
URL pattern default routes:
http://example.com/controller/action/param1/param2/param3
The URL /posts/view maps to the view() action of the PostsController, and /products/view_clearance maps to the viewClearance() action of the ProductsController. If no action is specified in the URL, the index() method is assumed.
The default routing setup also allows you to pass parameters to your actions using the URL. A request for /posts/view/25 would be equivalent to calling view(25) on the PostsController, for example.
3.4.5.2 Named parameters
There is no translation yet for this section. Please help out and translate this.. More information about translations
New in CakePHP 1.2 is the ability to use named parameters. You can name parameters and send their values using the URL. A request for /posts/view/title:first+post/category:general would result in a call to the view() action of the PostsController. In that action, you’d find the values of the title and category parameters inside $this->passedArgs[‘title’] and $this->passedArgs[‘category’] respectively.
Some summarizing examples for default routes might prove helpful.
URL to controller action mapping using default routes:
URL: /monkeys/jump
Mapping: MonkeysController->jump();
URL: /products
Mapping: ProductsController->index();
URL: /tasks/view/45
Mapping: TasksController->view(45);
URL: /donations/view/recent/2001
Mapping: DonationsController->view('recent', '2001');
URL: /contents/view/chapter:models/section:associations
Mapping: ContentsController->view();
$this->passedArgs['chapter'] = 'models';
$this->passedArgs['section'] = 'associations';
3.4.5.3 Defining Routes
There is no translation yet for this section. Please help out and translate this.. More information about translations
Defining your own routes allows you to define how your application will respond to a given URL. Define your own routes in the /app/config/routes.php file using the Router::connect() method.
The connect() method takes up to three parameters: the URL you wish to match, the default values for your route elements, and regular expression rules to help the router match elements in the URL.
The basic format for a route definition is:
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 route elements (variable names 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.
Another common use for the Router is to define an "alias" for a controller. Let's say that instead of accessing our regular URL at /users/someAction/5, we'd like to be able to access it by /cooks/someAction/5. The following route easily takes care of that:
Router::connect(
'/cooks/:action/*', array('controller' => 'users', 'action' => 'index')
);
Router::connect('/cooks/:action/*', array('controller' => 'users', 'action' => 'index'));
This is telling the Router that any url beginning with /cooks/ should be sent to the users controller.
When generating urls, routes are used too. Using array('controller' => 'users', 'action' => 'someAction', 5) as a url will output /cooks/someAction/5 if the above route is the first match found
If you are planning to use custom named arguments with your route, you have to make the router aware of it using the Router::connectNamed function. So if you want the above route to match urls like /cooks/someAction/type:chef we do:
Router::connectNamed(array('type'));
Router::connect(
'/cooks/:action/*', array('controller' => 'users', 'action' => 'index')
);
Router::connectNamed(array('type'));Router::connect('/cooks/:action/*', array('controller' => 'users', 'action' => 'index'));
You can specify your own 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 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. Note that parenthesis (grouping) are not supported in the regular expressions. You can still specify alternates, as above, but not grouped with parenthesis.
Once defined, this route will match /articles/2007/02/01, /posts/2004/11/16, and /products/2001/05 (as defined, the day parameter is optional as it has a default), handing the requests to the index() actions of their respective controllers, with the date parameters in $this->params.
3.4.5.4 Passing parameters to action
There is no translation yet for this section. Please help out and translate this.. More information about translations
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
<?php echo $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<?php echo $html->link('CakePHP Rocks', array('controller' => 'blog','action' => 'view','id' => 3,'slug' => Inflector::slug('CakePHP Rocks'))); ?>
3.4.5.5 Prefix Routing
There is no translation yet for this section. Please help out and translate this.. More information about translations
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. The view file used would be app/views/users/admin_edit.ctp
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 configure the Router to use multiple prefixes 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.
Wildcard prefix routing is available using the named element :prefix similar to :controller and :action. You can map the url /api/user/create to your user_create action of api controller using the following route
Router::connect('/api/:prefix/:action', array('controller' => 'api')); Router::connect('/api/:prefix/:action', array('controller' => 'api'));
Additionally you can map the url /api/question/create to your question_create action of api controller or /api/question/edit to your question_edit action of api controller.
Also important to remember, using the HTML helper to build your links will help maintain the prefix calls. Here's how to build this link using the HTML helper:
echo $html->link('Edit your profile', array('profiles' => true, 'controller' => 'users', 'action' => 'edit', 'id' => 5)); echo $html->link('Edit your profile', array('profiles' => true, 'controller' => 'users', 'action' => 'edit', 'id' => 5));
You can set up multiple prefixed routes using this approach to create a flexible URL structure for your application.
3.4.5.6 Plugin routing
There is no translation yet for this section. Please help out and translate this.. More information about translations
Plugin routing uses the plugin key. You can create links that point to a plugin by adding the plugin key to your url array.
echo $html->link('New todo', array('plugin' => 'todo', 'controller' => 'todo_items', 'action' => 'create'));
echo $html->link('New todo', array('plugin' => 'todo', 'controller' => 'todo_items', 'action' => 'create'));
Conversely if the active request is a plugin request and you want to create a link that has no plugin you can do the following.
echo $html->link('New todo', array('plugin' => null, 'controller' => 'users', 'action' => 'profile'));
echo $html->link('New todo', array('plugin' => null, 'controller' => 'users', 'action' => 'profile'));
By setting plugin => null you tell the Router that you want to create a link that is not part of a plugin.
3.4.5.7 File extensions
There is no translation yet for this section. Please help out and translate this.. More information about translations
To handle different file extensions with your routes, you need one extra line in your routes config file:
Router::parseExtensions('html', 'rss');
Router::parseExtensions('html', 'rss');
This will tell the router to remove any matching file extensions, and then parse what remains.
If you want to create a URL such as /page/title-of-page.html you would create your route as illustrated below:
Router::connect(
'/page/:title',
array('controller' => 'pages', 'action' => 'view'),
array(
'pass' => array('title')
)
);
Router::connect('/page/:title',array('controller' => 'pages', 'action' => 'view'),array('pass' => array('title')));
Then to create links which map back to the routes simply use:
$html->link('Link title', array('controller' => 'pages', 'action' => 'view', 'title' => Inflector::slug('text to slug', '-'), 'ext' => 'html'))
$html->link('Link title', array('controller' => 'pages', 'action' => 'view', 'title' => Inflector::slug('text to slug', '-'), 'ext' => 'html'))


























