URLs amigables en CodeIgniter: Controlador ‘catch-all’

Supongamos que estamos programando un CMS en CodeIgniter para integrarlo en nuestros proyectos, y queremos generar urls del estilo www.dominio.com/titulo-de-la-pagina. Una manera de enfocarlo sería por ejemplo crear un controlador Paginas con un método cargar, al que se le pasará como parámetro el título de la página en cuestión. De esta manera se llamaría a la url www.dominio.com/paginas/cargar/titulo-de-la-pagina. Para eliminar /paginas/cargar/ de la url editaríamos el fichero routing.php.

Esto supone un problema: si añadimos una regla genérica a las rutas para redirigir cualquier url al controlador paginas/cargar, no funcionaría el resto de controladores de nuestra aplicación. Deberíamos añadir una regla para cada página o bien para cada controlador que tengamos, con lo cual perdemos dinamismo y nos obliga a editar el fichero de rutas con cada cambio.

Extendiendo la librería Router

Lo que nos interesa es un controlador ‘catch-all’, que capture cualquier texto de la url y lo procese siempre que no exista otro controlador con ese nombre. Para ello vamos a extender la librería de rutas creando un archivo MY_Router.php y guardándolo en application/libraries/. El método estándar para extender librerías es crear un archivo con el mismo nombre añadiendo el prefijo MY_. Aquí tenéis el código de MY_Router.php:

<?php
class MY_Router extends CI_Router {
 
    function MY_Router()
    {
        parent::CI_Router();
    }
 
    function _validate_request($segments)
    {
        // Comprueba que el controlador no existe
        if (!file_exists(APPPATH.'controllers/'.$segments[0].EXT))
        {
            $segments = array("paginas", "cargar", $segments[0]);
 
        }
        return parent::_validate_request($segments);
    }
}
?>

Como veis lo que hacemos es extender el método _validate_request de la librería Router, que es el que procesa los segmentos de nuestra url. En él comprobamos si el nombre del primer segmento de la url corresponde a un controlador existente, si no es así añadimos al array de segmentos nuestro controlador y método paginas y cargar y llamamos al método _validate_request de la librería Router original pasándole estos parámetros.

Finalmente nos queda crear el controlador Paginas.php:

<?php
class Paginas extends Controller {
    function __construct(){
        	parent::Controller();
    }
 
    function cargar($title){
    	.....
    }
}
?>

Dentro de la función cargar, $title contendrá el título de nuestra url, es decir el primer segmento que le pasamos: www.dominio.com/titulo-de-la-pagina. En dicha función lo gestionaremos como nos interese, siendo lo más lógico utilizar ese título como identificador de nuestra página y buscarla en la base de datos para mostrarla.

Si te ha gustado este artículo, por favor compártelo:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • email
  • Meneame
  • StumbleUpon
  • Tumblr
  • Twitter

