# Ejercicios 5

En esta sección de ejercicios vamos a terminar la web de gestión del videoclub añadiendo notificaciones, el funcionamiento de algunos botones que faltaban y una API tipo RESTful para permitir el acceso externo.

## Ejercicio 5.1 - Notificaciones

En este primer ejercicio vamos a instalar una librería externa para mostrar las notificaciones de nuestra aplicación, para esto tenéis que seguir los pasos indicados en el apartado de teoría "Ejemplo: instalación de paquete de notificaciones".

Una vez instalado y correctamente configurado vamos a modificar los controladores para mostrar un aviso tipo `success` después de guardar y editar una película. La notificación se tendrá que añadir antes de realizar la redirección. Le podéis poner los textos: "La película se ha guardado/modificado correctamente".

Por último vamos a modificar la vista con el _layout_ principal, situada en `resources/views/layouts/master.blade.php`, para indicar que se muestren las notificaciones justo antes del contenido principal:

```php
<div class="container">
    @include('alert::alert')

    @yield('content')
</div>
```

## Ejercicio 5.2 - Completando botones

En este ejercicio vamos añadir la funcionalidad de los botones de alquilar, devolver y eliminar película. Todos estos botones están situados en la vista detalle de una película (el de eliminar lo tendremos que añadir). En todos los casos tendremos que crear una nueva ruta, un nuevo método en el controlador, actualizar el botón en la vista y mostrar una notificación después de realizar la acción. En la siguiente tabla se muestra un resumen de las nuevas rutas a añadir:

| Ruta                   | Tipo   | Controlador / Acción                        |
| ---------------------- | ------ | ------------------------------------------- |
| `/catalog/rent/{id}`   | PUT    | `[CatalogController::class, 'putRent']`     |
| `/catalog/return/{id}` | PUT    | `[CatalogController::class, 'putReturn']`   |
| `/catalog/delete/{id}` | DELETE | `[CatalogController::class, 'deleteMovie']` |

En primer lugar tenéis que añadir las rutas al fichero `routes/web.php` y posteriormente modificar el controlador `CatalogController` para añadir los tres nuevos métodos. Estos tres métodos son similares al método que ya habíamos implementado antes para editar los datos de una película. En el caso de `putRent` y `putReturn` únicamente modificaremos el campo `rented` asignándole el valor _true_ y _false_ respectivamente, y una vez guardado crearemos la notificación y realizaremos una redirección a la pantalla con la vista detalle de la película. En el método `deleteMovie` también obtendremos el registro de la película pero tendremos que llamar al método `delete()` de la misma, una vez hecho esto añadiremos la notificación y realizaremos una redirección al listado general de películas.

A continuación tenemos que editar la vista detalle de películas para modificar los botones (`resources/views/catalog/show.blade.php`). Dado que la acciones se tienen que realizar usando peticiones HTTP tipo PUT y DELETE no podemos poner un enlace normal (ya que este sería tipo GET). Para solucionarlo tenemos que crear un formulario alrededor del botón y asignar al formulario el método correspondiente, por ejemplo:

```markup
<form action="{{action([App\Http\Controllers\CatalogController::class, 'putReturn'], ['id' => $pelicula->id])}}" 
    method="POST" style="display:inline">
    @method('PUT')
    @csrf
    <button type="submit" class="btn btn-danger" style="display:inline">
        Devolver película
    </button>
</form>
```

## Ejercicio 5.3 - Api RESTful y pruebas

En este ejercicio vamos a crear una API tipo _RESTful_ para permitir el acceso y gestión del catálogo del videoclub de forma externa. En la siguiente tabla se muestra el listado de todas las rutas que vamos a definir para la API:

| Ruta                          | Método | Filtro            | Controlador / Método             |
| ----------------------------- | ------ | ----------------- | -------------------------------- |
| `/api/v1/catalog`             | GET    |                   | `APICatalogController@index`     |
| `/api/v1/catalog/{id}`        | GET    |                   | `APICatalogController@show`      |
| `/api/v1/catalog`             | POST   | `auth.basic.once` | `APICatalogController@store`     |
| `/api/v1/catalog/{id}`        | PUT    | `auth.basic.once` | `APICatalogController@update`    |
| `/api/v1/catalog/{id}`        | DELETE | `auth.basic.once` | `APICatalogController@destroy`   |
| `/api/v1/catalog/{id}/rent`   | PUT    | `auth.basic.once` | `APICatalogController@putRent`   |
| `/api/v1/catalog/{id}/return` | PUT    | `auth.basic.once` | `APICatalogController@putReturn` |

Como se ve en la tabla, tenemos que definir todas las rutas _RESTful_ para el catálogo, además de dos especiales: `/rent` y `/return`. Todas las rutas estarán protegidas con contraseña (usando autenticación HTTP básica **sin estado**) a excepción de `index` y `show` que serán públicas. Tenéis que comprobar que las rutas y filtros sean los correctos usando el método de Artisan `php artisan route:list`.

> Pista 1: Recuerda que las rutas de una API las tienes que definir dentro del fichero de rutas `routes/api.php` y que al incluirlas dentro de este fichero automáticamente se añade el prefijo `api`, por lo que en este caso tendrás que indicar la URL solamente a partir de `v1`.
>
> Pista 2: El _middleware_ "auth.basic.once" de autenticación básica sin estado no viene definido con Laravel por defecto. Para añadirlo tenéis que seguir las instrucciones indicadas en el apartado "Autenticación HTTP básica sin estado" de la teoría.
>
> Pista 3: Para poder aplicar un filtro solamente a algunos de los métodos del controlador tendréis que separar la declaración de las rutas. Para esto podéis utilizar el tercer parámetro con las opciones `only` y `except`.

A continuación tenéis que añadir el nuevo controlador `APICatalogController` usando el comando de Artisan que genera el controlador de recurso junto con todos los métodos RESTful. Las acciones y contenidos de los métodos serán muy similares a los de `CatalogController`, pero teniendo en cuenta que **no** tendremos que devolver una vista sino directamente el contenido de la consulta en formato JSON. Por ejemplo, el método que devuelve el listado de todas las películas sería simplemente:

```php
public function index() {
    return response()->json( Movie::all() );
}
```

Para devolver una respuesta en los métodos que realizan alguna acción (por ejemplo, para indicar que la película se ha marcado como alquilada o que se ha modificado correctamente) podemos realizar lo siguiente:

```php
public function putRent($id) {
    $m = Movie::findOrFail( $id );
    $m->rented = true;
    $m->save();
    return response()->json( ['error' => false,
                          'msg' => 'La película se ha marcado como alquilada' ] );
}
```

Por último, utiliza `cURL` para comprobar que todas las rutas que has creado funcionan correctamente. Recuerda que puedes especificar el método HTTP a utilizar mediante el parámetro `-X`, las cabeceras de la petición con el parámetro `-H` y el contenido a enviar con `-d`, por ejemplo:

```bash
curl -i -H "Accept: application/json" -H "Content-Type: application/json" 
        -X PUT -d '{"title":"nuevo titulo"}' http://localhost:8000/api/v1/catalog/21
```

> Aviso: hemos de tener cuidado con el método de actualizar los datos de una película ya que los campos que no se envíen se asignarán como vacíos. Para solucionar esto podemos actualizar solamente los campos que contengan algún valor o enviar siempre todos los campos.
