El enrutamiento te provee de herramientas que permiten mapear URLs a acciones
de un controlador. Al definir rutas, puedes separar cómo está implementada tu
aplicación y cómo están estructuradas sus URLs.
El enrutamiento en CakePHP también abarca la idea de enrutamiento inverso, donde
una matriz de parámetros se puede transformar en una cadena URL. Al utilizar el
enrutamiento inverso, puedes refactorizar la estructura de tus URLs sin necesidad
de actualizar todo tu código.
Vistazo rápido
Esta sección te enseñará los usos más comunes del enrutamiento en CakePHP con
ejemplos. Normalmente, deseas mostrar algo como una página de destino, por lo que
tendrás que añadir esto a tu archivo config/routes.php:
/** @var \Cake\Routing\RouteBuilder $routes */
$routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
Esto ejecutará el método index que se encuentra en ArticlesController
cuando
se visite la página principal de tu sitio. A veces necesitas rutas dinámicas que
aceptarán múltiples parámetos, por ejemplo cuando necesites una ruta para ver
el contenido de un artículo:
$routes->connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']);
La ruta anterior aceptará cualquier URL que se parezca a /article/15
e invocará
el método view(15)
de ArticlesController
. Esto no prevendrá que las personas
intenten acceder a URLs como /articles/foobar
. Si quieres, puedes restringir
algunos parámetros que se ajusten a una expresión regular:
// Utilizando una interfaz fluida
$routes->connect(
'/articles/{id}',
['controller' => 'Articles', 'action' => 'view'],
)
->setPatterns(['id' => '\d+'])
->setPass(['id']);
// Utilizando una matriz de opciones
$routes->connect(
'/articles/{id}',
['controller' => 'Articles', 'action' => 'view'],
['id' => '\d+', 'pass' => ['id']]
);
En el ejemplo anterior se cambió el comparador asterisco por un nuevo marcador de
posición {id}
. Utilizar marcadores de posición nos permite valiadr partes de
la URL, en este caso utilizamos la expresión regular \d+
por lo que sólo los
dígitos son comparados. Finalmente, le indicamos al enrutador que trate el marcador
de posición id
como un argumento de función para el método view()
especificando la opción pass
.
Hablaremos más sobre el uso de esta opción más adelante.
El enrutador de CakePHP también puede revertir rutas de coincidencia. Esto quiere
decir que desde una matriz que contiene parámetros de coincidencia es capaz de generar
una cadena de URL:
use Cake\Routing\Router;
echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);
// Obtendrás como salida
/articles/15
Las rutas también pueden etiquetarse con un nombre único, esto te permite referenciarlas
rápidamente cuando creas enlaces en lugar de especificar cada uno de los parámetros de
la ruta:
// En routes.php
$routes->connect(
'/upgrade',
['controller' => 'Subscriptions', 'action' => 'create'],
['_name' => 'upgrade']
);
use Cake\Routing\Router;
echo Router::url(['_name' => 'upgrade']);
// Obtendrás como salida
/upgrade
Para ayudar a mantener tu código de enrutamiento DRY, el Enrutador tiene el concepto
de “ámbitos”.
Un ámbito define un segmento de ruta común y, opcionalmente, rutas predeterminadas.
Cualquier ruta conectada dentro de un ámbito heredará la ruta y valores por defecto
de su ámbito:
$routes->scope('/blog', ['plugin' => 'Blog'], function (RouteBuilder $routes) {
$routes->connect('/', ['controller' => 'Articles']);
});
La rua anterior coincidiría con /blog/
y la enviaría a
Blog\Controller\ArticlesController::index()
.
El esqueleto de la aplicación viene con algunas rutas de inicio. Una vez has añadido
tus tuyas propias, puedes eliminar las rutas por defecto si no las necesitas.
Conectando Rutas
Para mantener tu código DRY debes utilizar “ámbitos de ruta”. Los ámbitos
de ruta no sólo te facilitan mantener tu código DRY, sino que ayudan al Enrutador a
optimizar sus operaciones. Este método se aplica por defecto al ámbito /
. Para
crear un ámbito y conectar algunas rutas utilizarás el método scope()
:
// En config/routes.php
use Cake\Routing\RouteBuilder;
use Cake\Routing\Route\DashedRoute;
$routes->scope('/', function (RouteBuilder $routes) {
// Conecta las rutas alternativas genéricas.
$routes->fallbacks(DashedRoute::class);
});
El método connect()
acepta hasta tres parámetros: la plantilla de URL para la que
deseas conincidencias, los valores predeterminados para los elementos de tu ruta.
Las opciones frecuentemente incluyen reglas de expresión regular que para ayudar al
enrutador a coincidir con elementos de la URL.
El formato básico para la definición de una ruta es:
$routes->connect(
'/url/template',
['targetKey' => 'targetValue'],
['option' => 'matchingRegex']
);
El primer parámetro se utiliza para indicarle al enrutador qué tipo de URL se
está intentando controlar. La URL es una cadena normal delimitada por barras
diagonales, pero también puede contener un comodín (*) o Elementos de ruta.
El uso de un comodín le indica al enrutador que puede aceptar cualquier argumento
adicional que se le proporcione. Las rutas sin * sólo coincidirán con el patrón
de plantilla exacto proporcionado.
Una vez que hayas especificado una URL, utiliza los dos últimos parámetros de
connect()
para indicar a CakePHP qué debe hacer con la solicitud cuando
haya coincidencia. El segundo parámetro define la ruta “objetivo”. Esto se puede
definir como una matriz o como una cadena de destino. Algunos ejemplos de ruta
objetivo son:
// Matriz de destino a un controlador de aplicación
$routes->connect(
'/users/view/*',
['controller' => 'Users', 'action' => 'view']
);
$routes->connect('/users/view/*', 'Users::view');
// Matriz de destino a un controlador de plugin con prefijo
$routes->connect(
'/admin/cms/articles',
['prefix' => 'Admin', 'plugin' => 'Cms', 'controller' => 'Articles', 'action' => 'index']
);
$routes->connect('/admin/cms/articles', 'Cms.Admin/Articles::index');
La primera ruta que conectamos coincide con las URL que comienzan con /users/view
y asigna esas solucitudes al UsersController->view()
. El /*
indica al enrutador
para pasar cualquier segmento adicional como argumentos del método. Por ejemplo,
/users/view/123
se asignaría a UsersController->view(123)
.
El ejemplo anterior también ilustra los destinos de cadena. Los destinos de cadena
proporcionan una forma compacta de definir el destino de una ruta. Los destinos de
cadena tienen la siguiente sintaxis:
[Plugin].[Prefix]/[Controller]::[action]
Algunos ejemplos de destino de cadena son:
// Controlador de aplicación
'Articles::view'
// Controlador de aplicación con prefijo
Admin/Articles::view
// Controlador de plugin
Cms.Articles::edit
// Controlador de plugin con prefijo
Vendor/Cms.Management/Admin/Articles::view
Anteriormente, usamos el asterisco final (/*
) para capturar segmentos de ruta adicionales,
también está el doble asterisco final (/**
). Utilizando el doble asterisco final,
capturará el resto de una URL como un único argumento. Esto es útil cuando se desea
utilizar un argumento que incluye /
:
$routes->connect(
'/pages/**',
['controller' => 'Pages', 'action' => 'show']
);
La URL entrante /pages/the-example-/-and-proof
daría como resultado el paso de un
único argumento the-example-/-and-proof
.
El segundo parámetro de connect()
puede definir cualquier parámetro para componer
los parámetros de ruta po predeterminado:
$routes->connect(
'/government',
['controller' => 'Pages', 'action' => 'display', 5]
);
Este ejemplo utiliza el segundo parámetro de connect()
para definir los parámetros
predeterminados. Si creas una aplicación que presenta productos para diferentes categorías
de clientes, podrías considerar crear una ruta. Esto permite enlazar /government
en
lugar de /pages/display/5
.
Un uso común del enrutamiento es renombrar los controladores y sus acciones. En lugar de
acceder a nuestro controlador de usuarios como /users/some-action/5
, nos gustaría acceder
a él a través de /cooks/some-action/5
. La siguiente ruta se encarga de eso:
$routes->connect(
'/cooks/{action}/*', ['controller' => 'Users']
);
Esto indica al enrutador que cualquier URL que empieze por /cooks/
deberá ser
enviada al UsersController
. La acción invocada dependerá del valor del parámetro {action}
.
Utilizando Elementos de ruta, puedes crear rutas variables que aceptan entradas del usuario
o variables. La ruta anterior también utiliza el asteristo final. El asterisco final indica que
esta ruta debe aceptar cualquier argumento posicional adicional dado. Estos argumentos estarán
disponibles en la matriz Argumentos Pasados.
Al generar URL también se utilizan rutas. Utilizando
['controller' => 'Users', 'action' => 'some-action', 5]
como una URL, generará
/cooks/some-action/5
si la ruta anterior es la primera coincidencia encontrada.
Las ruts que hemos conectado hasta ahora coincidirán con cualquier tipo de petición HTTP. Si estás
contruyendo un API REST, a menudo querrás asignar acciones HTTP a diferentes métodos de
controlador. El RouteBuilder
proporciona métodos auxiliares que facilitan la definición
de rutas para tipos de peticiones HTTP específicas más simples:
// Crea una ruta que sólo responde a peticiones GET.
$routes->get(
'/cooks/{id}',
['controller' => 'Users', 'action' => 'view'],
'users:view'
);
// Crea una ruta que sólo responde a peticiones PUT
$routes->put(
'/cooks/{id}',
['controller' => 'Users', 'action' => 'update'],
'users:update'
);
Las rutas anteriores asignan la misma URL a diferentes acciones del controlador según
el tipo de petición HTTP utilizada. Las solicitudes GET irán a la acción “view”, mientras
que las solicitudes PUT irán a la acción UPDATE. Existen métodos auxiliares HTTP para:
GET
POST
PUT
PATCH
DELETE
OPTIONS
HEAD
Todos estos métodos devuelven una instancia de ruta, lo que permite aprovechar la
fluent setterts para configurar aún más la ruta.
Elementos de ruta
Puedes especificar tus propios elementos de ruta y al hacerlo podrás definir los
lugares de la URL donde los parámetros para las acciones del controlador deben estar.
Cuando se realiza una solicitud, los valores para estos elementos de ruta se encuentran
en $this->request->getParam()
en el controlador.
Cuando defines un elemento de ruta personalizado, opcionalmente puedes especificar
una expresión regular; esto le dice a CakePHP como saber si la URL está formada
correctamente o no. Si eliges no proporcionar una expresión regular, cualquier caracter
que no sea /
será tratado como parte del parámetro:
$routes->connect(
'/{controller}/{id}',
['action' => 'view']
)->setPatterns(['id' => '[0-9]+']);
$routes->connect(
'/{controller}/{id}',
['action' => 'view'],
['id' => '[0-9]+']
);
El ejemplo anterior ilustra cómo crear una forma rápida de ver modelos desde cualquier
controlador creando una URL que se parezca a /controllername/{id}
. La URL proporcionada
a connect()
especifica dos elementos de ruta: {controller}
y {id}
. El elemento
{controller}
es un elemento de ruta predeterminado de CakePHP, por lo que el enrutador
conoce cómo identificar y emparejar los nombres de controladores en la URL. El elemento
{id}
es un elemento de ruta personalizado y debe aclararse especificando una expresión
regular en el tercer parámetro de connect()
.
CakePHP no produce automáticamente URL en minúsculas y con guiones cuando utiliza el
parámetro {controller}
. Si necesitas hacer esto, el ejemplo anterior podría ser
reescrito así:
use Cake\Routing\Route\DashedRoute;
// Crea un constructor con una clase de ruta diferente
$routes->scope('/', function (RouteBuilder $routes) {
$routes->setRouteClass(DashedRoute::class);
$routes->connect('/{controller}/{id}', ['action' => 'view'])
->setPatterns(['id' => '[0-9]+']);
$routes->connect(
'/{controller}/{id}',
['action' => 'view'],
['id' => '[0-9]+']
);
});
La clase DashedRoute
se asegurará de que los parámetros {controller}
y
{plugin}
están correctamente en minúsculas y con guiones.
Nota
Los patrones utilizados por los elementos de ruta no deben contener
ningún grupo de captura. Si lo hacen, el enrutador no funcionará
correctamente.
Una vez que se ha definido esta ruta, al solicitar /apples/5
se llamará al método
view()
de ApplesController. Dento del método view()
, necesitarás acceder al ID
pasado en $this->request->getParam('id')
.
Si tienes un único controlador en tu aplicación y no quieres que el nombre del
controlador aparezca en la URL, puedes asignar todas las URL a acciones en tu
controlador. Por ejemplo, para asignar todas las URL a acciones del contolador
home
, para tener una URL como /demo
en lugar de /home/demo
, puedes
hacer lo siguiente:
$routes->connect('/{action}', ['controller' => 'Home']);
Si quieres proporcionar una URL que no distinga entre mayúsculas y minúsculas,
puedes utilizar modificadores en línea de expresiones regulares:
$routes->connect(
'/{userShortcut}',
['controller' => 'Teachers', 'action' => 'profile', 1],
)->setPatterns(['userShortcut' => '(?i:principal)']);
Un ejemplo más y serás un profesional del enrutamiento:
$routes->connect(
'/{controller}/{year}/{month}/{day}',
['action' => 'index']
)->setPatterns([
'year' => '[12][0-9]{3}',
'month' => '0[1-9]|1[012]',
'day' => '0[1-9]|[12][0-9]|3[01]'
]);
Esto es bastante complicado, pero muestra cuán poderosas pueden ser las rutas. La URL
proporcionada tiene cuatro elementos de ruta. El primero nos resulta familiar: es
un elemento de ruta por defecto que incica a CakePHP que espere un nombre de controlador.
A continuación, especificamos algunos valores predeterminados. Independientemente
del controlador, queremos que se llame a la acción index()
.
Finalmente, especificamos algunas expresiones regulares que coincidirán con año, mes
y día en forma numérica. Ten en cuenta que los paréntesis (captura de grupos) no se
admiten en expresiones regulares. Aún podemos especificar alternativas, como se
indicó anteriormente, pero no agrupadas entre paréntesis.
Una vez definida, esta ruta coincidirá con /articles/2007/02/01
,
/articles/2004/11/16
, entregando las solicitudes a la acción index()
de sus respectivos controladores, con los parámetros de fecha en
$this->request->getParams()
.
Elementos de Ruta Reservados
Hay varios elementos de ruta que tienen un significado especial en CakePHP,
y no deben usarse a menos que desee un significado especial
controller
Se utiliza para nombrar el controlador de una ruta.
action
Se utiliza para nombrar la acción del controlador para una ruta.
plugin
Se utiliza para nombrar el complemento en el que se encuentra un controlador.
prefix
Usado para Enrutamiento de Prefijo
_ext
Usado para File extentions routing.
_base
Se establece a false
para eliminar la ruta base de la URL generada. Si
su aplicación no está en el directorio raíz, esto puede utilizarse para generar URL
que son “cake relative”.
_scheme
Configurado para crear enlaces en diferentes esquemas como webcal o ftp.
El valor predeterminado es el esquema actual.
_host
Establece el host que se utilizará para el enlace. El valor predeterminado
es el host actual.
_port
Establece el puerto si necesitamos crear enlaces en puertos no estándar.
_full
Si es true
el valor de App.fullBaseUrl
mencionado en
Configuración General se atepondrá a la URL generada.
#
Permite configurar fragmentos de hash de URL.
_https
Establecerlo en true
para convertir la URL generada a https o``false``
para forzar http. Antes de 4.5.0 utilizar _ssl
.
_method
Define el tipo de petición/método a utilizar. Útil cuando trabajamos con
Enrutamiento RESTful.
_name
Nombre de la ruta. Si has configurado rutas con nombre, puedes utilizar
esta clave para especificarlo.
Configurando Opciones de Ruta
Hay varias opciones de ruta que se pueden configurar en cada ruta. Después de
conectar una ruta, puedes utilizar sus métodos de creación fluidos para configurar
aún más la ruta. Estos métodos reemplazan muchas de las claves en el parámetro
$options
de connect()
:
$routes->connect(
'/{lang}/articles/{slug}',
['controller' => 'Articles', 'action' => 'view'],
)
// Permite peticiones GET y POST.
->setMethods(['GET', 'POST'])
// Sólo coincide con el subdominio del blog.
->setHost('blog.example.com')
// Establecer los elementos de ruta que deben convertirse en argumentos pasados
->setPass(['slug'])
// Establecer los patrones de coincidencia para los elementos de ruta
->setPatterns([
'slug' => '[a-z0-9-_]+',
'lang' => 'en|fr|es',
])
// También permite archivos con extensión JSON
->setExtensions(['json'])
// Establecer lang para que sea un parámetro persistente
->setPersist(['lang']);
Pasar Parámetros a una Acción
Cuando conectamos rutas utilizando :Elementos de ruta es posible que desees
que los elementos enrutados se pasen como argumentos. La opción pass
indica
qué elementos de ruta también deben estaar disponibles como argumentos pasados
a las funciones del controlador:
// src/Controller/BlogsController.php
public function view($articleId = null, $slug = null)
{
// Algún código aquí...
}
// routes.php
$routes->scope('/', function (RouteBuilder $routes) {
$routes->connect(
'/blog/{id}-{slug}', // For example, /blog/3-CakePHP_Rocks
['controller' => 'Blogs', 'action' => 'view']
)
// Definir los elementos de ruta en la plantilla de ruta
// para anteponerlos como argumentos de la función. El orden
// es importante ya que esto pasará los elementos `$id` y `$slug`
// como primer y segundo parámetro. Cualquier otro parámetro
// adicional pasado en tu ruta se agregará después de los
// argumentos de setPass().
->setPass(['id', 'slug'])
// Definir un patrón con el que `id` debe coincidir.
->setPatterns([
'id' => '[0-9]+',
]);
});
Ahora, gracias a las capacidades de enturamiento inverso, puedes pasar la matriz
de URL como se muestra a continuación y CakePHP sabrá cómo formar la URL como se
define en las rutas:
// view.php
// Esto devolverá un enlace a /blog/3-CakePHP_Rocks
echo $this->Html->link('CakePHP Rocks', [
'controller' => 'Blog',
'action' => 'view',
'id' => 3,
'slug' => 'CakePHP_Rocks'
]);
// También podemos utilizar índices numéricos como parámetros.
echo $this->Html->link('CakePHP Rocks', [
'controller' => 'Blog',
'action' => 'view',
3,
'CakePHP_Rocks'
]);
Uso del Enrutamiento de Ruta
Hablamos de objetivos de cadena anteriormente. Lo mismo también funciona para la
generación de URL usando Router::pathUrl()
:
echo Router::pathUrl('Articles::index');
// salida: /articles
echo Router::pathUrl('MyBackend.Admin/Articles::view', [3]);
// salida: /admin/my-backend/articles/view/3
Truco
La compatibilidad del IDE para el autocompletado del enrutamiento de ruta se puede habilitar con CakePHP IdeHelper Plugin.
Usar Rutas con Nombre
A veces encontrarás que escribir todos los parámetros de la URL para una ruta es
demasiado detallado, o le gustaría aprovechar las mejoras de rendimiento que tienen
las rutas con nombre. Al conectar rutas, puedes especificar una opción _name
,
esta opción se puede utilizar en rutas inversas para identificar la ruta que deseas
utilizar:
// Conectar una ruta con nombre.
$routes->connect(
'/login',
['controller' => 'Users', 'action' => 'login'],
['_name' => 'login']
);
// Nombrar una ruta específica según el tipo de petición
$routes->post(
'/logout',
['controller' => 'Users', 'action' => 'logout'],
'logout'
);
// Generar una URL utilizando una ruta con nombre.
$url = Router::url(['_name' => 'logout']);
// Generar una URL utilizando una ruta con nombre,
// con algunos argumentos de cadena en la consulta.
$url = Router::url(['_name' => 'login', 'username' => 'jimmy']);
Si tu plantilla de ruta contienen elementos de ruta como {controller}
deberás
proporcionarlos como parte de las opciones de Router::url()
.
Nota
Los nombres de las rutas deben ser únicos en toda la aplicación. El mismo
_name
no se puede utilizar dos veces, incluso si los nombres aparecen
dentro de un alcance de enrutamiento diferente.
Al crear rutas con nombre, probablemente querrás ceñirte a algunas convenciones
para los nombres de las rutas. CakePHP facilita la creación de nombres de rutas
al permitir definir prefijos de nombres en cada ámbito:
$routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes) {
// El nombre de esta ruta será `api:ping`
$routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
// Generar una URL para la ruta de ping
Router::url(['_name' => 'api:ping']);
// Utilizar namePrefix con plugin()
$routes->plugin('Contacts', ['_namePrefix' => 'contacts:'], function (RouteBuilder $routes) {
// Conectar rutas.
});
// O con prefix()
$routes->prefix('Admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) {
// Conectar rutas.
});
También puedes utilizar la opción _namePrefix
dentro de ámbitos anidados y
funciona como se esperaba:
$routes->plugin('Contacts', ['_namePrefix' => 'contacts:'], function (RouteBuilder $routes) {
$routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes) {
// Este nombre de ruta será `contacts:api:ping`
$routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
});
// Generar una URL para la ruta de ping
Router::url(['_name' => 'contacts:api:ping']);
Las rutas conectadas en ámbitos con nombre sólo se les agregarán nombres si la
ruta también tiene nombre. A las rutas sin nombre no se les aplicará el _namePrefix
.
Routes connected in named scopes will only have names added if the route is also
named. Nameless routes will not have the _namePrefix
applied to them.
Enrutamiento de Prefijo
-
static Cake\Routing\RouterBuilder::prefix($name, $callback)
Muchas aplicaciones requieren una sección de adminitración donde
los usuarios con privilegios puedan realizar cambios. Esto se hace
a menudo a través de una URL especial como /admin/users/edit/5
.
En CakePHP, el enrutamiento de prefijo puede ser habilitado utilizando
el método de ámbito prefix
:
use Cake\Routing\Route\DashedRoute;
$routes->prefix('Admin', function (RouteBuilder $routes) {
// Todas las rutas aquí tendrán el prefijo `/admin`, y
// tendrán el elemento de ruta `'prefix' => 'Admin'` agregado que
// será necesario para generar URL para estas rutas
$routes->fallbacks(DashedRoute::class);
});
Los prefijos se asignan a subespacios de nombres en el espacio de nombres
Controller
en tu aplicación. Al tener prefijos como controladores separados,
puedes crear controladores más pequeños y simples. El comportamiento que es común
a los controladores con y sin prefijo se puede encapsular mediante herencia,
Componentes, o traits. Utilizando nuestro ejemplo de usuarios,
acceder a la URL /admin/users/edit/5
llamaría al médito edit()
de nuestro
src/Controller/Admin/UsersController.php pasando 5 como primer parámetro.
El archivo de vista utilizado sería templates/Admin/Users/edit.php
Puedes asignar la URL /admin a tu acción index()
del controlador pages utilizando
la siguiente ruta:
$routes->prefix('Admin', function (RouteBuilder $routes) {
// Dado que te encuentras en el ámbito de admin,
// no necesitas incluir el prefijo /admin ni el
// elemento de ruta Admin.
$routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
});
Al crear rutas de prefijo, puedes establecer parámetros de ruta adicionales
utilizando el argumento $options
:
$routes->prefix('Admin', ['param' => 'value'], function (RouteBuilder $routes) {
// Las rutas conectadas aquí tienen el prefijo '/admin' y
// tienen configurada la clave de enrutamiento 'param'.
$routes->connect('/{controller}');
});
Los prefijos con varias palabras se convierten de forma predeterminada utilizando la
inflexión dasherize, es decir, MyPrefix
se asignará a my-prefix
en la URL.
Asegúrate de establecer una ruta para dichos prefijos si deseas utilizar un formato
diferente como, por ejemplo, subrayado:
$routes->prefix('MyPrefix', ['path' => '/my_prefix'], function (RouteBuilder $routes) {
// Las rutas conectadas aquí tiene el prefijo '/my_prefix'
$routes->connect('/{controller}');
});
También puedes definir prefijos dentro del alcance de un plugin:
$routes->plugin('DebugKit', function (RouteBuilder $routes) {
$routes->prefix('Admin', function (RouteBuilder $routes) {
$routes->connect('/{controller}');
});
});
Lo anterior crearía una plantilla de ruta como /debug-kit/admin/{controller}
.
La ruta conectada tendría establecidos los elementos de ruta plugin
y prefix
.
Al definir prefijos, puedes anidar varios prefijos si es necesario:
$routes->prefix('Manager', function (RouteBuilder $routes) {
$routes->prefix('Admin', function (RouteBuilder $routes) {
$routes->connect('/{controller}/{action}');
});
});
Lo anterior crearía una plantilla de ruta como /manager/admin/{controller}/{action}
.
La ruta conectada tendría establecido el elemento de ruta prefix
a Manager/Admin
.
El prefijo actual estará disponible desde los métodos del controlador a través de
$this->request->getParam('prefix')
Cuando usamos rutas de prefijo es importante configurar la opción prefix
y
utilizar el mismo formato CamelCased que se utiliza in el método prefix()
.
A continuación se explica cómo crear este enlace utilizando el helper HTML:
// Ve a una ruta de prefijo
echo $this->Html->link(
'Manage articles',
['prefix' => 'Manager/Admin', 'controller' => 'Articles', 'action' => 'add']
);
// Deja un prefijo
echo $this->Html->link(
'View Post',
['prefix' => false, 'controller' => 'Articles', 'action' => 'view', 5]
);
Crear Enlaces a Rutas de Prefijo
Puedes crear enlaces que apunten a un prefijo añadiendo la clave del prefijo a la matriz
de URL:
echo $this->Html->link(
'New admin todo',
['prefix' => 'Admin', 'controller' => 'TodoItems', 'action' => 'create']
);
Al utilizar anidamiento, es necesario encadenarlos entre sí:
echo $this->Html->link(
'New todo',
['prefix' => 'Admin/MyPrefix', 'controller' => 'TodoItems', 'action' => 'create']
);
Esto se vincularía a un controlador con el espacio de nombre App\Controller\Admin\MyPrefix
y
la ruta de archivo src/Controller/Admin/MyPrefix/TodoItemsController.php
.
Nota
Aquí el prefijo siempre es CamelCased, incluso si el resultado del enrutamiento
es discontinuo.
La propia ruta hará la inflexión si es necesario.
Enrutamiento de Plugin
-
static Cake\Routing\RouterBuilder::plugin($name, $options = [], $callback)
Las rutas para Plugins deben crearse utilizando el método plugin()
.
Este método crea un nuevo ámbito de enrutamiento para las rutas del plugin:
$routes->plugin('DebugKit', function (RouteBuilder $routes) {
// Las rutas conectadas aquí tienen el prefijo '/debug-kit' y
// el elemento de ruta plugin configurado a 'DebugKit'.
$routes->connect('/{controller}');
});
Cuando creamos ámbitos de plugin, puedes personalizar el elemento de ruta utilizado
con la opción path
:
$routes->plugin('DebugKit', ['path' => '/debugger'], function (RouteBuilder $routes) {
// Las rutas conectadas aquí tiene el prefijo '/debugger' y
// el elemento de ruta plugin configurado a 'DebugKit'.
$routes->connect('/{controller}');
});
Al utilizar ámbitos, puedes anidar ámbitos de plugin dentro de ámbitos de prefijos:
$routes->prefix('Admin', function (RouteBuilder $routes) {
$routes->plugin('DebugKit', function (RouteBuilder $routes) {
$routes->connect('/{controller}');
});
});
Lo anteior crearía una ruta similar a /admin/debug-kit/{controller}
.
Tendría configurados los elementos de ruta prefix
y plugin
. En la sección
Rutas del Plugin hay más información sobre la creación de rutas de plugin.
Crear Enlaces a Rutas de Plugin
Puedes crear enlaces que apunten a un plugin añadiendo la clave plugin a tu
matrix de URL:
echo $this->Html->link(
'New todo',
['plugin' => 'Todo', 'controller' => 'TodoItems', 'action' => 'create']
);
Por el contrario, si la solicitud activa es una solicitud de plugin y deseas crear
un enlace que no tenga plugin puedes hacer lo siguiente:
echo $this->Html->link(
'New todo',
['plugin' => null, 'controller' => 'Users', 'action' => 'profile']
);
Estableciendo 'plugin' => null
le indicas al Enrutador que quieres
crear un enlace que no forme parte de un plugin.
Enrutamiento SEO-Friendly
Algunos desarrolladores prefieren utilizar guiones en las URL, ya que se
percibe que dan un mejor posicionamiento en los motores de búsqueda.
La clase DashedRoute
se puede utilizar en tu aplicación con la capacidad
de enrutar plugin, controlador y acciones camelizadas a una URL con guiones.
Por ejemplo, si tenemos un plugin ToDo
, con un controlador TodoItems
, y
una acción showItems()
, se podría acceder en /to-do/todo-items/show-items
con la siguiente conexión de enrutador:
use Cake\Routing\Route\DashedRoute;
$routes->plugin('ToDo', ['path' => 'to-do'], function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});
Coincidencia de Métodos HTTP Específicos
Las rutas pueden coincidir con métodos HTTP específicos utilizando los métodos
del helper HTTP:
$routes->scope('/', function (RouteBuilder $routes) {
// Esta ruta sólo coincide con peticiones POST.
$routes->post(
'/reviews/start',
['controller' => 'Reviews', 'action' => 'start']
);
// Coincide con múltiples tipos de peticiones
$routes->connect(
'/reviews/start',
[
'controller' => 'Reviews',
'action' => 'start',
]
)->setMethods(['POST', 'PUT']);
});
Puedes hacer coincidir múltiples métodos HTTP utilizando una matriz. Dada que el
parámetro _method
es una clave de enturamiento, participa tanto en el análisis
como en la generación de URL. Para generar URLs para rutas específicas de un método
necesitarás incluir la clave _method
al generar la URL:
$url = Router::url([
'controller' => 'Reviews',
'action' => 'start',
'_method' => 'POST',
]);
Coincidencia con Nombres de Dominio Específicos
Las rutas pueden utilizar la opción _host
para coincidir sólo con dominios
específicos. Puedes utilizar el comodín *.
para coincidir con cualquier
subdominio:
$routes->scope('/', function (RouteBuilder $routes) {
// Esta ruta sólo coincide en http://images.example.com
$routes->connect(
'/images/default-logo.png',
['controller' => 'Images', 'action' => 'default']
)->setHost('images.example.com');
// Esta ruta sólo coincide en http://*.example.com
$routes->connect(
'/images/old-logo.png',
['controller' => 'Images', 'action' => 'oldLogo']
)->setHost('*.example.com');
});
La opción _host
también se utiliza en la generación de URL. Si tu opción
_host
especifica un dominio exacto, ese dominio se incluirá en la URL
generada. Sin embargo, si utilizas un comodín, tendrás que indicar el parámetro
_host
al generar la URL:
// Si tienes esta ruta
$routes->connect(
'/images/old-logo.png',
['controller' => 'Images', 'action' => 'oldLogo']
)->setHost('images.example.com');
// Necesitas esto para generar la URL
echo Router::url([
'controller' => 'Images',
'action' => 'oldLogo',
'_host' => 'images.example.com',
]);
Enrutamiento de Extensiones de Archivo
-
static Cake\Routing\RouterBuilder::extensions(string|array|null $extensions, $merge = true)
Para manejar diferentes extensiones de archivo en tus URL, puedes definir las
extensiones utilizando el método Cake\Routing\RouteBuilder::setExtensions()
:
$routes->scope('/', function (RouteBuilder $routes) {
$routes->setExtensions(['json', 'xml']);
});
Esto habilitará ls extensiones nombradas para todas las rutas que se estén conectando
en ese ámbito después de la llamada a setExtensions()
, incluidas aquellas que
se estén conectando en ámbitos anidados.
Nota
Configurar las extensiones debe ser lo primero que hagas en un ámbito, ya que
las extensiones sólo se aplicarán a rutas conectadas después de configurar
las extensiones.
También ten en cuenta que los ámbitos reabiertos no heredarán las extensiones
definidas en ámbitos abiertos anteriormente.
Al utilizar extensiones, le indicas al enrutador que elimine cualquier extensión de
archivo coincidente en la URL y luego analice lo que queda. Si deseas crear una URL como
/page/title-of-page.html, crearías su ruta usando:
$routes->scope('/page', function (RouteBuilder $routes) {
$routes->setExtensions(['json', 'xml', 'html']);
$routes->connect(
'/{title}',
['controller' => 'Pages', 'action' => 'view']
)->setPass(['title']);
});
Luego, para crear enlaces que correspondan con las rutas, simplemente usa:
$this->Html->link(
'Link title',
['controller' => 'Pages', 'action' => 'view', 'title' => 'super-article', '_ext' => 'html']
);
Enrutamiento RESTful
El enrutador ayuda a generar rutas RESTful para tus controladores. Las rutas RESTful
son útiles cuando estás creando API endpoints para tus aplicaciones. Si quisiéramos
permitir el acceso REST a un controlador de recetas, haríamos algo como esto:
// En config/routes.php...
$routes->scope('/', function (RouteBuilder $routes) {
$routes->setExtensions(['json']);
$routes->resources('Recipes');
});
La primera línea configura una serie de rutas predeterminadas para el acceso REST
donde el método especifica el formato de resultado deseado, por ejemplo, xml, json
y rss. Estas rutas son sensible al método de solicitud HTTP.
HTTP format |
URL.format |
Acción del controlador invocada |
GET |
/recipes.format |
RecipesController::index() |
GET |
/recipes/123.format |
RecipesController::view(123) |
POST |
/recipes.format |
RecipesController::add() |
PUT |
/recipes/123.format |
RecipesController::edit(123) |
PATCH |
/recipes/123.format |
RecipesController::edit(123) |
DELETE |
/recipes/123.format |
RecipesController::delete(123) |
Nota
El patrón predeterminado para los ID de recursos sólo coincide con números
enterors o UUID. Si tus ID son diferentes, tendrás que proporcionar un
patrón de expresión regular a través de la opción id
, por ejemplo
$builder->resources('Recipes', ['id' => '.*'])
.
El método HTTP utilizado se detecta desde algunas fuentes diferentes.
Las fuentes en orden de preferencia son:
La variable POST _method
El encabezado The X_HTTP_METHOD_OVERRIDE
.
El encabezado REQUEST_METHOD
La variable POST _method
es útil para utilizar un navegador como
cliente REST (o cualquier otra cosa que pueda realizar POST).
Simplemente, establece el valor de _method()
con el nombre del
método de la solicitud HTTP que deseas emular.
Crear Rutas de Recursos Anidadas
Una vez hayas conectado recursos en un alcance, también puedes conectar rutas para
subrecursos. Las rutas de subrecursos estarán precedidas por el nombre del recurso
original y un parámetro de identificación. Por ejemplo:
$routes->scope('/api', function (RouteBuilder $routes) {
$routes->resources('Articles', function (RouteBuilder $routes) {
$routes->resources('Comments');
});
});
Generará rutas de recursos tanto para articles
como para comments
.
Las rutas de comments se verán así:
/api/articles/{article_id}/comments
/api/articles/{article_id}/comments/{id}
Puedes obtener el article_id
en CommentsController
mediante:
$this->request->getParam('article_id');
De forma predeterminada, las rutas de recursos se asignan al mismo prefijo que el
ámbito contenedor. Si tienes controladores de recursos anidados y no anidados, puedes
utilizar un controlador diferente en cada contexto mediante el uso de prefijos:
$routes->scope('/api', function (RouteBuilder $routes) {
$routes->resources('Articles', function (RouteBuilder $routes) {
$routes->resources('Comments', ['prefix' => 'Articles']);
});
});
Lo anterior asignará el recurso “Comments” a
App\Controller\Articles\CommentsController
. Tener controladores separados
te permite mantener la lógica del controlador más simple. Los prefijos creados de
esta manera son compatibles con Enrutamiento de Prefijo.
Nota
Si bien puedes anidar recursos con la profundidas que necesites, no se recomienda
anidar más de dos recursos juntos.
Limitar las Rutas Creadas
Por defecto, CakePHP conectará 6 rutas para cada recurso. Si deseas conectar
sólo rutas de recursos específicas podrás utilizar la opción only
:
$routes->resources('Articles', [
'only' => ['index', 'view']
]);
Crearía rutas de recurso de sólo lectura. Los nombres de las rutas son
create
, update
, view
, index
, and delete
.
El nombre de ruta y acción del controlador utilizados predeterminados son
los siguientes:
Nombre de ruta |
Acción del controlador utilizada |
create |
add |
update |
edit |
view |
view |
index |
index |
delete |
delete |
Cambiar las Acciones del Controlador Utilizadas
Es posible que debas cambiar los nombres de las acciones del controlador que se
utilizan al conectar rutas. Por ejemplo, si tu acción edit()
se llama put()
puedes utilizar la clave actions
para renombrar las acciones utilizadas:
$routes->resources('Articles', [
'actions' => ['update' => 'put', 'create' => 'add']
]);
Lo anterior utilizaría put()
para la acción edit()
y add()
en lugar de create()
.
Mapeo de Rutas de Recursos Adicionales
Puedes asignar métodos de recursos adicionales utilizando la opción map
:
$routes->resources('Articles', [
'map' => [
'deleteAll' => [
'action' => 'deleteAll',
'method' => 'DELETE'
]
]
]);
// Esto conectaría /articles/deleteAll
Además de las rutas predeterminadas, esto también conectaría una ruta para
/articles/delete-all. De forma predeterminada, el segmento de ruta coincidirá
con el nombre de la clave. Puedes utilizar la clave “path” dentro de la defición
del recurso para personalizar el nombre de la ruta:
$routes->resources('Articles', [
'map' => [
'updateAll' => [
'action' => 'updateAll',
'method' => 'PUT',
'path' => '/update-many',
],
],
]);
// Esto conectaría /articles/update-many
Si defines “only” and “map”, asegúrate de que tus métodos asignados también están
en la lista “only”.
Enrutamiento de Recursos Prefijados
[[Continuar]]
Las rutas de recursos pueden conectarse a los controladores en prefijos de
enrutamiento conectando rutas en un ámbito prefijado or utilizando la opción prefix
:
$routes->resources('Articles', [
'prefix' => 'Api',
]);
Clases de Ruta Personalizada para Rutas de Recursos
Puedes proporcionar la clave coneectOptions
en la matriz $options
para
resources()
para proporcionar la configuración personalizada utilizada por
connect()
:
$routes->scope('/', function (RouteBuilder $routes) {
$routes->resources('Books', [
'connectOptions' => [
'routeClass' => 'ApiRoute',
]
];
});
Inflexión de URL para Rutas de Recursos
De forma predeterminada, los fragmentos de URL de los controladores con varias
palabras están en la forma con guiones del nombre del controlador. Por ejemplo,
el fragmento de URL de BlogPostsController
sería /blog-posts.
Puedes especificar un tipo de inflexión alternativo utilizando la opción inflect
:
$routes->scope('/', function (RouteBuilder $routes) {
$routes->resources('BlogPosts', [
'inflect' => 'underscore' // Will use ``Inflector::underscore()``
]);
});
Lo anterior generará una URL del tipo: /blog_posts.
Cambiar el Elemento de Ruta
De forma predeterminada, las rutas de recursos utilizan una forma inflexionada
del nombre del recurso para el segmento de URL. Puedes configurar un segmento
de ruta personalizado con la opción path
:
$routes->scope('/', function (RouteBuilder $routes) {
$routes->resources('BlogPosts', ['path' => 'posts']);
});
Generando URL
-
static Cake\Routing\RouterBuilder::url($url = null, $full = false)
-
static Cake\Routing\RouterBuilder::reverse($params, $full = false)
Generar URL o enrutamiento inverso es una característica de CakePHP que se
utiliza para permitirte cambiar la estructura de tu URL sin tener que modificar
todo tu código.
Si creas URL utilizando cadenas como:
$this->Html->link('View', '/articles/view/' . $id);
Y luego decides que /articles
realmente debería llamarse posts
,
tendría que ir por toda tu aplicación renombrando las URL. Sin embargo,
si definiste tu enlace como:
//`link()` utiliza internamente Router::url() y acepta una matriz de enrutamiento
$this->Html->link(
'View',
['controller' => 'Articles', 'action' => 'view', $id]
);
o:
//'Router::reverse()' opera en la matriz de parámetos de la petición
//y producirá una cadena de url válida para `link()`
$requestParams = Router::getRequest()->getAttribute('params');
$this->Html->link('View', Router::reverse($requestParams));
Luego, cuando decidieras cambiar tus URL, podrías hacerlo definiendo una ruta.
Esto cambiaría tanto la asignación de URL entrante como las URL generadas.
La elección de la técnica está determinada por qué tan bien se pueden predecir
los elementos de la matriz de enrutamiento.
Utilizando Router::url()
Router::url()
te permite utilizar routing arrays
en situaciones donde los elementos requeridos de la matriz son fijos o se deducen
fácilmente.
Proporcionará enrutamiento inverso cuando la url de destino esté bien definida:
$this->Html->link(
'View',
['controller' => 'Articles', 'action' => 'view', $id]
);
También es útil cuando el destino es desconocido, pero sigue un patrón bien definido:
$this->Html->link(
'View',
['controller' => $controller, 'action' => 'view', $id]
);
Los elementos con claves numéricas se tratan como Argumentos Pasados.
Al utilizar matrices de enrutamiento, puedes definir tanto los parámetros de
la cadena de consulta como los fragmentos de documentos utilizando claves
especiales:
$routes->url([
'controller' => 'Articles',
'action' => 'index',
'?' => ['page' => 1],
'#' => 'top'
]);
// Generará una URL del tipo.
/articles/index?page=1#top
También puedes utilizar cualquiera de los elementos de ruta especiales al generar URL:
_ext
Se utiliza para enrutamiento de Enrutamiento de Extensiones de Archivo.
_base
Establecer en false
para eliminar la ruta base de la URL generada.
Si tu aplicación no está en el directorio raíz, esto se puede utilizar para generar
URL relativas a cake.
_scheme
Configurado para crear enlaces en diferentes esquemas como webcal
o
ftp
. El valor predeterminado es el esquema actual.
_host
Establece el host que se utilizará en el enlace. El valor por defecto es el
del host actual.
_port
Establece el puerto si necesitas crear enlaces a puestos no estándar.
_method
Define el verbo HTTP para el que es la URL.
_full
Si es true
el valor de App.fullBaseUrl
mencionado en
Configuración General se antepondrá a las URL generadas.
_https
Establecer en true
para convertir la URL generada a https o false
para forzar http.
_name
Nombre de la ruta. Si has configurado rutas con nombre, puedes utilizar esta
clave para especificarlas.
Utilizando Router::reverse()
Router::reverse()
te permite utilizar los Parámetros de la solicitud en casos
donde la URL actual con algunas modificaciones es la base para el destino y los
elementos de la URL actual son impredecibles.
Como ejemplo, imagina un blog que permite a los usuarios crear Articles y
Comments, y marcar ambos como published o draft. Ambas URL de la página index
pueden incluir el ID del usuario. La URL de Comments también puede incluir el
ID de un Article para identificar a qué artículo se refieren los comentarios.
Aquí están las url para este escenario:
/articles/index/42
/comments/index/42/18
Cuando el autor utilice estas páginas, sería conveniente incluir enlaces que
permitan mostrar la página con todos los resultados, sólo publicados o sólo
borrador.
Para mantener el código DRY, sería mejor incluir los enlaces a través de un
elemento:
// element/filter_published.php
$params = $this->getRequest()->getAttribute('params');
/* preparar la url para Borrador */
$params = Hash::insert($params, '?.published', 0);
echo $this->Html->link(__('Draft'), Router::reverse($params));
/* Preparar la url para Publicados */
$params = Hash::insert($params, '?.published', 1);
echo $this->Html->link(__('Published'), Router::reverse($params));
/* Preparar la url para Todos */
$params = Hash::remove($params, '?.published');
echo $this->Html->link(__('All'), Router::reverse($params));
Los enlaces generados por estas llamadas incluirían uno o dos parámetros
de paso dependiendo de la estructura de la URL actual. Y el código
funcionaría para cualquier URL futura, por ejemplo, si comenzara a usar
prefijos de ruta o si agregara más parámetros del paso.
Matrices de Enrutamiento vs Parámetros de Solicitud
La diferencia significativa entre las dos matrices y su uso en estos métodos
de enrutamiento inverso está la forma en la que incluyen los parámetros
de paso.
Las matrices de enrutamiento incluyen los parámetros de paso como valores
sin clave en la matriz:
$url = [
'controller' => 'Articles',
'action' => 'View',
$id, //un parámetro de paso
'page' => 3, //un argumento de consulta
];
Los parámetros de consulta incluyen parámtros de paso en la clave “pass”
de la matriz:
$url = [
'controller' => 'Articles',
'action' => 'View',
'pass' => [$id], //los parámetros de paso
'?' => ['page' => 3], //los parámtros de consulta
];
Por lo tanto, si los deseas, es posible convertir los parámetros de solicitud
en una matriz de enrutamiento o viceversa.