View on GitHub

apunts

Apunts DWES

Exemple

Videoclub

Com a exemple anem a desenvolupar una xicoteta web per a la gestió interna d’un videoclub, començarem per definir les rutes i vistes del lloc i a poc a poc en els següents exercicis l’anirem completant fins a acabar el lloc web complet.

L’objectiu és realitzar un lloc web per a la gestió interna en un videoclub, el qual estarà protegit mitjançant usuari i contrasenya. Una vegada autoritzat l’accés, l’usuari podrà llistar el catàleg de pel·lícules, veure informació detallada d’una pel·lícula, realitzar cerques o filtrats i algunes operacions més de gestió.

Definició de les rutes

Video

En aquest exercici anem a definir les rutes principals que va a tenir el nostre lloc web. Per a començar simplement indicarem que les rutes retornen una cadena (així podrem comprovar que s’han creat correctament). A continuació s’inclou una taula amb les rutes a definir (totes de tipus GET) i el text que han de mostrar:

Ruta Text a mostrar
/ Pantalla principal
login Login usuari
logout Logout usuari
catalog Llistat pel·lícules
catalog/show/{id} Vista detall pel·lícula {id}
catalog/create Afegir pel·lícula
catalog/edit/{id} Modificar pel·lícula {id}
Solució:
   Route::get('/', function () { return 'Pagina principal';});
    Route::get('login', function () { return 'Login usuari';});
    Route::get('logout', function () { return 'Logout usuari';});
    Route::get('catalog', function () { return 'Llistat pel.licules';});
    Route::get('catalog/show/{id}', function () { return "Vista detall pel.licula $id";});
    Route::get('catalog/create', function () { return 'Afegir pel.licula';});
    Route::get('catalog/edit/{id}', function () {return "Modificar pel.licula $id";});

Per a comprovar que les rutes s’hagen creat correctament utilitza el comando de artisan que retorna un llistat de rutes i a més prova també les rutes en el navegador.

php artisan route:list

Layout principal de les vistes amb Bootstrap

En aquest exercici anem a crear el layout base que van a utilitzar la resta de vistes del lloc web i a més inclourem la llibreria Bootstrap per a utilitzar-la com a estil base. Laravel 5.8 ja inclou bootstrap però laravel 6.0 no. Així que cal instalar-lo:

Dels materials que ens hem descarregat copiem la plantilla per a la barra de navegació principal (navbar.blade.php) i l’emmagatzemem en la carpeta resources/views/partials. A continuació anem a crear el layout principal del nostre lloc:

Amb açò ja hem definit el layout principal, no obstant açò encara no podem provar-ho ja que no està associat a cap ruta.

Solució:
<!DOCTYPE html>
	<html lang="es">
	  <head>
	    <meta charset="utf-8">
	    <meta http-equiv="X-UA-Compatible" content="IE=edge">
	    <meta name="viewport" content="width=device-width, initial-scale=1">
	    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
	    <title>Video Club</title>
	    <meta name="csrf-token" content="{{ csrf_token() }}">
	    <!-- Bootstrap -->
	     <link href="{{ asset('css/app.css') }}" rel="stylesheet">
	  </head>
	  <body>
	    @include('partials.navbar')
	    <div id='app' class="container"> @yield('content')</div>
	   
	    <!-- Scripts -->
	    <script src="{{ asset('js/app.js') }}" ></script>
	  </body>
	</html>

Crear la resta de vistes

En aquest exercici anem acabar una primera versió estable de la web. En primer lloc crearem les vistes associades a cada ruta, les quals hauran d’estendre del layout que hem fet en l’exercici anterior i mostrar (en la secció de content del layout) el text d’exemple que havíem definit per a cada ruta en l’exercici 2. En general totes les vistes tindran un codi similar al següent (variant únicament la secció content):

@extends(‘layouts.master’)
@section('content')
 		Pantalla principal 
@stop

Per a organitzar millor les vistes les anem a agrupar en sub-carpetes dins de la carpeta resources/views seguint la següent estructura:

Vista Carpeta Ruta associada
home.blade.php resources/views/ /
login.blade.php resources/views/auth/ login
index.blade.php resources/views/catalog/ catalog
show.blade.php resources/views/catalog/ catalog/show/{ id}
create.blade.php resources/views/catalog/ catalog/ create
edit.blade.php resources/views/catalog/ catalog/edit/{id}

Creem una vista separada per a totes les rutes excepte para la ruta “ logout”, la qual no tindrà cap vista. Finalment anem a actualitzar les rutes del fitxer routes/web.php perquè es carreguen les vistes que acabem de crear. Acordar-vos que per a referenciar les vistes que estan dins de carpetes la barra / de separació es transforma en un punt, i que a més, com a segon paràmetre, podem passar dades a la vista. A continuació s’inclouen alguns exemples:

return view('home');
return view('catalog.index');
return view('catalog.show',array('id'=>$id));

Una vegada fets aquests canvis ja podem provar-ho en el navegador, el qual hauria de mostrar en tots els casos la plantilla base amb la barra de navegació principal i els estils de Bootstrap aplicats. En la secció principal de contingut de moment solament podrem veure els textos que hem posat d’exemple.

Solució:

web.php

	Route::get('/', function () { return view('home');});
	Route::get('login', function () {return view('login');});
	Route::get('logout', function () { return 'Logout usuari';});
	Route::get('catalog', function () { return view('index');});
	Route::get('catalog/show/{id}', function ($id) { return view('show',['pelicula'=>$id]);});
	Route::get('catalog/create', function () { return view('create');});
	Route::get('catalog/edit/{id}', function ($id) {return view('edit',['pelicula' =>$id]);});

edit.blade

	@extends('layouts.master')
	@section('content')
    	Editar pel.licula id {{$pelicula}}
	@stop

show.blade

	@extends('layouts.master')
	@section('content')
    	Mostrar pel.licula id {{$pelicula}}
	@stop

create.blade

	@extends('layouts.master')
	@section('content')
    	Crear pel.licula 
	@stop

home.blade

	@extends('layouts.master')
	@section('content')
    	Pagina principal 
	@stop

index.blade

	@extends('layouts.master')
	@section('content')
    	Catalogo
	@stop

login.blade

	@extends('layouts.master')
	@section('content')
    	Login
	@stop

Crear les proves

Crea un fitxer de proves en la consola del artisan

php artisan make:test BasicTest

