withbody full_base_url cakephp routing prefix

full_base_url - request is cakephp



Agregar un prefijo a cada URL en CakePHP (3)

¿Cuál es la forma más limpia de agregar un prefijo a cada URL en CakePHP, como un parámetro de idioma?

http://example.com/en/controller/action http://example.com/ru/admin/controller/action

Tiene que funcionar con prefijos "reales" como admin , e idealmente la URL /controller/action podría ser redirigida a /DEFAULT-LANGUAGE/controller/action .

Ahora estoy trabajando en una aplicación retroadaptada, pero fue un truco, y necesito incluir el parámetro de idioma a mano en la mayoría de los enlaces, lo cual no es bueno.

Entonces la pregunta es doble:

  • ¿Cuál es la mejor manera de estructurar Rutas, por lo que el parámetro de idioma se incluye implícitamente por defecto sin tener que especificarse para cada Ruta recién definida?
    • Router::connect(''/:controller/:action/*'', ...) debe incluir implícitamente el prefijo.
    • El parámetro debe estar disponible en $this->params[''lang''] o en algún lugar similar para ser evaluado en AppController::beforeFilter() .
  • ¿Cómo obtener Router::url() para incluir automáticamente el prefijo en la URL, si no se especifica explícitamente?
    • Router::url(array(''controller'' => ''foo'', ''action'' => ''bar'')) debería devolver /en/foo/bar
    • Dado que Controller::redirect() , Form::create() o incluso Router::url() directamente necesitan tener el mismo comportamiento, anular todas y cada una de las funciones no es realmente una opción. Html::image() por ejemplo, debería producir una URL sin prefijo.

Los siguientes métodos parecen llamar a Router::url .

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams través de Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid , pero solo para una generación hash

De esos parece que los métodos Controller y Helper deberían ser anulados, podría vivir sin el JsHelper . Mi idea sería escribir una función general en AppController o tal vez solo en bootstrap.php para manejar la inserción de parámetros. Los métodos reemplazados de Controller y Helper usarían esta función, como lo haría si quisiera llamar manualmente a Router::url . ¿Esto sería suficiente?


Esto es esencialmente todo el código que implementé para resolver este problema al final (al menos creo que eso es todo ;-)):

/config/bootstrap.php

define(''DEFAULT_LANGUAGE'', ''jpn''); if (!function_exists(''router_url_language'')) { function router_url_language($url) { if ($lang = Configure::read(''Config.language'')) { if (is_array($url)) { if (!isset($url[''language''])) { $url[''language''] = $lang; } if ($url[''language''] == DEFAULT_LANGUAGE) { unset($url[''language'']); } } else if ($url == ''/'' && $lang !== DEFAULT_LANGUAGE) { $url.= $lang; } } return $url; } }

/config/core.php

Configure::write(''Config.language'', ''jpn'');

/app_helper.php

class AppHelper extends Helper { public function url($url = null, $full = false) { return parent::url(router_url_language($url), $full); } }

/app_controller.php

class AppController extends Controller { public function beforeFilter() { if (isset($this->params[''language''])) { Configure::write(''Config.language'', $this->params[''language'']); } } public function redirect($url, $status = null, $exit = true) { parent::redirect(router_url_language($url), $status, $exit); } public function flash($message, $url, $pause = 1) { parent::flash($message, router_url_language($url), $pause); } }

/config/routes.php

Router::connect(''/'', array(''controller'' => ''pages'', ''action'' => ''display'', ''home'')); Router::connect(''/pages/*'', array(''controller'' => ''pages'', ''action'' => ''display'')); Router::connect(''/:language/'', array(''controller'' => ''pages'', ''action'' => ''display'', ''home''), array(''language'' => ''[a-z]{3}'')); Router::connect(''/:language/pages/*'', array(''controller'' => ''pages'', ''action'' => ''display''), array(''language'' => ''[a-z]{3}'')); Router::connect(''/:language/:controller/:action/*'', array(), array(''language'' => ''[a-z]{3}''));

Esto permite que las URL predeterminadas como /controller/action utilicen el idioma predeterminado (JPN en mi caso) y las URL como /eng/controller/action para usar un idioma alternativo. Esta lógica se puede cambiar bastante fácilmente en la función router_url_language() .

Para que esto funcione, también necesito definir dos rutas para cada ruta, una que contenga el /:language/ parámetro y otra sin. Al menos no pude entender cómo hacerlo de otra manera.


Una manera más fácil podría ser almacenar el idioma elegido en una cookie y luego no tener que volver a escribir todas las URL. También es posible que detecte el idioma del navegador del usuario automáticamente.

Sin embargo , es poco probable que los motores de búsqueda capten los distintos idiomas y también perderías el idioma si alguien intentara compartir el enlace.

Pero ama la solución completa que publicaste, muy completa, gracias. :-)