4 |
5 | ### Contenido de este manual
6 | 1. [Prerrequisitos](#prerrequisitos-para-usar-slim)
7 | 2. [Instalación](#instalación)
8 | 3. [Creación de Base de datos](#base-de-datos)
9 | 3.1. [Método en consola](#en-consola)
10 | 3.2. [Método usando phpmyAdmin](#en-phpmyadmin)
11 | 4. [Configuración de Slim](#configuración-de-slim)
12 | 5. [Modelo](#modelo)
13 | 6. [Controlador](#controlador)
14 | 7. [Rutas](#rutas)
15 | 8. [Vista](#vista)
16 | 9. [Referencias](#referencias)
17 |
18 |
19 | ### Prerrequisitos para usar Slim
20 |
21 | - PHP 5.5 o posterior
22 | - Un servidor web con reescritura de URLs
23 | - Sistema Manejador de Bases de Datos MySQL/MariaDB[1](#foot1)
24 | - Eloquent (ORM) de Laravel
25 | - Respect Validation
26 | - Twig templates
27 |
28 |
29 |
30 | ### Instalación
31 |
32 | La manera para instalar Slim recomendada por sus desarrolladores es mediante PHP Composer.
33 |
34 | #### Instalación de Composer
35 |
36 | ###### GNU/Linux (GNU plus Linux), MAC OS X y *BSD
37 |
38 | Si usas una distribución como Arch Linux o basada en esta, composer está en los repositorios oficiales, así que puedes instalarlo con Pacman.
39 |
40 | ```
41 | # pacman -S composer
42 | ```
43 |
44 | En caso de que no, para instalar Composer escribe en consola el siguiente comando:
45 |
46 | ```
47 | $ curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
48 | ```
49 |
50 |
51 | o si prefieres, puedes usar el siguiente script[2](#foot2):
52 |
53 | ```sh
54 | #!/bin/sh
55 |
56 | EXPECTED_SIGNATURE=$(wget https://composer.github.io/installer.sig -O - -q)
57 | php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
58 | ACTUAL_SIGNATURE=$(php -r "echo hash_file('SHA384', 'composer-setup.php');")
59 |
60 | if [ "$EXPECTED_SIGNATURE" = "$ACTUAL_SIGNATURE" ]
61 | then
62 | php composer-setup.php --quiet
63 | RESULT=$?
64 | rm composer-setup.php
65 | exit $RESULT
66 | else
67 | >&2 echo 'ERROR: Invalid installer signature'
68 | rm composer-setup.php
69 | exit 1
70 | fi
71 |
72 | ```
73 | Guardado como `install-composer.sh` para ejecutarlo en terminal con el comando
74 |
75 | ```
76 | $ sh install-composer.sh
77 | ```
78 |
79 | **Nota**: Mediante este método, podemos mantener actualizado Composer, pero debes mover el archivo composer.phar a la carpeta `/usr/local/bin/` con el comando
80 |
81 | ```
82 | # mv composer.phar /usr/local/bin/composer
83 | ```
84 | de este modo podrás ejecutar Composer escribiendo solo `composer` en consola en vez de `php composer.phar`.
85 |
86 | ##### Microsoft Windows
87 |
88 | Si eres usuario de Windows debes descargar el archivo `Composer-Setup.*.exe` del repositorio oficial de Composer en Github, que está en [https://github.com/composer/windows-setup/releases/](https://github.com/composer/windows-setup/releases/tag/v4.5.0) y seguir las instrucciones que te de el instalador.
89 |
90 | #### Instalación de Slim
91 |
92 | Podemos crear un proyecto desde cero o usar el esqueleto que proporciona Slim, el cual nos da una configuración sencilla para empezar la aplicación, solo tienes que escribir en consola lo siguiente:
93 |
94 | ```
95 | $ composer create-proyect slim/slim-skeleton crud-slim
96 | ```
97 |
98 | Esto creará un nuevo directorio `crud-slim`con los archivos necesarios para comenzar a escribir la aplicación.
99 |
100 | **Estructura del directorio**
101 |
102 | ```
103 | crud-slim
104 | ├── composer.json
105 | ├── composer.lock
106 | ├── CONTRIBUTING.md
107 | ├── dirstruct.txt
108 | ├── logs
109 | │ ├── app.log
110 | │ └── README.md
111 | ├── phpunit.xml
112 | ├── public
113 | │ └── index.php
114 | ├── README.md
115 | ├── src
116 | │ ├── dependencies.php
117 | │ ├── middleware.php
118 | │ ├── routes.php
119 | │ └── settings.php
120 | ├── templates
121 | │ └── index.phtml
122 | ├── tests
123 | │ └── Functional
124 | │ ├── BaseTestCase.php
125 | │ └── HomepageTest.php
126 | └── vendor/...
127 |
128 | ```
129 |
130 | **Nota:** el directorio `vendor/` contiene muchos subdirectorios pero no es recomendado editar ninguno de los archivos que se contienen aquí ya que es donde están todas las dependencias que usaremos dentro de la aplicación y modificarlos afectaría el funcionamiento de esta.
131 |
132 | Si ejecutamos `php -S localhost:8080 -t public public/index.php`en el directorio de nuestra aplicación y abrimos nuestro navegador en la dirección `localhost:8080` aparecerá la siguiente vista
133 |
134 |
135 |
136 | ### Base de datos
137 |
138 | #### En Consola
139 | Creamos una base de datos con el nombre `slim`
140 |
141 | ```
142 | $ mysql -u[nombre-de-usuario] -p
143 | > CREATE DATABASE slim COLLATE = 'utf8_unicode_ci';
144 | > \u slim
145 | ```
146 |
147 | Agregamos la tabla `usuarios`.
148 |
149 | ```sql
150 | > CREATE TABLE usuarios (`id` BIGINT NOT NULL AUTO_INCREMENT,
151 | `nombre` VARCHAR (250) NOT NULL,
152 | `correo` VARCHAR (250) NOT NULL,
153 | `clave_acceso` VARCHAR (250) NOT NULL,
154 | PRIMARY KEY (`id`));
155 | ```
156 |
157 | #### En phpMyAdmin
158 |
159 | Creamos la base de datos que usaremos para el crud:
160 |
161 |
162 | Creamos la tabla de usuarios:
163 |
164 |
165 |
166 |
167 | ### Configura Slim
168 |
169 | Ahora que tenemos la base de datos, hay que agregarla a la configuración de Slim. Para esto, abrimos el archivo `settings.php` que se encuentra en el directorio `src` y que contiene lo siguiente:
170 |
171 | ```php
172 | [
175 | 'displayErrorDetails' => true, // set to false in production
176 | 'addContentLengthHeader' => false, // Allow the web server to send the content-length header
177 |
178 | // Renderer settings
179 | 'renderer' => [
180 | 'template_path' => __DIR__ . '/../templates/',
181 | ],
182 |
183 | // Monolog settings
184 | 'logger' => [
185 | 'name' => 'slim-app',
186 | 'path' => __DIR__ . '/../logs/app.log',
187 | 'level' => \Monolog\Logger::DEBUG,
188 | ],
189 | ],
190 | ];
191 |
192 |
193 | ```
194 | agregamos después del campo `logger` la configuración de nuestra base de datos
195 |
196 | ```php
197 |
198 | //Configuración de base de datos para Slim
199 | 'db' => [
200 | 'driver' => 'mysql',
201 | 'host' => 'localhost',
202 | 'database' => 'slim'
203 | 'username' => '',
204 | 'password' => '',
205 | 'charset' => 'utf8',
206 | 'collation' => 'utf8_unicode_ci',
207 | 'prefix' => '',
208 | ],
209 |
210 | ```
211 | Además, para cargar automáticamente las clases que crearemos más adelante, debemos agregar en el archivo `composer.json` un mapeo _autoload_ con la convención **PSR-4** de php.
212 |
213 | ```javascript
214 | "autoload": {
215 | "psr-4": {
216 | "App\\": "src/"
217 | }
218 | }
219 | ```
220 |
221 | ### Modelo
222 |
223 | Ahora hay que crear el **Modelo** para la aplicación. Aunque Slim no sigue el patrón de diseño MVC (Modelo-Vista-Controlador) de un modo convencional, nos conviene tener un directorio exclusivo para cada componente, así que crearemos un directorio para el modelo dentro de `src/`con nuestro explorador de archivos o con el comando `mkdir modelos` desde el directorio `src`.
224 |
225 | Como sabemos, Slim no cuenta con una herramienta para el Mapeo Objeto-Relacional por defecto. Sin embargo, nos permite agregar una de otro framework escrito en PHP; en este caso usaremos **Eloquent**[3](#foot3) de Laravel.
226 |
227 | Para agregar **Eloquent** a nuestro CRUD primero debemos pedirle a composer que lo agregue a las dependencias de nuestra aplicación.
228 |
229 | ```sh
230 | $ composer require illuminate/database "~5.1"
231 | ```
232 |
233 | Luego agregamos **Eloquent** al **Contenedor de Inyección de Dependencias** (en adelante _CID_) de la aplicación. Abrimos el archivo `dependencies.php` que está en el directorio `src`y le agregamos
234 |
235 | ```php
236 | $container['db'] = function ($container) {
237 | $capsule = new \Illuminate\Database\Capsule\Manager;
238 | $capsule->addConnection($container['settings']['db']);
239 | return $capsule;
240 | };
241 | ```
242 | Para inicializar **Eloquent** en la aplicación hay que agregarlo también en el archivo `public/index.php` antes de `app->run();`
243 | ```php
244 | $capsule = $app->getContainer()->get('capsule'); // toma el elemento capsule dentro del contenedor de la app
245 | $capsule->bootEloquent(); // inicializa Eloquent
246 | ```
247 | Creamos la clase **ModeloUsuario** dentro del directorio modelos.
248 |
249 | ```php
250 | [4](#foot4) mediante **Composer**.
277 |
278 | ```
279 | $ composer require respect/validation
280 | ```
281 |
282 |
283 | ```php
284 | view = $view;
316 | $this->router = $router;
317 | }
318 |
319 |
320 | /**
321 | * Verifica que los parametros que recibe el controlador sean correctos
322 | * @param type array $args - los argumentos a evaluar
323 | */
324 | public function validaArgs($args)
325 | {
326 | $valid = [
327 | // verifica que la id sea un entero
328 | v::intVal()->validate($args['id']),
329 |
330 | // verifica que se reciba una cadena de al menos longitud 2
331 | v::stringType()->length(2)->validate($args['nombre']),
332 |
333 | // verifica que se reciba un correo
334 | v::email()->validate($args['correo']),
335 |
336 | // verifica que no esté en blanco la contraseña
337 | v::notBlank()->validate($args['clave_acceso'])
338 | ];
339 |
340 | }
341 |
342 | /**
343 | * Verifica la correctud de un conjunto de validaciones
344 | * @param type array $validaciones - el conjunto de validaciones a evaluar
345 | * @throws \Exception cuando las validaciones no están en un arreglo
346 | */
347 | public static function verifica($validaciones)
348 | {
349 | if(!is_array($validaciones){
350 | throw new \Exception('Las validaciones deben estar en un arreglo');
351 | } else {
352 | foreach($validaciones as $v){
353 | if ($v == false) {
354 | return false; // todas las validaciones deben cumplirse para que sea correcto
355 | }
356 | }
357 | return true;
358 | }
359 | }
360 |
361 | /*-- Funciones del CRUD --*/
362 | }
363 | ```
364 |
365 | También hay que agregar el **ControladorUsuario** al _CID_ de la aplicación para que ésta pueda utilizarlo.
366 |
367 | ```php
368 | $container['ControladorUsuario'] = function($container){
369 | return new App\Controladores\ControladorUsuario($container);
370 | };
371 | ```
372 |
373 | #### Crear
374 | Recordemos que en **ModeloUsuario** definimos una parte _fillable_ para la tabla, esto se debe a que al ser `id` definido en la base de datos como un atributo auto incrementable, entonces solo necesitamos ingresar los otros 3 campos a la base de datos y lo haremos con esta función:
375 |
376 | ```php
377 | /**
378 | * Función para crear un usuario
379 | * @param type Slim\Http\Request $request - solicitud http
380 | * @param type Slim\Http\Response $response - respuesta http
381 | */
382 | public function crea($request, $response, $args)
383 | {
384 | /*
385 | getParsedBody() toma los parametros del cuerpo de $request que estén
386 | como json o xml y lo parsea de un modo que PHP lo entienda
387 | */
388 | $param = $request->getParsedBody();
389 |
390 | $validaciones = $this->validaArgs($param); // hace las validaciones
391 | if(verifica($validaciones)){
392 |
393 | // evalua si el correo ya existe en la base de datos
394 | $correo_existente = Usuario::where('correo', $atr['correo'])->get()->first();
395 |
396 | // si el correo ya existe manda un error 403
397 | if($correo_existente){
398 | echo->$this->error('YA_ESTÁ_REGISTRADO_EL_CORREO',
399 | $request->getUri()->getPath(),
400 | 404);
401 | return $this->response->withStatus(403);
402 | } else {
403 |
404 | //crea un nuevo usuario a partir del modelo
405 | $usuario = new Usuario;
406 |
407 | // asigna cada elemento del arreglo $atr con su columna en la tabla usuarios
408 | $usuario->nombre = $atr['nombre'];
409 | $usuario->correo = $atr['correo'];
410 | $usuario->clave_acceso = $atr['clave_acceso'];
411 |
412 | $usuario->save(); //guarda el usuario
413 |
414 | // crea una ruta para el usuario con su id
415 | $path = $request->getUri()->getPath() . '/' . $usuario->id;
416 |
417 | return $response->withStatus(201); // el usuario fue creado con éxito
418 | }
419 | }
420 | }
421 | ```
422 |
423 | #### Leer
424 |
425 | Aquí se ejemplifican dos funciones, una para mostrar todos los usuarios registrados y otra donde muestre un usuario en específico. La estructura de los templates `lista.twig` y `usuario.twig` que se mencionan se explicará con mayor detalle en la sección de [Vistas](#vista).
426 |
427 | ```php
428 | /**
429 | * Obtiene todos los usuarios de la tabla usuarios y los manda a la vista
430 | * @param type Slim\Http\Request $request - solicitud http
431 | * @param type Slim\Http\Response $response - respuesta http
432 | */
433 | public function listaUsuarios($request, $response, $args)
434 | {
435 | /*
436 | la vista manda un arreglo de usuarios con la respuesta http,
437 | para que lo renderice en en el template lista.twig
438 | */
439 | return $this->view->render($response, 'lista.twig', ['usuarios' => Usuario::all()]);
440 | }
441 |
442 | /**
443 | * Busca un usuario por su id
444 | * @param type Slim\Http\Request $request - la solicitud http
445 | * @param type Slim\Http\Response $response - la respuesta http
446 | * @param type array $args - argumentos para la función
447 | */
448 | public function buscaUsuarioID($request, $response, $args)
449 | {
450 | $id = $args['id'];
451 |
452 | $valid = [v::intVal()->validate($id)]; // verifica que la id sea un entero
453 | n
454 | // si la validación es correcta
455 | if ($valid == true){
456 |
457 | $usuario = Usuario::find($id); // busca la id en la tabla usuarios
458 | if ($usuario){
459 |
460 | /*
461 | si el usuario es encontrado, manda una respuesta con éste
462 | y lo renderiza en el template usuario.twig
463 | */
464 |
465 | return $this->view->render($response, 'usuario.twig', $usuario);
466 | } else {
467 |
468 | /*
469 | Si no hay un usuario con la id de los parametros, entonces obtiene la uri de la solicitud,
470 | redirecciona a la lista de usuarios y regresa una respuesta con la uri y un status 404 (not found)
471 | */
472 |
473 | $status = 404;
474 | $uri = $request->getUri()->withQuery('')->withPath($this->router->pathFor('listaUsuarios'));
475 | return $response->withRedirect((string)$uri, $status);
476 | } else {
477 | // si la validación es falsa, regresa un error de bad request
478 | return $response->withStatus(400);
479 | }
480 | }
481 | ```
482 | #### Actualizar
483 | Ejemplo de una función para actualizar un usuario.
484 | ```php
485 | /**
486 | * Actualiza un usuario
487 | * @param type Slim\Http\Request $request - la solicitud http
488 | * @param type Slim\Http\Response $response - la respuesta http
489 | * @param type array $args - argumentos para la función
490 | */
491 | public function actualiza($request, $response, $args)
492 | {
493 | // busca un usuario la id del arreglo de parametros en la tabla usuarios
494 | $usuario = Usuario::find((int)$args['id']);
495 |
496 | if(!$usuario){
497 | /*
498 | Si no hay un usuario con la id de los parametros, entonces obtiene la uri de la solicitud,
499 | redirecciona a la lista de usuarios y regresa una respuesta con la uri y un estado 404 (not found)
500 | */
501 | $status = 404;
502 | $uri = $request->getUri()->withQuery('')->withPath($this->router->pathFor('listaUsuarios'));
503 | return $response->withRedirect((string)$uri, $status);
504 | } else{
505 | $data = $request->getParsedBody(); // guarda los argumentos de la solicitud en un arreglo
506 | $validaciones = $this->valida($data); // valida los datos
507 | if (verifica($validaciones)){
508 | $usuario->update($data); // Eloquent actualiza la información en la tabla
509 |
510 | // regresa una respuesta con la uri y redirecciona a la vista especifica del usuario
511 | $uri = $request->getUri()->withQuery('')->withPath($this->router->pathFor('usuario', ['id' => $usuario->id]));
512 | return $response->withRedirect((string)$uri);
513 | }
514 | }
515 | }
516 | ```
517 |
518 | #### Eliminar
519 |
520 | Eloquent cuenta con tres maneras de eliminar elementos de una tabla: la primera es eliminar una instancia del modelo de la que no se conoce su llave primaria, esta usa la función `delete` pero su desventaja es que tiene que recuperar todo la instancia antes de llamar a `delete`; la segunda es, suponiendo que se conoce la llave primaria del modelo, llama la función `destroy` que elimina el modelo sin tener que recuperar la instancia completa; la tercera opción es mediante consultas, por ejemplo `$eliminados = Usuario::where('nombre','like','C%')->delete();` eliminaría a todos los usuarios cuyo nombre empiece con "C". Adicionalmente, Eloquent cuenta con _soft deleting_, es decir, el modelo no se borra de la base de datos, sino que se le agrega un atributo `deleted_at` y que, según recomiendan los desarrolladores de Laravel, debería ser agregada una columna a la tabla para que contenga dichos atributos.
521 | Para habilitar el método _soft deleting_ en la aplicación se debe agregar la clase `Illuminate\Database\Eloquent\SoftDeletes` en los modelos de la app.
522 | El siguiente ejemplo usa `delete` para hacer validaciones y darle más robustez antes de eliminar los modelos, eres libre de usar cualquiera de las opciones disponibles.
523 |
524 | ```php
525 | /**
526 | * Elimina un usuario
527 | * @param type Slim\Http\Request $request - la solicitud http
528 | * @param type Slim\Http\Response $response - la respuesta http
529 | * @param type array $args - argumentos para la función
530 | */
531 | public function elimina($request, $response, $args)
532 | {
533 | $usuario = Usuario->find($args['id']);
534 | $validaID = [v::intVal()->validate($id)];
535 | if($usuario && $validaID){
536 | // si existe el usuario y la validación es correcta, lo elimina
537 | $usuario->delete();
538 | }
539 | /*
540 | regresa una respuesta con la uri y redirecciona a la lista de usuarios,
541 | se haya o no eliminado el usuario
542 | */
543 | $uri = $request->getUri()->withQuery('')->withPath($this->router->pathFor('listaUsuarios'));
544 | return $response->withRedirect((string)$uri);
545 |
546 | }
547 |
548 | ```
549 | ### Rutas
550 |
551 | La implementación de rutas de Slim fue construida a partir de **FastRoute**[5](#foot5) y provee de métodos para poder trabajar con los métodos HTTP más comunmente usados, es decir _GET_, _POST_, _PUT_, _DELETE_, _PATCH_, _OPTIONS_ que pueden manejarse uno por uno o todos de manera generar con el método `any()`de Slim. Además, es posible manejar varios métodos en una sola ruta usando la función `map()`.
552 | En nuestra aplicación, las rutas se encuentran en el archivo `src/routes.php` que contiene la ruta que carga la vista de la página inicial del esqueleto, no la necesitamos entonces puedes quitarla o comentarla para guiarte al crear las demás rutas. Usaremos los métodos _GET_ para cargar vistas y ver usuarios, _POST_ para crear usuarios, _PATCH_ para actualizar un usuario y _DELETE_ para eliminar.
553 |
554 | #### GET
555 | Las rutas que solo manejar solicitudes HTTP _GET_ usan el método `get()` de Slim, que recibe como argumentos un patrón de ruta (con marcadores de posición opcionales) y una función callback que puede provenir de un controlador o declararse dentro de la misma ruta.
556 |
557 | ```php
558 | $app->get('/', function($request, $response, $args){
559 | return $this->view->render($response, "index.twig");
560 | })->setName('inicio');
561 | ```
562 | Lo que hace esta ruta es, para el patrón "/" (que sería el patrón inicial del servidor) llamar a una función que regrese como respuesta la vista definida en el template `index.twig` y a esta ruta le asigna el nombre "inicio" para que las vistas puedan interpretarlas más fácilmente.
563 |
564 | ```php
565 | // ruta para cargar la vista de todos los usuarios registrados
566 | $app->get('/listaUsuarios', function ($request, $response, $args){
567 | return $this->view->render($response, 'listaUsuarios.twig');
568 | })->setName('listaUsuarios');
569 |
570 | /*
571 | ruta para cargar la vista de un usuario en especifico definido por su id
572 | empleando la función buscaUsuarioID() de la clase ControladorUsuario,
573 | previamente agregada al CID de la aplicación
574 | */
575 | $app->get('/listaUsuarios/{id}','ControladorUsuario:buscaUsuarioID')->setName('usuario.ver');
576 |
577 | // ruta para cargar el formulario para crear usuario
578 | $app->get('/nuevo', function($request, $response, $args){
579 | return $this->view->render($response, 'formulario_crea.twig');
580 | })->setName('usuario.crear');
581 |
582 | // ruta para cargar el formulario para actualizar usuario
583 | $app->get('/listaUsuarios/{id}/actualiza', function($request, $response, $args){
584 | return $this->view->render($response, 'formulario_actualiza.twig');
585 | })->setName('usuario.editar');
586 |
587 | ```
588 |
589 | #### POST
590 |
591 | Al igual que con las solicitudes _GET_, Slim cuenta con una función llamada `post()` para manejar las solicitudes _POST_. Esta función también recibe como parametros el patrón de la ruta (con marcadores de posición opcionales) y una función callback.
592 |
593 | ```php
594 | // ruta para crear un nuevo usuario
595 | $app->post("/nuevo", "ControladorUsuario:crea");
596 | ```
597 | Se puede notar que esta ruta no uso la función `setName()` pues al haber ya una ruta con el mismo patrón ("/nuevo") pero usando distintos métodos, ambas pueden compartir el mismo nombre.
598 |
599 | #### PATCH
600 |
601 | Para _PATCH_ también se cumple lo mencionado antes para _GET_ y _POST_. Entonces, para actualizar, tendríamos algo de este estilo:
602 | ```php
603 | // ruta para actualizar un usuario
604 | $app->patch('listaUsuarios/{id}', 'ControladorUsuario:actualiza')->setName('usuario.actualizar');
605 | ```
606 | #### DELETE
607 |
608 | ```php
609 | // ruta para eliminar un usuario
610 | $app->delete('listaUsuario/{id}', 'ControladorUsuario:elimina')->setName('usuario.eliminar');
611 | ```
612 |
613 | ### Vista
614 | Ya sabemos que Slim no cuenta nativamente con una herramienta para generar las plantillas de sus vistas y, de hecho, las vistas solo son parte del cuerpo de las respuestas HTTP de PSR-7 que implementa Slim por lo que dependen necesariamente de las rutas. Sin embargo, pueden proveerse mediante **Composer** de componentes para dicho fin y ellos mismos proporcionan las implementaciones de dos de estos componentes, **Twig** y **PHP-View**. Personalmente prefiero Twig ya que me causó menos problemas y en general tiene una estructura más clara pues su síntaxis está basada en jinja y django templates. Por supuesto que, como todo en Slim, el uso de los componentes es cuestión de gustos y pueden manejarse otras herramientas para generar nuestras vistas.
615 |
616 | Primero, y al igual que con el resto de dependencias, agregaremos **Twig** usando **Composer**.
617 | ```
618 | $ composer require slim/twig-view
619 | ```
620 |
621 | **Nota**: si quieres usar **PHP-View** en vez de **Twig** solo sustituye `slim/twig-view` por `slim/php-view`
622 |
623 | Después de instalar **Twig** hay que agregarlo también al _CID_ de la aplicación para que Slim lo registre como uno de los servicios y puede utilizarlo.
624 |
625 | ```php
626 |
627 | $container['view'] = function ($c) {
628 | $settings = $c->get('settings')['renderer']; //nos indica el directorio donde están las plantillas
629 | $view = new Slim\Views\Twig($settings['template_path'], [
630 | 'cache' => false,]); // puede ser false o el directorio donde se guardará la cache
631 |
632 | // instancia y añade la extensión especifica de slim
633 | $basePath = rtrim(str_ireplace('index.php', '', $c['request']->getUri()->getBasePath()), '/');
634 | $view->addExtension(new Slim\Views\TwigExtension($c['router'], $basePath));
635 |
636 | return $view;
637 | };
638 |
639 | ```
640 | En una estructura básica de **Twig** nos encontraremos con 3 tipos de delimitadores:
641 | - {% ... %}, usado para ejecutar sentencias como estructuras de control, o crear bloques.
642 | - {{ ... }}, usado para mostrar el contenido de variables o el resultado de la evaluación de una expresion.
643 | - {# ... #}, usado para comentarios en las plantillas
644 |
645 | Como el diseño de **Twig** se basa en plantillas, podemos crear una plantilla base `layout.twig` y heredarla al resto de plantillas.
646 |
647 | ```php
648 |
649 |
650 |
651 |
652 | CRUD SLIM
653 |
654 |
655 |
656 | {% block stylesheets %}
657 |
658 | {# Aquí incluimos los archivos CSS o CDN de CSS que usemos #}
659 |
660 |
661 | {# la función base_url() le indica a twig que busque desde el directorio raíz de proyecto #}
662 |
663 |
664 |
665 | {% endblock %}
666 |
667 | {%block scripts }
668 |
669 | {# Aqui incluimos los .js y otros scripts
670 |
671 |
672 | {% endblock %}
673 |
674 |
675 | {% block content %}{% endblock %}
676 |
677 |
678 |
679 |
680 | ```
681 | Podemos tener las plantillas que hereden de `layout.twig` en otro directorio, por ejemplo `templates/crud` para mantener organizada la jerarquía entre estas.
682 |
683 | Si recordamos las [rutas](#rutas), la vista que carga al iniciar la aplicación es `index.twig` que tendría una estructura como la siguiente:
684 |
685 | ```php
686 |
687 | {% extends 'layout.twig' %}
688 |
689 | {% block content %}
690 |
691 | {# la función path_for('') llama la ruta con el nombre que recibe como parametro #}
692 | Lista los usuarios registrados
693 | Agrega un nuevo usuario
694 |
695 | {% endblock %}
696 |
697 | ```
698 |
699 | Estructura de `formulario_crea.twig`
700 |
701 |
702 | ```php
703 |
704 | {% extends 'layout.twig' %}
705 |
706 | {% block content %}
707 |
708 | {# manda los datos del formulario a la ruta 'usuario.crear' con un método post #}
709 |