Crea un prova per a comprobrar que va la pantalla d’inici:

public function testLoadHomePage(){ 
	$this->get('/')->assertStatus(200)->assertSee('Pantalla principal');
}

Comprova totes les vistes:

Solució
class BasicTest extends TestCase
{
    public function testLoadHomePage(){ 
        $this->get('/')->assertStatus(200)->assertSee('Pantalla principal');
    }
    public function testLoadCatalogPage(){ 
        $this->get('/catalog')->assertStatus(200)->assertSee('Catalogo');
    }
    public function testLoadCreatePage(){ 
        $this->get('/catalog/create')->assertStatus(200)->assertSee('Crear pel.licula');
    }
    public function testLoadEditPage(){ 
        $this->get('/catalog/edit/2')->assertStatus(200)->assertSee('Editar pel.licula id 2');
    }
    public function testLoadShowPage(){ 
        $this->get('/catalog/show/2')->assertStatus(200)->assertSee('Mostrar pel.licula id 2');
    }
}

Definint Controladors

Video

En aquest primer exercici anem a crear els controladors necessaris per a gestionar la nostra aplicació i a més actualitzarem el fitxer de rutes perquè els utilitze. Comencem per afegir els dos controladors que ens van a fer falta: CatalogController.php i HomeController.php. Per a açò heu d’utilitzar el comando de Artisan que permet crear un controlador buit (sense mètodes). A continuació anem a afegir els mètodes d’aquests controladors. En la següent taula resumeixen podem veure un llistat dels mètodes per controlador i les rutes que tindran associades:

Ruta Controlador Mètode
/ HomeController getHome
catalog CatalogController getIndex
catalog/show/{id} CatalogController getShow
catalog/create CatalogController getCreate
catalog/edit/{id} CatalogController getEdit

Acordeu-vos que els mètodes getShow i getEdit hauran de rebre com a paràmetre el $id de l’element a mostrar o editar, per la qual cosa la definició del mètode en el controlador haurà de ser com la següent:

public function getShow($id) {
return view('catalog.show', array('id'=>$id)); }

Finalment anem a canviar el fitxer de rutes routes/web.php per tal que totes les rutes que teníem definides (excepte les de login i logout que les deixarem com estan) apunten als nous mètodes dels controladors, per exemple:

Route::get('/', 'Homecontroller@gethome');

El codi que teníem posat per a cada ruta amb el return amb la generació de la vista ho heu de moure al mètode del controlador corresponent.

Comprova que les proves segueixen funcionant. En cas contrari corregeix les fallades.

routes.php

Route::get('/','homeController@getHome');
Route::get('login', function () {return view('login');});
Route::get('logout', function () { return 'Logout usuari';});
Route::get('catalog','catalogController@getIndex');
Route::get('catalog/show/{id}', 'catalogController@getShow');
Route::get('catalog/create','catalogController@getCreate');
Route::get('catalog/edit/{id}','catalogController@getEdit');
Renderitzant les vistes

catalogController.php

	<?php
	namespace App\Http\Controllers;
	use Illuminate\Http\Request;

	class catalogController extends Controller
	{
	    public function getIndex(){
	        return view('index');
	    }
	    public function getShow($id){
	        return view('show',['pelicula'=>$id]);
	    }
	    public function getCreate(){
	        return view('create');
	    }
	    public function getEdit($id){
	        return view('edit',['pelicula' =>$id]);
	    }
	}

homeController.php

<?php

	namespace App\Http\Controllers;
		
	use Illuminate\Http\Request;
		
	class homeController extends Controller
	{
	    public function getHome()
	    {
	        return redirect()->action('Catalogcontroller@getindex');
	    }
}

Completant les vistes

En aquest exercici anem a acabar els mètodes dels controladors que hem creat en l’exercici anterior i a més completarem les vistes associades:

Mètode Homecontroller@gethome

En aquest mètode de moment solament anem a fer una redirecció a l’acció que mostra el llistat de pel·lícules del catàleg:

return redirect()->action('Catalogcontroller@getindex'); 

Més endavant haurem de comprovar si l’usuari està logueado o no, i en cas que no l’aquest redirigir-li al formulari de login.

Mètode CatalogController@index

Aquest mètode ha de mostrar un llistat de totes les pel·lícules que té el videoclub. El llistat de pel·lícules ho podeu obtenir del fitxer array_peliculas.php facilitat amb els materials. Aquest array de pel·lícules ho heu de copiar com a variable membre de la classe (més endavant les emmagatzemarem en la base de dades). En el mètode del controlador simplement haurem de modificar la generació de la vista per a passar-li aquest array de pel·lícules complet ($this->arrayPeliculas).

I en la vista corresponent simplement haurem d’incloure el següent tros de codi en la seua secció content:

	<div class="row">
		@foreach( $arrayPeliculas as $key => $pelicula ) 		
			<div class="col-xs-6 col-sm-4 col-md-3 text-center">
				<a href="{{  url('/catalog/show/'.$key) }}">
					<img src="{{ $pelicula['poster']}}" style="height:200px"/> 
					<h4 style="min-height:45px;margin:5px 0 10px 0">
					{{ $pelicula['title']}} </h4>
				</a>
			</div> 
		@endforeach
	</div>

Com es pot veure en el codi, en primer lloc es crea una fila (usant el sistema de reixeta de Bootstrap) i a continuació es realitza un bucle foreach utilitzant la notació de Blade per a iterar per totes les pel·lícules. Per a cada pel·lícula obtenim la seua posició en el array i les seues dades associades, i generem una columna per a mostrar-los.

És important que ens fixem en com s’itera pels elements d’un array de dades i en la forma d’accedir als valors. A més s’ha inclòs un enllaç perquè en prémer sobre una pel·lícula ens porte a l’adreça /catalog/show/{$key}, sent key la posició d’aqueixa pel·lícula en el array.

Mètode Catalogcontroller@show

Aquest mètode s’utilitza per a mostrar la vista detall d’una pel·lícula. Hem de tenir en compte que el mètode corresponent rep un identificador que (de moment) es refereix a la posició de la pel·lícula en el array. Per tant, haurem d’agafar aquesta pel·lícula del array ($this->arrayPeliculas[$id]) i passar-li-la a la vista.

