L’integrazione dell’ORM Eloquent in una applicazione Laravel non si limita alla possibilità di scrivere query verso il database sfruttando la semplicità di una classe che rappresenta la tabella.
Sappiamo che in una applicazione Laravel è possibile usare la dependency injection per includere e accedere semplicemente ad altre parti dell’applicazione. Grazie alla dependency injection i Model Eloquent possono essere integrati in punti chiave dell’applicazione Laravel, quali, per esempio, router, controller e view.
Laravel è, infatti, un framework MVC (Model-View-Controller) e, in questa integrazione tra le varie parti del paradigma MVC, trova uno dei suoi maggiori punti di forza.
Binding Route-Model in Laravel
Uno delle necessità tipiche per cui può risultare necessario sfruttare i meccanismi delle dependency injection per poter accedere alle funzioni offerte da un model, è quello di recuperare dati dalla tabella del database collegata al model.
Riprendiamo un esempio presentato durante l’esposizione dei controller: supponiamo di avere definito una rotta per mostrare il contenuto di un post. La rotta risponde alla URI in cui è indicato l’id del post, come https://www.example.com/posts/23861.
use App\Http\Controllers\PostController; Route::get('/posts/{id}', [PostController::class, 'show']);
In un’ applicazione Laravel in cui l’accesso al dato è gestito da un model, possiamo riscrivere la stessa rotta nel modo seguente.
use App\Models\Post; Route::get('/posts/{post}', function (Post $post) { return view('post.show', $post); });
Viene realizzato, in questo modo, il cosiddetto implicit binding. Vengono, in pratica, collegate tra loro la variabile $user e la porzione variabile della URI {post}, assumendo implicitamente che il valore che arriva dalla URI attraverso {post} sia il valore della chiave primaria del model indicato. In pratica, la variabile $user con cui si interagisce all’interno della funzione è già una istanza ricavata eseguendo Post::find() con il valore di {post} passato come argomento.
Questa integrazione Model <> Route offre diversi vantaggi e funzionalità aggiuntive interessanti.
È, per esempio, possibile indicare più model (vedremo tra poco come mettere in relazione diversi model), semplicemente facendo corrispondere il model alla porzione variabile di URI con le stesse convenzioni su nomi e ordine.
use App\Models\Author; use App\Models\Book; Route::get('/authors/{author}/books/{book}', function (Author $author, Book $book) { return $book; });
Sempre in tema di convenzioni, è anche possibile indicare una colonna diversa da id per l’implicit binding, a patto che, ovviamente, tale colonna sia una chiave primaria (ogni riga ha un valore diverso).
use App\Models\Post; // nel mondo del web uno slug è un identificativo univoco di una pagina, // è parte della URI completo e di solito indica il contenuto della pagina stessa Route::get('/posts/{post:slug}', function (Post $post) { return $post; });
Model e Controller in Laravel
Anche i controller possono sfruttare meccanismi simili per avere a costo zero una connessione semplificata con il database per mezzo di un model Eloquent.
Laravel permette di creare nuovi controller di tipo resource indicando, sin da subito, a quale model collegarli.
$ php artisan make:controller PostController --model=Post INFO Controller [app/Http/Controllers/PostController.php] created successfully.
Rispetto all’analogo controller di risorsa mostrato nella lezione sui controller, quello creato indicando il model associato avrà nei vari parametri indicata l’istanza della classe App\Models\Post e non l’intero del suo id
public function show(Post $post) { // }
Le possibilità offerte per collegare route/controller al model sono, quindi, molte.
View e paginazione in Laravel
Nel momento in cui le righe delle nostre tabelle cominciano a diventare molte, non è più sostenibile restituire tutte le righe in una singola chiamata o pagina.
Risulta, quindi, necessario avere la possibilità di dividere i possibili risultati su più pagine che siano collegate in qualche modo tra loro.
Il query builder di Laravel – e quindi anche i modelli Eloquent – offre diversi metodi per aggiungere in modo semplice e quasi trasparente la paginazione a una collection di risultati. Vediamo un esempio per la nostra ipotetica rotta che restituisce l’elenco di tutti i post del nostro blog.
// in routes/web.php use App\Models\Post; const RESULTS_PER_PAGE = 10; Route::get('/posts', function (){ return view('post.index', [ 'posts' => Post::paginate(RESULTS_PER_PAGE) ]); }); {{- resources/views/post/index.blade.php -}} <div class="container"> <ul> @foreach ($posts as $post) <li> {{ $post->title }} - {{$post->status}} </li> @endforeach </ul> </div> {{ $posts->total() }} total posts {{ $posts->links() }}
Il metodo statico paginate necessita di un solo parametro, che indica il numero di elementi da mostrare in ogni singola pagina di risultati.
A fronte di ciò, offre allo sviluppatore web una seria di comodità, sia dal punto di vista della automazione di alcuni comportamenti – Laravel aggiunge in modo automatico la gestione dell’argomento page in query string per la rotta indicata – sia dal punto di vista di metodi aggiuntivi invocabili sull’array dei risultati – in questo caso, avremo a disposizione per $post nella view non solo le comodità della classe Illuminate\Database\Eloquent\Collection, ma anche di Illuminate\Pagination\Paginator, come, ad esempio, la generazione automatica dei link per spostarsi da una pagina all’altra