14 comentarios para “URLs amigables en CodeIgniter: Controlador ‘catch-all’”

  1. carlos dice:

    Excelente artículo, y ahora un pregunta, si tengo dos o mas tipos de contenido? y necsite enrutar a mas acciones? servira hacer alguna modificación?

    Saludos y buen tuto :)

  2. David Rojas dice:

    @carlos No entiendo exáctamente tu pregunta. Tal como está, la extensión MY_Router lo que hace es capturar el primer segmento de la url del título y enviarlo al controlador/método que definas en el array $segments, pero esto sólo lo hace si no encuentra ningún controlador que hayas creado cuyo nombre coincida con el segmento de la url.

  3. carlos dice:

    Hola de nuevo, le estoy dando media vuelta para ver si consigo hacer lo que quiero, quizas sea más facil d elo que parece, soy medio nuevo en Codeigniter.

    Por ejemplo tengo ds controladores uno de paginas y otro de post y cada uno una accion o metodo que recibe la url como parametro.

    Algun truco para que las url que envio me sepa distinguir la olibreria si es post o pagina, y lo rutee al controlador correcto? No se si me dejo entender., por lo pronto l agrgue un segundo parametro a la url que es un post para que lo distinga, pero quiero usar solo la url limpia. Habra alguna solucion, o me quda hacerla a la vieja usansa con la bd y definiedo el tipo de contenido.

    Gracias por la ayuda :)

  4. David Rojas dice:

    @carlos Si sólo quieres tener una url limpia para todo el contenido (sin añadir /post/titulo-de-la-pagina), me temo que la solución es como dices definir un tipo de contenido y comprobarlo en la BD.

  5. Hola David, nuevamente Juan de Colombia… Tengo la siguente duda. Este codigo que pones funciona para direcciones de este estilo:

    http://www.gabasip.com/index.php/article/index/2

    (direccion real), en donde el 7 es el id de un registro de base de datos?. Es decir, empezando con ete codigo podria sustitur esto

    http://www.gabasip.com/index.php/article/index/2

    por esto:

    http://www.gabasip.com/index.php/article/index/servicios

    sin perder la navegacion?, muchas gracias

    PD. en este sitio de ejemplo use tu codigo y la validacion del formulario de contacto muchas gracias!

  6. David Rojas dice:

    @Juan Con esa estructura que propones realmente no necesitas utilizar esto, es más fácil. Supongo que tendrás un controlador article, con un método index. Sólo tienes que pasarle una variable, $nombre por ejemplo, a esa función index (la defines como function index($nombre). Tendrás que meter un campo en la base de datos que tendrá una variable nombre con el nombre de la página (en este ejemplo, ’servicios’). Dentro de la función index entonces obtendrás la página que quieras mostrar a partir de esa variable nombre (en vez de buscarla por el id).

  7. Muchas gracias David, esa es la solucion mas practica, le estaba dando demasiadas vueltas al asunto…

  8. consulta si hago esto que pasara con la pagina de errores ? funcionaran en caso que se le ponga una url que no exista:

    mysitio.com/papapapapappaapapa

  9. David Rojas dice:

    @jose Eso lo controlas tú mismo. Dentro de la función cargar es donde realizas la búsqueda para ver si esa url existe, y si no puedes llamar a un show_404 para que te muestre la página de error.

  10. Nicho dice:

    Qué tal David, buen día:
    Nunca terminaré de agradecerte lo que me has ayudado con tu blog y esta ocasión quisiera saber si conoces como; y me pudieras orientar, para integrar el script de http://mibew.org/sp/ que es un buen webmessenger para atención en línea y que quisiera acoplar en los proyectos de CI. Agradecería infinitamente tus consejos, gracias.

  11. David Rojas dice:

    @Nicho me temo que no puedo ayudarte con esto, no he usado nunca ese paquete así que no sé indicarte.

  12. Nicho dice:

    Ok, gracias por tu respuesta, yo quisiera imaginar que es como integrar alún otros script como los de soporte o como integrar phpbb o wordpress…es que lo he intentado pero como lo instalo en una carpeta en el root y el CI también lo tengo en el root, pues a la hora de querer entrar a la administración del mibew no se puede puesto que no hay un controlador para ello, eso mismo me pasó una vez que intenté hacerlo con phpbb y lo rsolví metiendo el sitio en una carpeta, el foro en otra y un index en el root que me direccionaba al sitio echo con CI, pero lo que quisiera hacer es que todos estuvieran integrados en el CI sin necesidad de hacer lo anterior…eso es posible?

  13. David Rojas dice:

    @Nicho Si instalas algo como wordpress o phpbb lo mejor es que lo tengas separado en una carpeta cada cosa. Si configuras bien el .htaccess no debe darte problemas. Si lo que usas no es un sistema completa sino una clase en php o algo por el estilo, lo que puedes es hacerte tu propia librería en CI que ‘envuelva’ el componente que quieres instalar. Pero como te digo, eso es para clases o widgets concretos, no un sistema completo como wordpress.

  14. Nicho dice:

    Ok…ya entiendo, muchas gracias, entonces le buscaré con el .htaccess…no se gran cosas, pero le voy a buscar. Gracias nuevamente.

Deja un comentario

Introduce tu información personal en el formulario, regístrate o identifícate usando twitter con el siguiente botón.

RSS iTunes podcast Twitter

Categorías

Mi Amazon whislist: Regálame un libro!

Archivos