En aquesta vista anem a crear dues columnes, la primera columna per a mostrar la imatge de la pel·lícula i la segona per a incloure tots els detalls. A continuació s’inclou l’estructura HTML que hauria de tenir aquesta pantalla:

	<div class="row">
		<div class="col-sm-4">
			{{ -- TOT: Imatge de la pel·lícula --}}
		</div>
		<div class="col-sm-8">
			{{ -- TOT: Dades de la pel·lícula --}}
		</div> 
	</div>

En la columna de l’esquerra completem el TOT per a inserir la imatge de la pel·lícula. En la columna de la dreta s’hauran de mostrar totes les dades de la pel·lícula: títol, any, director, resum i el seu estat.

Per a mostrar l’estat de la pel·lícula consultarem el valor rented del array, el qual podrà tenir dos casos:

A més hem d’incloure dos botons més, un botó que ens portarà a editar la pel·lícula i un altre per a tornar al llistat de pel·lícules.

Nota: els botons de llogar/retornar de moment no han de funcionar. Acordeu-vos que en Bootstrap podem transformar un enllaç en un botó, simplement aplicant les classes “btn btn-default” (més info en). Aquesta pantalla finalment hauria de tenir una aparença similar a la següent:

Mètode Catalogcontroller@create

Aquest mètode retorna la vista “catalog.create” per a afegir una nova pel·lícula. Per a crear aquest formulari en la vista corresponent ens podem basar en el contingut de la plantilla “catalog_create.php”. Aquesta plantilla té una sèrie de ToDo’s que cal completar. En total haurà de tenir els següents camps:

Label Name Tipus de camp
Títol title text
Any year text
Director director text
Poster poster text
Resum synopsis textarea

A més tindrà un botó al final amb el text “Afegir pel·lícula”. De moment el formulari no funcionarà. Més endavant ho acabarem.

Mètode Catalogcontroller@edit

Aquest mètode permetrà modificar el contingut d’una pel·lícula. El formulari serà exactament igual al d’afegir pel·lícula, així que ho podem copiar i pegar en aquesta vista i simplement canviar els següents punts:

homeController.php

	<?php
	
	namespace App\Http\Controllers;
	
	use Illuminate\Http\Request;
	
	class HomeController extends Controller
	{
	    public function getHome(){
	        return redirect()->action('CatalogController@getIndex');
	    }
	}

catalogController.php

	..
	private $arrayPeliculas = ...
	
	public function index(){
        return view('index',['arrayPeliculas'=>$this->arrayPeliculas]);
    }
    public function show($id){
        $pelicula = $this->arrayPeliculas[$id];
        return view('show',compact('pelicula','id'));
    }
    public function create(){
        return view('create');
    }
    public function edit($id){
        return view('edit',['pelicula' =>$id]);
    }

show.blade.php

	@extends('layouts.master')
	@section('content')
	    <div class="row">
			<div class="col-sm-4">
	                    <img src="{{ $pelicula['poster']}}" alt="{{ $pelicula['title']}}"/>
			</div>
			<div class="col-sm-8">
	                    <h2>{{ $pelicula['title']}}</h2>
	                    <h4>{{ $pelicula['year']}}</h4>
	                    <h4>{{ $pelicula['director']}}</h4>
	                    <p><strong>Resumen: </strong>{{ $pelicula['synopsis']}}</p>
	                    <p><strong>Estado: </strong>Pel.lícula @if ($pelicula['rented'])  Actualment llogada @else disponible @endif</p>
	                    <p>
	                       @if ($pelicula['rented']) 
	                        <a href='' class="btn btn-info">Tornar Pel.lícula</a> 
	                       @else 
	                        <a href='' class="btn btn-danger">Llogar Pel.lícula</a>
	                       @endif 
	                       <a href="{{ route('catalog.edit',$id)}}" class="btn btn-warning"><i class="fa fa-pencil"></i>Editar Pel.lícula</a>
	                       <a href="\catalog" class="btn btn-default">Tornar catàleg</a>
	                    </p>
			</div> 
		</div>
	@stop

create.blade.php

	@extends('layouts.master')
	@section('content')
	<div class="row" style="margin-top:20px">
	    <div class="col-md-offset-3 col-md-6">
	        <div class="panel panel-default">
	            <div class="panel-heading">
	                <h3 class="panel-title text-center">
	                    <span class="glyphicon glyphicon-film" aria-hidden="true"></span>
	                    Afegir pel.lícula
	                </h3>
	            </div>
	            <div class="panel-body" style="padding:30px">
	                <form method='POST'>
	                    @csrf
	                    <div class="form-group">
	                        <label for="title">Título</label>
	                        <input type="text" name="title" id="title" class="form-control">
	                    </div>
	
	                    <div class="form-group">
	                        <label for='year'>Any:</label>
	                        <input type='number' name='year' />
	                    </div>
	                    <div class="form-group">
	                        <label for='director'>Director:</label>
	                        <input type='text' name='director' />
	                    </div>
	
	                    <div class="form-group">
	                        <label for='poster'>Poster:</label>
	                        <input type='url' name='poster' />
	                    </div>
	
	                    <div class="form-group">
	                        <label for="synopsis">Resumen</label>
	                        <textarea name="synopsis" id="synopsis" class="form-control" rows="3"></textarea>
	                    </div>
	
	                    <div class="form-group text-center">
	                        <button type="submit" class="btn btn-primary" style="padding:8px 100px;margin-top:25px;">
	                            Afegir pel.lícula
	                        </button>
	                    </div>
	                </form>
	            </div>
	        </div>
	    </div>
	</div>
	@stop

edit.blade.php

	@extends('layouts.master')
	@section('content')
	<div class="row" style="margin-top:20px">
	    <div class="col-md-offset-3 col-md-6">
	        <div class="panel panel-default">
	            <div class="panel-heading">
	                <h3 class="panel-title text-center">
	                    <span class="glyphicon glyphicon-film" aria-hidden="true"></span>
	                    Modificar pel.lícula
	                </h3>
	            </div>
	            <div class="panel-body" style="padding:30px">
	                <form method='POST'>
	                    @csrf
	                    @method('PUT')
	                    <div class="form-group">
	                        <label for="title">Título</label>
	                        <input type="text" name="title" id="title" class="form-control">
	                    </div>
	                    <div class="form-group">
	                        <label for='year'>Any:</label>
	                        <input type='number' name='year' />
	                    </div>
	                    <div class="form-group">
	                        <label for='director'>Director:</label>
	                        <input type='text' name='director' />
	                    </div>
	                    <div class="form-group">
	                        <label for='poster'>Poster:</label>
	                        <input type='url' name='poster' />
	                    </div>
	
	                    <div class="form-group">
	                        <label for="synopsis">Resumen</label>
	                        <textarea name="synopsis" id="synopsis" class="form-control" rows="3"></textarea>
	                    </div>
	                    <div class="form-group text-center">
	                        <button type="submit" class="btn btn-primary" style="padding:8px 100px;margin-top:25px;">
	                            Modificar pel.lícula
	                        </button>
	                    </div>
	                </form>
	            </div>
	        </div>
	    </div>
	</div>
	@stop

