├── resources └── images │ ├── 1.png │ ├── 2.png │ ├── hvsf.png │ ├── favicon.png │ └── esqueleto.png ├── .gitignore └── README.md /resources/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayovg/Slim-CRUD/HEAD/resources/images/1.png -------------------------------------------------------------------------------- /resources/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayovg/Slim-CRUD/HEAD/resources/images/2.png -------------------------------------------------------------------------------- /resources/images/hvsf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayovg/Slim-CRUD/HEAD/resources/images/hvsf.png -------------------------------------------------------------------------------- /resources/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayovg/Slim-CRUD/HEAD/resources/images/favicon.png -------------------------------------------------------------------------------- /resources/images/esqueleto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayovg/Slim-CRUD/HEAD/resources/images/esqueleto.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | composer* 3 | Manual* 4 | *.jpg 5 | *png 6 | *.tar* 7 | Skeleton* 8 | *zip 9 | UPRS.jar 10 | *presentacion* 11 | *.sh 12 | README.html* 13 | *.svg 14 | *.pptx 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

Slim Micro Framework

3 |

Manual para hacer CRUD

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 | vista inicial del esqueleto de Slim 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 | Creación de base de datos 161 | 162 | Creamos la tabla de usuarios: 163 | Creación de tabla usuarios 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 |
710 | 713 | 716 |