Slim es un marco liviano que tiene mucho impacto por su pequeña huella. Tiene un increíble sistema de enrutamiento y ofrece una base sólida para trabajar sin interponerse en su camino. Deja que te enseñe!
Pero eso no quiere decir que Slim no tenga algunos problemas; su configuración de un solo archivo se desordena a medida que crece su aplicación. En este artículo, revisaremos cómo estructurar una aplicación Slim no solo para mantener, sino también mejorar su funcionalidad y mantener las cosas ordenadas y sistemáticas..
Comencemos mirando un código Slim común para identificar el problema. Después de instalar Slim a través de Composer, necesita crear una instancia de Delgado
Objetar y definir sus rutas:
get ('/', function () echo "Home Page";); $ app-> get ('/ testPage', function () use ($ app) $ app-> render ('testpage.php');); $ app-> run ();
Vamos a convertir el objeto Slim en el "controlador".
La primera llamada de método establece una nueva ruta para el URI raíz (/
), y conecta la función dada a esa ruta. Esto es bastante detallado, pero fácil de configurar. La segunda llamada de método define una ruta para el URI página de prueba
. Dentro del método suministrado, utilizamos Slim's. hacer()
método para hacer una vista.
Aquí está el primer problema: esta función (un cierre) no se llama en el contexto actual y no tiene forma de acceder a las funciones de Slim. Es por esto que necesitamos usar el utilizar
palabra clave para pasar la referencia a la aplicación Slim.
El segundo tema proviene de la arquitectura de Slim; está destinado a ser definido todo en un archivo. Por supuesto, puede subcontratar la variable a otro archivo, pero solo se ensucia. Idealmente, queremos la capacidad de agregar controladores para modularizar el marco en componentes individuales. Como beneficio adicional, sería bueno que estos controladores ofrecieran acceso nativo a las funciones de Slim, eliminando la necesidad de pasar referencias a los cierres.
Es discutible si la lectura del código fuente de un proyecto de código abierto se considera ingeniería inversa, pero es el término con el que me quedo. Entendemos cómo usar Slim, pero ¿qué sucede debajo del capó? Veamos una ruta más complicada para llegar a la raíz de esta pregunta:
$ app-> get ('/ users /: name', function ($ name) echo "Hello". $ name;);
Esta definición de ruta usa dos puntos con la palabra, nombre
. Este es un marcador de posición, y el valor utilizado en su lugar se pasa a la función. Por ejemplo, / usuarios / gabriel
coincide con esta ruta, y 'gabriel' se pasa a la función. La ruta, / usuarios
, por otro lado, no es una coincidencia porque falta el parámetro.
Si lo piensa de manera lógica, hay una serie de pasos que deben completarse para procesar una ruta..
Para optimizar mejor el proceso, Slim (utilizando devoluciones de llamada de expresiones regulares y grupos) almacena los marcadores de posición mientras comprueba las coincidencias. Esto combina dos pasos en uno, dejando solo la necesidad de ejecutar la función conectada cuando Slim está listo. Queda claro que el objeto de la ruta es autónomo y, francamente, todo lo que se necesita.
En el ejemplo anterior, teníamos acceso a las funciones de Slim al analizar las rutas, pero necesitábamos pasar una referencia de objeto Slim porque, de lo contrario, no estaría disponible dentro del contexto de ejecución de la función. Eso es todo lo que necesita para la mayoría de las aplicaciones, ya que la lógica de su aplicación debe ocurrir en el controlador.
Con eso en mente, extraigamos la parte de "enrutamiento" en una clase y convirtamos el objeto Slim en el "controlador".
Para comenzar, descarguemos e instalemos "vanilla Slim" si aún no lo ha hecho. Voy a suponer que tienes Composer instalado, pero si no, sigue los pasos .
Dentro de un nuevo directorio, cree un archivo llamado compositor.json
, y anexar lo siguiente:
"name": "nettuts / slim-mvc", "require": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*"
En una ventana de terminal, navegue a dicho directorio y escriba instalación del compositor
. Le guiaré a través de estos paquetes, si es la primera vez que usa Slim.
Técnicamente no necesitas los extras Slim o Twig para este tutorial, pero me gusta usar Twig en lugar de las plantillas estándar de PHP. Sin embargo, si usa Twig, necesita los extras de Slim, ya que proporciona una interfaz entre Twig y Slim.
Ahora vamos a agregar nuestros archivos personalizados, y comenzaremos agregando un directorio a la vendedores
carpeta. Nombraré el mío Nettuts
, Pero no dudes en nombrar el tuyo como desees. Si aún se encuentra en el terminal, asegúrese de que la ventana de su terminal esté en el directorio del proyecto y escriba lo siguiente:
mkdir vendedor / Nettuts
Ahora edita compositor.json
agregando la referencia a esta nueva carpeta:
"name": "nettuts / slim-mvc", "require": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*", " carga automática ": " psr-0 ": " Nettuts ":" vendedor / "
Queremos que nuestra aplicación cargue automáticamente las clases del Nettuts
espacio de nombres, así que esto le dice a Composer que mapee todas las solicitudes de Nettuts
a la norma PSR-0 a partir de la vendedor
carpeta.
Ahora ejecuta:
compositor dump-autoload
Esto vuelve a compilar el autocargador para incluir la nueva referencia. A continuación, crea un archivo, llamado Router.php
, dentro de Nettuts
directorio, y escriba lo siguiente:
Vimos que cada objeto de ruta tiene una función independiente que determina si coincide con el URI proporcionado. Entonces, queremos una serie de rutas y una función para analizarlas. También necesitaremos otra función para agregar nuevas rutas y una forma de recuperar el URI de la solicitud HTTP actual.
Comencemos agregando algunas variables miembro y el constructor:
Class Router rutas protegidas $; solicitud protegida de $; función pública __construct () $ env = \ Slim \ Environment :: getInstance (); $ this-> request = new \ Slim \ Http \ Request ($ env); $ this-> route = array ();Establecemos el
rutas
variable para contener las rutas, y lasolicitud
variable para almacenar el SlimSolicitud
objeto. A continuación, necesitamos la posibilidad de agregar rutas. Para seguir las mejores prácticas, dividiré esto en dos pasos:función pública addRoutes ($ rutas) foreach ($ rutas como $ ruta => $ ruta) $ método = "cualquiera"; if (strpos ($ path, "@")! == false) list ($ path, $ method) = explode ("@", $ path); $ func = $ this-> processCallback ($ path); $ r = new \ Slim \ Route ($ route, $ func); $ r-> setHttpMethods (strtoupper ($ method)); array_push ($ this-> rutas, $ r);Esta función pública acepta una matriz asociativa de rutas en el formato de
ruta => ruta
, dónderuta
es una ruta Slim estándar ycamino
es una cadena con la siguiente convención:Opcionalmente, puede omitir ciertos parámetros para utilizar un valor predeterminado. Por ejemplo, el nombre de la clase será reemplazado por
Principal
si lo dejas afuera,índice
es el valor predeterminado para los nombres de funciones omitidos, y el valor predeterminado para el método HTTP esalguna
. Por supuesto,alguna
no es un método HTTP real, pero es un valor que Slim utiliza para coincidir con todos los tipos de métodos HTTP.los
addRoutes
la función comienza con unapara cada
Bucle que recorre las rutas. A continuación, establecemos el método HTTP predeterminado, opcionalmente reemplazándolo con el método proporcionado si el@
El símbolo está presente. Luego, pasamos el resto de la ruta a una función para recuperar una devolución de llamada y la adjuntamos a una ruta. Finalmente, agregamos la ruta a la matriz..Ahora veamos el
processCallback ()
función:función protegida processCallback ($ path) $ class = "Main"; if (strpos ($ path, ":")! == false) list ($ class, $ path) = explode (":", $ path); $ function = ($ path! = "")? $ ruta: "índice"; $ func = function () usa ($ class, $ function) $ class = '\ Controllers \\'. $ clase; $ class = new $ class (); $ args = func_get_args (); devolver call_user_func_array (array ($ class, $ function), $ args); ; devuelve $ func;El segundo tema proviene de la arquitectura de Slim; está destinado a ser definido todo en un solo archivo.
Primero establecemos la clase por defecto a
Principal
, y anule esa clase si se encuentra el símbolo de dos puntos. A continuación, determinamos si una función está definida y usamos el método predeterminadoíndice
si necesario. Luego pasamos los nombres de clase y función a un cierre y lo devolvemos a la ruta.Dentro del cierre, vamos a añadir el nombre de la clase con el espacio de nombres. Luego creamos una nueva instancia de la clase especificada y recuperamos la lista de argumentos pasados a esta función. Si recuerdas, mientras Slim verifica si una ruta coincide, construye lentamente una lista de parámetros basados en comodines de la ruta. Esta función (
func_get_args ()
) se puede utilizar para obtener los parámetros pasados en una matriz. Luego, usando elcall_user_func_array ()
El método nos permite especificar la clase y la función, mientras pasamos los parámetros al controlador.No es una función muy complicada una vez que la entiendes, pero es un muy buen ejemplo de cuándo los cierres son útiles..
Para recapitular, agregamos una función a nuestra
Enrutador
que le permite pasar una matriz asociativa que contiene rutas y rutas que se asignan a las clases y funciones. El último paso es procesar las rutas y ejecutar cualquiera que coincida. Siguiendo con la convención de nomenclatura Slim, llamémoslocorrer
:función pública run () $ display404 = true; $ uri = $ this-> request-> getResourceUri (); $ method = $ this-> request-> getMethod (); foreach ($ this-> rutas como $ i => $ route) if ($ route-> matches ($ uri)) if ($ route-> supportHttpMethod ($ method) || $ route-> supportHttpMethod ("ANY ")) call_user_func_array ($ route-> getCallable (), array_values ($ route-> getParams ())); $ display404 = falso; if ($ display404) echo "404 - ruta no encontrada";Comenzamos por configurar el
display404
variable, que representa ninguna ruta encontrada, acierto
. Si encontramos una ruta coincidente, estableceremos esto enfalso
y omita el mensaje de error. A continuación, utilizamos el objeto de solicitud de Slim para recuperar el método URI y HTTP actual.Usaremos esta información para recorrer y encontrar coincidencias de nuestra matriz.
Una vez que el objeto de la ruta
partidos()
La función se ejecuta, usted puede llamargetParams ()
para recuperar los parámetros analizados. Usando esa función y lagetCallable ()
Método, somos capaces de ejecutar el cierre y pasar los parámetros necesarios. Finalmente, mostramos un mensaje 404 si ninguna ruta coincide con el URI actual.Vamos a crear la clase de controlador que contiene las devoluciones de llamada para estas rutas. Si ha estado siguiendo esto, entonces se habrá dado cuenta de que nunca forzamos un protocolo o tipo de clase. Si no desea crear una clase de controlador, entonces cualquier clase funcionará bien.
Entonces, ¿por qué crear una clase de controlador? La respuesta corta es que todavía no hemos usado Slim! Usamos partes de Slim para la solicitud HTTP y las rutas, pero el objetivo de esto era tener acceso fácil a todas las propiedades de Slim. Nuestra clase de controlador ampliará la clase Slim real, obteniendo acceso a todos los métodos de Slim.
Puede omitir esta y subclase de Slim directamente desde sus controladores..
Construyendo el Controlador
Básicamente, este controlador te permite modificar Slim mientras aún lo mantienes de vainilla. Nombra el archivo
Controller.php
, y escribe el siguiente código:data = $ settings ['model']; parent :: __ construct ($ settings);Cuando inicializa Slim, puede pasar a una variedad de configuraciones, desde el modo de depuración de la aplicación hasta el motor de plantillas. En lugar de codificar los valores en el constructor, los cargo desde un archivo llamado
settings.php
y pasar esa matriz en el constructor de los padres.Debido a que estamos extendiendo Slim, pensé que sería genial agregar una configuración de "modelo", permitiendo a las personas conectar su objeto de datos directamente al controlador.
Esa es la sección que puede ver en medio del código anterior. Verificamos si el
modelo
Se ha establecido el ajuste y asignarlo al controlador.datos
propiedad si es necesario.Ahora crea un archivo llamado
settings.php
en la raíz de su proyecto (la carpeta con elcompositor.json
archivo), e ingrese lo siguiente:new \ Slim \ Extras \ Views \ Twig (), 'templates.path' => '… / Views', 'model' => array (objeto) ("mensaje" => "Hola mundo")); devuelve $ settings;Estas son configuraciones Slim estándar con la excepción del modelo. Cualquiera que sea el valor asignado a la
modelo
la propiedad se pasa a ladatos
variable; esto podría ser una matriz, otra clase, una cadena, etc ... Lo establezco en un objeto porque me gusta usar el->
notación en lugar de la notación de paréntesis (matriz).Ahora podemos probar el sistema. Si te acuerdas en el
Enrutador
clase, precedimos el nombre de la clase con el "Controlador
"espacio de nombres. Abrircompositor.json
agregue lo siguiente directamente después de la definición de psr-0 para elNettuts
espacio de nombres:"name": "nettuts / slim_advanced", "require": "slim / slim": "2.2.0", "slim / extras": "*", "twig / twig": "*", " autoload ": " psr-0 ": " Nettuts ":" vendor / "," Controller ":" ./ "Entonces, como antes, simplemente descargue el autocargador:
compositor dump-autoloadSi simplemente establecemos la ruta base al directorio raíz, entonces el espacio de nombres
Controlador
se asignará a una carpeta llamada "Controlador
"en la raíz de nuestra aplicación. Así que crea esa carpeta:mkdir controladorDentro de esta carpeta, crea un nuevo archivo llamado
Main.php
. Dentro del archivo, debemos declarar el espacio de nombres y crear una clase que amplíe nuestroControlador
clase basedatos-> mensaje; prueba de función pública () echo "Página de prueba";Esto no es complicado, pero vamos a tomarlo con moderación. En esta clase, definimos dos funciones; sus nombres no importan porque los mapearemos a las rutas más adelante. Es importante notar que accedo directamente a las propiedades desde el controlador (es decir, el modelo) en la primera función, y de hecho, tendrá acceso completo a todos los comandos de Slim.
Ahora vamos a crear el archivo público real. Cree un nuevo directorio en la raíz de su proyecto y asígnele un nombre
público
. Como su nombre lo indica, esto es donde residirán todas las cosas públicas. Dentro de esta carpeta, crea un archivo llamadoindex.php
y escriba lo siguiente:'Main: index @ get', '/ test' => 'Main: test @ get'); $ router-> addRoutes ($ rutas); $ router-> run ();Incluimos la biblioteca de carga automática de Composer y creamos una nueva instancia de nuestro enrutador. Luego definimos dos rutas, las agregamos al objeto enrutador y lo ejecutamos..
También debe activar mod_rewrite en Apache (o su equivalente utilizando un servidor web diferente). Para configurar esto, crea un archivo llamado
.htaccess
dentro depúblico
Directorio y llenarlo con lo siguiente:RewriteEngine On RewriteCond% REQUEST_FILENAME! -F RewriteRule ^ index.php [QSA, L]Ahora todas las solicitudes a esta carpeta (que no coinciden con un archivo real) se transferirán a
index.php
.En su navegador, navegue a su
público
directorio, y debería ver una página que dice "Hola mundo". Navegar a "/prueba
", y debería ver el mensaje" Página de prueba ". No es muy emocionante, pero hemos movido con éxito todo el código lógico a controladores individuales.
Segundo round
Slim no es CodeIgniter, no es Symfony y no es Laravel.
Así que tenemos una funcionalidad básica, pero hay algunos bordes ásperos. Empecemos por el router..
A partir de este momento, mostramos un simple mensaje de error si no existe una ruta. En una aplicación real, queremos la misma funcionalidad que cargar una página normal. Queremos aprovechar la capacidad de Slim para cargar vistas, así como configurar el código de error de la respuesta.
Agreguemos una nueva variable de clase que contenga una ruta opcional (al igual que las otras rutas). En la parte superior del archivo, agregue la siguiente línea directamente después de la definición del objeto de solicitud:
protegido $ errorHandler;A continuación, vamos a crear una función que acepte una ruta y le asigne una función de devolución de llamada. Esto es relativamente simple porque ya hemos abstraído esta funcionalidad:
función pública set404Handler ($ path) $ this-> errorHandler = $ this-> processCallback ($ path);Ahora vamos a ajustar el
correr
comando para ejecutar opcionalmente la devolución de llamada en lugar de simplemente mostrar el mensaje de error:if ($ display404) if (es_callable ($ this-> errorHandler)) call_user_func ($ this-> errorHandler); else echo "404 - ruta no encontrada";Abra la clase de controlador. Aquí es donde puede ajustar la funcionalidad de Slim a sus preferencias personales. Por ejemplo, me gustaría la opción de omitir la extensión de archivo al cargar vistas. Así que en lugar de escribir
$ this-> render ("home.php");
, Yo solo quiero escribir:$ this-> render ("home");
. Para hacer esto, vamos a anular el método de render:función pública render ($ name, $ data = array (), $ status = null) if (strpos ($ name, ".php") === false) $ name = $ name. ".php"; parent :: render ($ nombre, $ datos, $ estado);Aceptamos los mismos parámetros que la función principal, pero verificamos si se proporciona la extensión de archivo y la agregamos si es necesario. Después de esta modificación, pasamos el archivo al método principal para su procesamiento..
Este es solo un ejemplo, pero deberíamos poner cualquier otro cambio aquí en el
hacer()
método. Por ejemplo, si carga las mismas páginas de encabezado y pie de página en todos sus documentos, puede agregar una funciónrenderPage ()
. Esta función cargaría la vista pasada entre las llamadas para cargar el encabezado regular y el pie de página..A continuación, echemos un vistazo a la carga de algunas vistas. En la raíz de tu proyecto crea una carpeta llamada "
Puntos de vista
"(la ubicación y el nombre se pueden ajustar en lasettings.php
expediente). Vamos a crear dos vistas nombradasprueba.php
yerror.php
.Dentro
prueba.php
, agregue lo siguiente:título
Esta es la página nombre!
Y dentro de la
error.php
archivo, ingrese esto:404
La ruta que estabas buscando no se pudo encontrar.
Además, modifica la
Principal
controlador cambiando elíndice()
función a lo siguiente:índice de función pública () $ this-> render ("test", array ("title" => $ this-> data-> message, "name" => "Home"));Aquí, representamos la vista de prueba que acabamos de realizar y pasamos los datos para mostrar. A continuación, probemos una ruta con parámetros. Cambiar el
prueba()
función a lo siguiente:prueba de función pública ($ título) $ this-> render ("prueba", array ("título" => $ título, "nombre" => "Prueba"));Aquí, vamos un paso más allá al recuperar el título de la página desde la propia URI. Por último, pero no menos importante, agreguemos una función para la página 404:
función pública notFound () $ this-> render ('error', array (), 404);Usamos el
hacer()
El tercer parámetro opcional de la función, que establece el código de estado HTTP de la respuesta..Nuestra edición final está en
index.php
Para incorporar nuestras nuevas rutas:$ route = array ('/' => ", '/ test /: title' => 'Main: test @ get'); $ router-> addRoutes ($ route); $ router-> set404Handler (" Main: notFound "); $ router-> run ();Ahora debería poder navegar a las tres rutas y ver sus vistas respectivas.
Conclusión
Con todo lo que hemos logrado, seguro que tiene algunas preguntas sobre por qué Slim no ofrece estas modificaciones. Parecen lógicos, no se alejan demasiado de la implementación de Slim y tienen mucho sentido. Josh Lockhart (el creador de Slim) lo expresó mejor:
"Slim no es CodeIgniter, no es Symfony y no es Laravel. Slim es Slim. Fue diseñado para ser liviano y divertido, a la vez que puede resolver el 80% de los problemas más comunes. En lugar de preocuparse por el borde En los casos, se enfoca en ser simple y tener un código base fácil de leer ".
A veces, como desarrolladores, estamos tan atrapados cubriendo escenarios locos que nos olvidamos de lo que es realmente importante: el código. Mods, como el que se encuentra en este tutorial, solo son posibles debido a la simplicidad y verbosidad del código. Entonces, sí, puede haber algunos casos de vanguardia que requieran atención especial, pero se obtiene una comunidad activa, lo que, en mi opinión, supera ampliamente los costos..
Espero que hayan disfrutado este artículo. Si tiene alguna pregunta o comentario, deje un mensaje abajo. También puede contactarme a través del canal IRC en Freenode en el #nettuts canal.