Modificant les proves

Perquè totes seguisquen funcionant.

class BasicTest extends TestCase
	{
	    public function testLoadHomePage(){ 
	        $this->get('/')->assertStatus(302);
	    }
	    public function testLoadCatalogPage(){ 
	        $this->get('/catalog')->assertStatus(200)->assertSee('Catàleg');
	    }
	    public function testLoadCreatePage(){ 
	        $this->get('/catalog/create')->assertStatus(200)->assertSee('Afegir pel.lícula');
	    }
	    public function testLoadEditPage(){ 
	        $this->get('/catalog/edit/2')->assertStatus(200)->assertSee('Modificar pel.lícula');
	    }
	    public function testLoadShowPage(){ 
	        $this->get('/catalog/show/2')->assertStatus(200)->assertSee('Editar Pel.lícula');
	    }
	}

Configuració de la base de dades

Video

En primer lloc anem a configurar correctament la base de dades. Per a açò hem d’actualitzar els fitxers config/database.php i .env per a indicar que anem a usar una base de dades tipus MySQL cridada “videoclub” juntament amb el nom d’usuari i contrasenya d’accés (homestead i secret)

A continuació obrim PHPMyAdmin i creem una nova base de dades anomenada videoclub. Per a comprovar que tot s’ha configurat correctament anem a un terminal en la carpeta del nostre projecte i executem el comando que crea la taula de migracions.

Si tot va bé podrem actualitzar des de PHPMyAdmin i comprovar que s’ha creat aquesta taula dins de la nostra nova base de dades.

Si ens donara algun error haurem de revisar els valors indicats en el fitxer .env.

Ara anem a crear la taula que utilitzarem per a emmagatzemar el catàleg de pel·lícules. Executa el comando de Artisan per a crear la migració anomenada create_movies_table per a la taula movies.

Una vegada creat edita aquest fitxer per a afegir tots els camps necessaris, aquests són:

Camp Tipus Valor per defecte
id Autoincremental  
title String  
year String de longitud 8  
director String de longitud 64  
poster String  
rented Booleà false
synopsis Text  
timestamps Timestamps de Eloquent  

Recorda que en el mètode down de la migració has de desfer els canvis que has fet en el mètode up, en aquest cas seria eliminar la taula.

Finalment executarem el comando de Artisan que afig les noves migracions i comprovarem en PHPMyAdmin que la taula s’ha creat correctament amb els camps que li hem indicat.

.env

...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=videoclub
DB_USERNAME=homestead
DB_PASSWORD=secret
...

create_movies_table.php


<?php
	
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
	
class CreateMoviesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('movies', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('year',8);
            $table->string('director',64);
            $table->string('poster');
            $table->boolean('rented')->default(false);
            $table->text('synopsis');
            $table->timestamps();
        });
    }
	
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('movies');
    }
}

Model de dades

Video

Anem a crear el model de dades associat amb la taula movies. Per a açò usarem el comando apropiat de Artisan per a crear el model anomenat Movie.

Una vegada creat aquest fitxer ho obrirem i comprovarem que el nom de la classe siga el correcte i que herete de la classe Model. I ja està, no és necessari fer res més, el cos de la classe pot estar buit ({}), tot la resta es fa automàticament!

Seeders

Ara anem a procedir a emplenar la taula de la base de dades amb les dades inicials. Per a açò editem el fitxer de llavors situat en database/seeds/DatabaseSeeder.php i seguirem els següents passos:

public function run() {
	self::seedCatalog();
	$this->command->info('Taula catàleg inicialitzada amb dades!'); 
}
foreach( $this->arrayPeliculas as $pelicula) { 
	$p = new Movie;
	$p->title = $pelicula['title'];
	$p->year = $pelicula['year'];
	$p->director = $pelicula['director']; 
	$p->poster = $pelicula['poster']; 
	$p->rented = $pelicula['rented']; 
	$p->synopsis = $pelicula['synopsis']; 
	$p->save();
}

Finalment haurem d’executar el comando de Artisan que processa les llavors i una vegada realitzat obrirem PHPMyAdmin per a comprovar que s’emplenat la taula movies amb el llistat de pel·lícules.

Si t’apareix l’error “Fatal error: Class ‘Movie’ not found” revisa si has indicat l’espai de noms del model que vas a utilitzar (use App\Movie;).


use Illuminate\Database\Seeder;
use App\Movie;

class DatabaseSeeder extends Seeder
{
private $arrayPeliculas = 
..
public function run()
	    {
	        self::seedCatalog();
	        $this->command->info('Taula catàleg inicialitzada amb dades!');
	    }
	
	    
    private function seedCatalog()
    {
        DB::table('movies')->delete();

        foreach ($this->arrayPeliculas as $pelicula) {
            $p = new Movie;
            $p->title = $pelicula['title'];
            $p->year = $pelicula['year'];
            $p->director = $pelicula['director'];
            $p->poster = $pelicula['poster'];
            $p->rented = $pelicula['rented'];
            $p->synopsis = $pelicula['synopsis'];
            $p->save();
        }
    }
}    

Ús de la base de dades

Anem a actualitzar els mètodes del controlador CatalogController perquè obtinguen les dades des de la base de dades. Seguirem els següents passos:

Si en provar-ho t’apareix l’error “Class ‘Videoclub\Http\Controllers\Movie’ not found” revisa si has indicat l’espai de noms del model que vas a utilitzar (use Videoclub\Movie;).

Ja no necessitarem més el array de pel·lícules ($arrayPeliculas) que havíem posat en el controlador, així que ho podem comentar o eliminar.

Ara haurem d’actualitzar les vistes perquè en lloc d’accedir a les dades del array els obtinga de l’objecte amb la pel·lícula. Per a açò canviarem en tots els llocs on hàgem posat $pelicula[‘camp’] per $pelicula->camp.

A més, en la vista catalog/index.blade.php, en comptes d’utilitzar l’índex del array ($key) com a identificador per a crear l’enllaç a catalog/show/{id}, haurem d’utilitzar el camp id de la pel·lícula ($pelicula->id). El mateix en la vista catalog/show.blade.php, per a generar l’enllaç d’editar pel·lícula haurem d’afegir l’identificador de la pel·lícula a la ruta catalog/edit.

catalogController.php

	use Illuminate\Http\Request;
	use App\Movie;
	
	class CatalogController extends Controller
	{
	    public function getIndex(){
	        $arrayPeliculas = Movie::all();
	        return view('index',compact('arrayPeliculas'));
	    }
	    public function getShow($id){
	        $pelicula = Movie::findOrFail($id);
	        return view('show',compact('pelicula'));
	    }
	    public function getCreate(){
	        return view('create');
	    }
	    public function getEdit($id){
	        $pelicula = Movie::findOrFail($id);
	        return view('edit',compact('pelicula'));
	    }
	}

index.blade.php

	@extends('layouts.master')
	@section('content')
	<h2 >Catàleg</h2>
	    <div class="row">
	    @foreach( $arrayPeliculas as $pelicula )        
	        <div class="col-xs-6 col-sm-4 col-md-3 text-center">
	            <a href="{{ url('/catalog/show/'.$pelicula->id) }}">
	                <img src="{{$pelicula['poster']}}" style="height:200px"/> 
	                <h4 style="min-height:45px;margin:5px 0 10px 0">
	                {{$pelicula->title}} </h4>
	            </a>
	        </div> 
	    @endforeach
	    </div>  
	@stop

show.blade.php

	@extends('layouts.master')
	@section('content')
	    <div class="row">
			<div class="col-sm-4">
	                    <img src="{{$pelicula->poster}}" alt="{{$pelicula->title}}"/>
			</div>
			<div class="col-sm-8">
	                    <h2>{{$pelicula->title}}</h2>
	                    <h4>{{$pelicula->year}}</h4>
	                    <h4>{{$pelicula->director}}</h4>
	                    <p><strong>Resumen: </strong>{{$pelicula->synopsis}}</p>
	                    <p><strong>Estado: </strong>Pel.lícula @if ($pelicula->rented)  Actualment llogada @else disponible @endif</p>
	                    <p>
	                       @if ($pelicula->rented) 
	                        <a href='' class="btn btn-info">Tornar Pel.lícula</a> 
	                       @else 
	                        <a href='' class="btn btn-danger">Llogar Pel.lícula</a>
	                       @endif 
	                       <a href="\catalog\edit\{{$pelicula->id}}" class="btn btn-warning"><i class="fa fa-pencil"></i>Editar Pel.lícula</a>
	                       <a href="\catalog" class="btn btn-default">Tornar catàleg</a>
	                    </p>
			</div> 
		</div>
	@stop

Afegir i editar pel·lícules

Video

En primer lloc anem a afegir les rutes que ens van a fer falta per a arreplegar les dades en enviar els formularis. Per a açò editem el fitxer de rutes i afegim dues rutes (també protegides pel filtre auth):

A continuació anem a editar la vista catalog/edit.blade.php amb els següents canvis:

** web.php **

	Auth::routes();
	Route::get('/','HomeController@getHome');
	Route::group(['middleware'=>'auth'],function(){
	    Route::get('/logout','Auth\Logincontroller@logout');
	    Route::get('catalog','CatalogController@getIndex');
	    Route::get('catalog/show/{id}', 'CatalogController@getShow');
	    Route::get('catalog/create','CatalogController@getCreate');
	    Route::post('catalog/create','CatalogController@postCreate');
	    Route::get('catalog/edit/{id}','CatalogController@getEdit');
	    Route::put('catalog/edit/{id}','CatalogController@putEdit');
	});

** HomeController **

	<?php
	
	namespace App\Http\Controllers;
	
	use Illuminate\Http\Request;
	use Illuminate\Support\Facades\Auth;
	
	class HomeController extends Controller
	{
	    
	    public function getHome()
	    {
	        if (Auth::user())
	            return redirect()->action('CatalogController@getIndex');
	        else 
	            return redirect('login');
	    }
	}

** CatalogController **

	<?php
	
	namespace App\Http\Controllers;
	
	use Illuminate\Http\Request;
	use App\Movie;
	
	class CatalogController extends Controller
	{
	    public function getIndex(){
	        $arrayPeliculas = Movie::all();
	        return view('index',compact('arrayPeliculas'));
	    }
	    public function getShow($id){
	        $pelicula = Movie::findOrFail($id);
	        return view('show',compact('pelicula'));
	    }
	    public function getCreate(){
	        return view('create');
	    }
	    public function postCreate(Request $request){
	        $movie = new Movie();
	        $movie->title = $request->title;
	        $movie->year = $request->year;
	        $movie->director = $request->director;
	        $movie->poster = $request->poster;
	        $movie->synopsis = $request->synopsis;
	        $movie->save();
	        return redirect('/catalog');
	    }
	    public function getEdit($id){
	        $pelicula = Movie::findOrFail($id);
	        return view('edit',compact('pelicula'));
	    }
	    public function putEdit(Request $request,$id){
	        $movie = Movie::findOrFail($id);
	        $movie->title = $request->title;
	        $movie->year = $request->year;
	        $movie->director = $request->director;
	        $movie->poster = $request->poster;
	        $movie->synopsis = $request->synopsis;
	        $movie->save();
	        return redirect("/catalog/show/$id");
	    }
	}

Validació Formulari

Video

Proves

Ara fallen totes les proves en les quals hem d’estar autenticats. Per a corregir açò hem d’executar el get una vegada que ens hàgem loguejat. Per a fer açò tenim actuar com un usuari.

private function defaultUser(){ 
	return User::find(1);
}

public function testLoadCreatePage(){ 
   $this->actingAs($this->defaultUser())->get('/catalog/create')->assertStatus(200)->assertSee('Afegir pel.lícula');
}

Fes que totes les proves tornen a funcionar.

Instal.lació de paquets

Video

Els paquets són la manera primària d’afegir funcionalitat a Laravel. Els paquets podrien ser qualsevol cosa d’una manera: des de un gran de treballar amb dates com Carbon, o un marc de testatge de BDD sencer com Behat.

Naturalment, hi ha tipus diferents de paquets. Alguns paquets són independent del framework, treballen amb qualsevol marc de PHP. Qualssevol d’aquests paquets poden ser utilitzats amb Laravel afegint-los dins el vostre arxiu composer.json o amb composer require

D’altra banda, altres paquets són per ús amb Laravel. Aquests paquets poden tenir rutes, controladors, vistes, i la configuració concretament per a Laravel.

Exemple: StydeNet Html package

Aquest paquet conté una col·lecció de classes de PHP per generar components d’HTML comú, com:

És una extensió del paquet HTML de Laravel Colective i serà molt útil per generar formularis i HTML dinàmicament.

Aquest middleware és necessitat per fer els missatges d’alerta persistents entre sessions, després de que cada petició és completada.

Ara tindràs automàticament disponibles el següents components:

Alert => Styde\Html\Facades\Alert
Field => Styde\Html\Facades\Field
Menu  => Styde\Html\Facades\Menu
Form  => Collective\Html\FormFacade
Html  => Collective\Html\HtmlFacade

Opcionalment, pots també executar php artisan vendor:publish –provider=’Styde\Html\HtmlServiceProvider’ per publicar l’arxiu de configuració en config/html.php i revisar les seves opcions i valors.

Instal.la el component styde

Ja està explicat dalt.

###Refactorizar el formulari

En primer lloc, anem a canviar el formulari ‘create’. Substituïm tot el codi html per este que utilitza la classe Form dels components instal.lats. El formulari està associat està associat a un model i posse els camps que en fan falta. No cal possar el @csfr doncs es possa automàticament.


	* {!! Form::model(new App\Movie(),['class'=>'form-horizontal form-label-left','enctype'=>"multipart/form-data"]) !!}
	    {!! Field::text('title') !!}
	    {!! Field::text('year') !!}
	    {!! Field::text('director') !!}
	    {!! Field::text('poster') !!}
	    {!! Field::textarea('synopsis') !!}
	    {!! Form::submit('Enviar',['class'=>'btn btn-success','id'=>'submit']) !!}
    {!! Form::close() !!}	*
    

Canviarem, de la mateixa forma, el formulari de modificació, tenint en compte que si en conte de passar-li el model li passe un element del model, el valors s’afegisen al formulari.

	{!! Form::model($pelicula,['class'=>'form-horizontal form-label-left','enctype'=>"multipart/form-data",'method'=>'PUT']) !!}
        {!! Field::text('title') !!}
        {!! Field::text('year') !!}
        {!! Field::text('director') !!}
        {!! Field::select('id_genre') !!}
        {!! Field::text('poster') !!}
        {!! Field::textarea('synopsis') !!}
    {!! Form::submit('Enviar',['class'=>'btn btn-success','id'=>'submit']) !!}
    {!! Form::close() !!}

Refactoritzar els mètodes create i update

Anem a utilitzar l’assignament massiu per a omplir tots els camp a l’hora. Pots fer-ho declarant en el model la variable $fillable o la variable $guard

Després hauràs de substituir l’assignació de tots els camps, en el metodes create i update, per l’instrucció:

$movie->fill($request->toArray());

storeMovie.php

	<?php
	
	namespace App\Http\Requests;
	
	use Illuminate\Foundation\Http\FormRequest;
	use DateTime;
	
	class StoreMovie extends FormRequest
	{
	    /**
	     * Determine if the user is authorized to make this request.
	     *
	     * @return bool
	     */
	    public function authorize()
	    {
	        return true;
	    }
	
	    /**
	     * Get the validation rules that apply to the request.
	     *
	     * @return array
	     */
	    public function rules()
	    {
	        $now = new DateTime;
	        $year = $now->format("Y");
	        return [
	            'title' => 'required|max:255',
	            'year' => "required|numeric|min:1900|max:$year",
	            'poster' => 'required'
	        ];
	    }
	}

catalogController.php

	...
	public function postCreate(StoreMovie $request){
        $movie = new Movie();
        $movie->fill($request->toArray());
        $movie->save();
        return redirect('/catalog');
    }
    public function putEdit(StoreMovie $request,$id){
        $movie = Movie::findOrFail($id);
        $movie->fill($request->toArray());
        $movie->save();
        return redirect("/catalog/show/$id");
    }
    ...	

movie.php

protected $guarded = [];

Afegir relació u a molts.

Video

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateGenresTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('genres', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('genres');
    }
}
public function movies(){
        return $this->belongsToMany(Movie::class);
}

		<p><strong>Genere:</strong>
		 @if ($pelicula->Genre)   method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-info" > Tornar Película</button>
                    </form>
                @else
                    <form action=  method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-secondary" > Llogar Película</button>
                    </form>
                    <form action=  method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-danger"  > Esborrar Película</button>
                    </form>
                @endif}} 
		 @else Desconocido
		 @endif
		</p>

Afegir el camp Gènere al formulari.

Video

Anem a utilitza el component d’Styde:

{!! Field::select('id_genre') !!}

que posarem a les vistes. Si a este component li passem un array de paràmetres, es possarà com a valors seleccionables:

{!! Field::select('id_genre',['terror','musical','thriller']) !!}

També es pot declarar una funció en el model Movie per a que torne els valors.

	public function getIdGenreOptions(){
		return ['terror','musical','thriller']
	}

Però el que volem és que els valor s’agafem de la taula Genres. Tal i com així:

public function getIdGenreOptions()
{
        return Genre::all()->toArray();
}

Però aço no acaba de funcionar perquè torna un array d’esta forma


	array:2 [
	  0 => array:2 [
	    "id" => 1
	    "titulo" => "Terror"
	  ]
	  1 => array:2 [
	    "id" => 2
	    "titulo" => "Fantástico"
	  ]
	]

però per a que funcionara hauria de ser d’aquesta altra


	array:2 [
	  1 => "Terror"
	  2 => "Fantástico"
	  ]
	]

Aixì que anem a fer una funció genèrica php que donada una col.lecció d’objectes i dos camps del mateix, genere un array per a l’option.

function hazArray($elementos,'campo1','campo2')
{
    return $array
}

i la cridariem de la següent forma:


	public function getIdGenreOptions()
    {
        return hazArray(Genre::all(),'id','titulo');
    }

De moment declara-la com a privada en el model per a provar que funciona.

Nota: en Laravel, per a poder vore el valor d’una variable i para l’execució del programa s’utilitza la funció dd($variable)

HelperServiceProvider

Video

Però, esta funció ha de poser ser visible en tota la aplicació. Per tal de aconseguir-ho anem a crear un fitxer on guardar les nostres funcions genèriques.

<?php

function hazArray($elementos, $campo1, $campo2)
	{
	    $todos = [];
	    foreach ($elementos as $elemento)
	        $todos[$elemento->$campo1] = $elemento->$campo2;
	    return $todos;
	}

Per a que les funcions d’aquest fitxer siguen visibles en l’aplicació anem a crear un ServiceProvider i a registrar-lo:

php artisan make:provider HelperServiceProvider

Crearà un fitxer en la carpeta Providers. L’editem per afegir el nostre Helper.


	/**
	     * Register services.
	     *
	     * @return void
	     */
	    public function register()
	    {
	        require_once base_path() . '/app/Helpers/myHelpers.php';
	    }

I ara registrem el ServiceProvider en el fitxer config/app.php


'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        
        .....

        /*
         * Package Service Providers...
         */

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        App\Providers\HelperServiceProvider::class,

    ],

I com cada volta que toquen un fitxer de configuració executem

php artisan config:cache

I tot ha de funcionar. Ja podem triar un gènere en cada pel.licula.

El component de menu styde.

Video

Anem a fer el menu des d’un fitxer de text utilitzan el component de menu del paquet instal.lat

Substituïm el navbar per :

	<nav class="navbar navbar-expand-md navbar-light navbar-laravel">
	    <div class="container">
	        <a class="navbar-brand" href="">
	            <span class="glyphicon glyphicon-tower" aria-hidden="true"></span>
	            Videoclub
	        </a>
	        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="">
	                <span class="navbar-toggler-icon"></span>
	        </button>
	        @if( Auth::check() )
	            {!! Menu::make(config('menu'), 'navbar-nav mr-auto') !!}
	        @endif
	    </div>
	</nav>

on config(‘menu’) enllaça en un fitxer que hem de crear en la carpeta config i de nom menu.php. Este haurà de contindre:


	<?php
	
	return [
		'catalogo' => ['url' => '/catalog'],
		'nueva' => ['title' => 'Nueva Película', 'url' => '/catalog/create'],
		'logout' => ['title' => 'Cerrar Sesion' ,'url' => '/logout']
	];

Cal fer php artisan config:cache

On estan les opcions de menu.

Completant botons

En aquest exercici anem a afegir la funcionalitat dels botons de llogar, retornar i eliminar pel·lícules. En tots els casos haurem de crear una nova ruta, un nou mètode en el controlador , actualitzar el boton en la vista i mostrar una notificació despres de realitzar l’acció. En la següent taula es mostra un resum de la nova ruta a afegir:

Ruta Tipus Controlador/Acció
/catalog/rent/{id} PUT CatalogController@putRent
/catalog/return/{id} PUT CatalogController@putReturn
/catalog/delete/{id} DELETE CatalogController@deleteMovie

Aquests tres mètodes són similars al mètode que ja havíem implementat abans per a editar les dades d’una pel.lícula. En el cas de putRent i putReturn únicament modificarem el camp rented assignant-li el valor true i false respectivament i una vegada guardat crearem la notificació i realitzarem una redirecció a la pantalla amb la vista detalle de la pel.lícula. En el mètode deleteMovie també obtindrem el registre de la pel·lícula però haurem de cridar al mètode delete() de la mateixa, una vegada fet açò afegirem la notificació i realitzarem una redirecció al llistat general de pel·lícules.

A continuació hem d’editar la vista detalle de pel·lícules per a modificar els botons (show.blade). Atès que les accions han de realitzaren utilitzant peticions HTTP tipus PUT i DELETE no podem posar un enllaç normal (ja que seria de tipus GET). Per a solucionar-ho hem de crear un formulari al voltant del botó i assignar al formulari el mètode corresponent.

Per exemple:


	<form action=  method="POST" style="display:inline">
		
		
		<button type="submit" class="btn btn-danguer" style= "display:inline" > Devolver Película</button>
	</form>

Fes un manteniment per a la taula de gèneres i fica-la al menu.

Per a fer submenus amb styde :


	return [
		'catalogo' => [ 'submenu' => [
	            'lista' =>[ 'title'=> 'Catálogo', 'url' => '/catalog'],
	            'nueva' => ['title' => 'Nueva Película', 'url' => '/catalog/create'],
	        ]],
	        'genero' => ['submenu' => [ 
	            'genre' => ['title' => 'Mantenimiento Generos' , 'url' => '/genre'],
	            'nuevo' => ['title' => 'Nuevo Genero', 'url' => '/genre/create']
	            ]],
		'logout' => ['title' => 'Cerrar Sesion' ,'url' => '/logout']
	];

web.php

        Route::put('catalog/return/{id}','catalogController@putReturn');
	Route::put('catalog/rent/{id}','catalogController@putRent');
	Route::delete('catalog/{id}','catalogController@deleteMovie'); 

catalogController

public function putRent($id){
        $pelicula = Movie::findOrFail($id);
        $pelicula->rented = true;
        $pelicula->save();
        return redirect("/catalog/show/$id");
    }
    public function putReturn($id){
        $pelicula = Movie::findOrFail($id);
        $pelicula->rented = false;
        $pelicula->save();
        return redirect("/catalog/show/$id");
    }
    public function deleteMovie($id){
        Movie::findOrFail($id)->delete();
        return redirect("/catalog");
    }

show.blade.php

 @if ($pelicula->rented)
                    <form action=  method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-info" > Tornar Película</button>
                    </form>
                @else
                    <form action=  method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-secondary" > Llogar Película</button>
                    </form>
                    <form action=  method="POST" style="display:inline">
                        
                        @csrf
                        <button type="submit" class="btn btn-danger"  > Esborrar Película</button>
                    </form>
                @endif
    @endif

web.php

Route::get('genre','genreController@getIndex');
Route::get('genre/create','genreController@getCreate');
Route::post('genre/create','genreController@postCreate');
Route::get('genre/edit/{id}','genreController@getEdit');
Route::put('genre/edit/{id}','genreController@putEdit');
Route::get('genre/delete/{id}','genreController@delete');

genreController.php

<?php
	
	namespace App\Http\Controllers;
	
	use Illuminate\Http\Request;
	use App\Genre;
	
	
	class GenreController extends Controller
	{
	    public function getIndex(){
	        $generos = Genre::all();
	        return view('genre.index',compact('generos'));
	    }
	    
	    public function getCreate(){
	        return view('genre.create');
	    }
	    public function postCreate(Request $request){
	        $genre = new Genre();
	        $genre->fill($request->toArray());
	        $genre->save();
	        return redirect('/genre');
	    }
	    public function getEdit($id){
	        $genre = Genre::findOrFail($id);
	        return view('genre.edit',compact('genre'));
	    }
	    public function putEdit(Request $request,$id){
	        $genre = Genre::findOrFail($id);
	        $genre->fill($request->toArray());
	        $genre->save();
	        return redirect("/genre");
	    }
	    public function delete($id){
	        Genre::findOrFail($id)->delete();
	        return redirect("/genre");
	    }
	}
	

create.blade.php

@extends('layouts.master')
	@section('content')
	<div class="row" style="margin-top:20px">
	    <div class="col-md-offset-3 col-md-6">
	        <div class="panel panel-default">
	            <div class="panel-heading">
	                <h3 class="panel-title text-center">
	                    <span class="glyphicon glyphicon-film" aria-hidden="true"></span>
	                    Afegir gènere
	                </h3>
	            </div>
	            <div class="panel-body" style="padding:30px">
	                {!! Form::model(new App\Genre,['class'=>'form-horizontal form-label-left','enctype'=>"multipart/form-data"]) !!}
	                    {!! Field::text('title') !!}
	                    {!! Form::submit('Enviar',['class'=>'btn btn-success','id'=>'submit']) !!}
	                {!! Form::close() !!}
	            </div>
	        </div>
	    </div>
	</div>
	@stop

edit.blade.php

	@extends('layouts.master')
	@section('content')
	<div class="row" style="margin-top:20px">
	    <div class="col-md-offset-3 col-md-6">
	        <div class="panel panel-default">
	            <div class="panel-heading">
	                <h3 class="panel-title text-center">
	                    <span class="glyphicon glyphicon-film" aria-hidden="true"></span>
	                    Modificar Genere
	                </h3>
	            </div>
	            {!! Form::model($genre,['class'=>'form-horizontal form-label-left','enctype'=>"multipart/form-data"]) !!}
	                @method('PUT')
	                {!! Field::text('title') !!}
	            {!! Form::submit('Enviar',['class'=>'btn btn-success','id'=>'submit']) !!}
	            {!! Form::close() !!}
	        </div>
	    </div>
	</div>
	</div>
	@stop

index.blade.php

	@extends('layouts.master')
	@section('content')
	<h2 >Gèneres</h2>
	    <div class="row">
	        <table class="table-bordered table-info">
	            <tr><th>id</th><th>Titulo</th><th>Operacion</th></tr>
			    @foreach( $generos as $genero )        
			    <tr>
			        <td></td>
			        <td></td>
			        <td><a href='/genre/edit/'><i class='fa fa-edit'></i></a>
			            <a href='/genre/delete/'><i class='fa fa-trash'></i></a>
			        </td>
			    </tr>
			    @endforeach
	        </table>
	    </div>  
	@stop

Alertes

Video

El component d’Styde te un sistema de notificacions. Per a fer-lo servir cal possar en la vista on volem que ixquen les notificacions. En el nostre cas serà en la plantilla, després de mostrar el contingut:

master.blade.php


	...
	<div id='app' class="container"> 
        @yield('content')
        {!! Alert::render() !!}
    </div>
    ...

I ara quan guardem una pel.licula podem mostrar una notificació a l’usuari:

CatalogController.php


	...
	public function postCreate(StoreMovie $request){
        $movie = new Movie();
        $movie->fill($request->toArray());
        $movie->save();
        Alert::success("S'ha guardat la pel.licula");
        return redirect('/catalog');
    }
	...

ACCÉS (LOGIN) EN UNA APP AMB SOCIALITE

Video

Laravel disposa d’un paquet oficial, anomenat Laravel Socialite que ens ofereix una via ràpida i fàcil, per a oferir una forma d’autenticació amb proveïdors de OAuth, suportant de forma oficial a la data, Facebook, Twitter, LinkedIn, Google, GitHub i Bitbucket. Pot ser estès amb facilitat implementant el paquet Socialite Providers

Per fer un sistema d’autenticació per Facebook

Control de qui lloga la pel.licula.

Video

Cada volta que un usuari lloga un pel.licula anem a apuntar-ho en una taula rents.

php artisan make:migration create_rents_table
	<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateRentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('rents', function (Blueprint $table)
        {
            $table->increments('id');
            $table->integer('id_movie')->unsigned();
            $table->integer('id_user')->unsigned();
            $table->date('dateRent')->nullable();
            $table->date('dateReturn')->nullable();
            $table->foreign('id_movie')->references('id')->on('movies')->onUpdate('CASCADE')->onDelete('CASCADE');
            $table->foreign('id_user')->references('id')->on('users')->onUpdate('CASCADE')->onDelete('CASCADE');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('rents');
    }
}

Movie.php

public function users(){
        return $this->belongstoMany(User::class,'rents','id_movie', 'id_user')->withPivot(['dateRent','dateReturn']);
    }

User.php

public function movies(){
        return $this->belongstoMany(Movie::class,'rents','id_user', 'id_movie')->withPivot(['dateRent','dateReturn']);
    }
 public function putRent($id){
        DB::transaction(function () use($id) {
            $pelicula = Movie::findOrFail($id);
            $pelicula->rented = true;
            $pelicula->save();
            $pelicula->users()->attach(Auth::id(), ['dateRent' => date('Y/m/d')]);
        });

        return redirect("/catalog/show/$id");
    }
    public function putReturn($id){
        DB::transaction(function () use($id){
            $pelicula = Movie::findOrFail($id);
            $pelicula = Movie::findOrFail($id);
            $pelicula->rented = false;
            $pelicula->save();
            $pelicula->users()->updateExistingPivot(Auth::id(), ['dateReturn' =>date('Y/m/d')]);
        });
        return redirect("/catalog/show/$id");
    }

Que un usuari no puga retornar una pel.licula que no te llogada.

 public function rent_movies(){
        return $this->belongsToMany(Movie::class,'rents','id_user', 'id:movie')->withPivot(['dateRent','dateReturn'])->wherePivot('dateReturn',null);
    }