Parliamo oggi delle view, in Laravel possono essere fatte in semplice php oppure con blade. Il consiglio è di usare il secondo tipo perchè abbiamo diversi vantaggi che ora andremo a vedere.
Blade è il templating engine di Laravel, queste le sue caratteristiche:
- Permette di scrivere al suo interno puro php se necessario.
- Blade viene compilato solo se modificato, il file viene compilato e messo in cache.
- Ha strutture di controllo di flusso (if, for, while).
- I file blade hanno estensione blade.php e di default risiedono in resources/view.
Contents
Chiamare e passare dati a una View
Iniziamo con il passare dei dati dal nostro controller alla nostra view realizzata in blade, la prima cosa che dobbiamo quindi fare è quella di creare un controller di esempio e digitiamo dal terminale:
php artisan make:controller TestController
Questo comando creerà all’interno di app/Http/Controllers una classe php chiamata testController, apriamo la nostra classe e aggiungiamo ora all’interno del Controller la seguente funzione:
public function example(){
return view('test');
}
Laravel quindi andrà a cercare all’interno della cartella view che si trova in resources un file chiamato test.php o test.blade.php.
Ora chiaramente per vedere la pagina dobbiamo fare altre due azioni. La prima è quella di creare una rotta, lo faremo velocemente, andando ad aggiungere la seguente riga in routes/web.php:
Route::get('test', 'TestController@example');
Ultima cosa è chiaramente creare la view, quindi andiamo in resources poi in views e creiamo il nosto test.blade.php e possiamo anche iniziare a scriverci dentro qualcosa di molto banale:
<h1>Test Blade</h1>
ora se andiamo a verificare all’indirizzo 127.0.0.1:8000/test avremo la nostra bella scritta in bella mostra.
Dobbiamo, però, anche passare dei dati alle viste, iniziamo quindi con l’andare a modificare il nostro Controller, andando a creare un array $data che passeremo alla view:
protected $data = [
[
'name' => 'Massimiliano',
'surname' => 'Salerno'
],
[
'name' => 'Salvatore',
'surname' => 'Aranzulla'
],
[
'name' => 'Steve',
'surname' => 'Jobs'
]
];
Quindi il nostro Controller si presenterà così:
class TestController extends Controller
{
protected $data = [
[
'name' => 'Massimiliano',
'surname' => 'Salerno'
],
[
'name' => 'Salvatore',
'surname' => 'Aranzulla'
],
[
'name' => 'Steve',
'surname' => 'Jobs'
]
];
public function example(){
return view('test', ['data'=> $this->data]);
}
}
In questo modo così semplice abbiamo passato l’array alla view, aggiungere anche un altro parametro da passare è semplicissimo:
return view('test',
[
'title' => 'Elenco Persone',
'data'=> $this->data
]
);
Un altro modo di passare i dati alla view è tramite la funzione with:
return view('test')->with('title', 'Elenco Persone')->with('data', $this->data);
Oppure ancora, passando direttamente un array alla funzione with:
return view('test')
->with([
'title' => 'Elenco Persone',
'data' => $this->data]
);
Ancora un’ulteriore possibilità:
return view('test')
->withTitle('Elenco Persone')
->withData($this->data);
In questo caso si sfruttano i metodi magici di Php, quando infatti si chiama una funzione che non esiste automaticamente in php scatta la funzione __call e dentro questa funzione possiamo fare delle elaborazioni, è proprio ciò che fa Laravel per noi in questo caso.
Abbiamo ancora un’altra possibilità, forse spesso può risultare la più comoda e sfrutta la funzionalità di php, compact:
$data = $this->data;
$title = 'Elenco Persone';
return view('test', compact('title', 'data'));
Compact crea automaticamente un array con chiavi title e data e va a valorizzandole andando cercare variabili con lo stesso nome.
Scegliete tranquillamente quello che preferite.
Ora finalmente andiamo nella nostra view test.blade.php e andiamo a scrivere:
<h1>{{$title}}</h1>
{{var_dump($data)}}
Quando dovremo stampare variabili php lo faremo con le doppie graffe. Se andiamo a verificare ora avremo il nostro titolo è la stampa del var_dump dell’array subito sotto.
Vale la pena aggiungere, prima di passare alla parte più bella, che c’è la possibilità ora in Laravel di chiamare la view direttamente dalla definizione della rotta, in questo modo:
Route::view('test', 'welcome');
Blade @if e @for
Ora andiamo a listare l’array di persone. Lo facciamo in questo modo:
@if (!empty($data))
<ul>
@foreach($data as $person)
<li>{{$person['name']}} {{$person['surname']}}</li>
@endforeach
</ul>
@endif
Come vedete if e foreach non sono affatto complessi, iniziano con @if o @foreach e terminano con @endif @endforeach. Come potete vedere il codice rimane pulito e leggibile. Si può chiaramente anche usare nello stesso modo il @for e il @while.
Se volessimo andare a gestire il caso in cui l’array di persone fosse vuoto possiamo farlo con un else in questo modo:
@if (!empty($data))
<ul>
@foreach($data as $person)
<li>{{$person['name']}} {{$person['surname']}}</li>
@endforeach
</ul>
@else
<p>Non ci sono persone registrate</p>
@endif
Andiamo a modificare momentaneamente il nostro controller in questo modo:
$data = [];
$title = 'Elenco Persone';
return view('test', compact('title', 'data'));
Ora passiamo un array vuoto e quindi ci troveremo nel ramo else, possiamo verificarlo caricando la nostra pagina.
Ma se il codice già così vi sembra chiaro e pulito, pensate solamente che potremmo scrivere in maniera migliore così:
@forelse ($data as $person)
<li>{{$person['name']}} {{$person['surname']}}</li>
@empty
<p>Non ci sono persone registrate</p>
@endforelse
con il @forelse di Blade possiamo eliminare anche il @if, ottenendo lo stesso identico risultato.
Blade con il foreach fornisce altre interessanti informazioni come in questo caso:
<li style="{{$loop->first || $loop->last ? 'text-decoration: underline;' : ''}}">{{$person['surname']}}</li>
con $loop possiamo andare a vedere quando siamo al primo o all’ultimo elemento, e quindi personalizzare il nostro html. Possiamo avere tante informazioni tramite $loop:
- $loop->index : possiamo avere l’indice dell’array dell’elemento attuale
- $loop->iteration : come index solo che inizia a contare da 1 invece che da 0
- $loop->remaining : ci ritorna quanti elementi dell’array ancora dobbiamo sfogliare,
- $loop->count : andiamo a vedere il numero totale di elementi dell’array;
- $loop->parent : si va ai dati del foreach precedente, quello in cui è incluso il foreach attuale.
- $loop->deph : si contano i livelli di annidamento dei loop.
- $loop->first : restituisce 1 quando si è al primo elemento dell’array altrimenti 0
- $loop->last : restituisce 1 quando si è all’ultimo elemento dell’array altrimenti 0
Template Blade: @extend e @yield
Possiamo definire chiaramente un unico template e fare in modo che tutte le pagine ereditino da questo unico template.
Creiamo una cartella layouts e andiamo a metterci dentro un file chiamato layout.blade.php
Ora andiamo a cercare un qualsiasi template oppure a crearlo noi stessi, io oggi utilizzo uno base di bootstrap ho aggiunto solo il css e il js già preinstallati in laravel che hanno di default bootstrap e jquery:
<!DOCTYPE html>
<html lang="it">
<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 -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Starter Template for Bootstrap</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
</div><!-- /.container -->
<script src="/js/app.js"></script>
</body>
</html>
Ora andiamo a modificare questa pagina, la prima cosa che un minimo di attenzione SEO ci porterebbe a fare è modificare il titolo della pagina, ma come facciamo con Blade e Laravel? Questo è il title fisso e statico che abbiamo nel nostro template:
<title>Starter Template for Bootstrap</title>
Dobbiamo modificarlo in modo che sia diverso per ogni singola pagina del nostro sito. Ecco la soluzione di Laravel:
<title>@yield('title', 'Il nostro test')</title>
Abbiamo impostato il nome della direttiva yield che è title, e possiamo dare a questa un secondo parametro che è il titolo di default.
Più avanti cerchiamo la class container e andiamo a inserire il placeholder del contenuto qui dentro in questo modo:
<div class="container">
@yield('content')
</div>
In questo caso non gli diamo un valore di default.
Ora apriamo la nostra pagina test.blade.php e andiamo ad estendere la pagina di layout, modifichiamola in questo modo:
@extends('layouts/layout')
<h1>{{$title}}</h1>
@forelse ($data as $person)
<li>{{$person['name']}} {{$person['surname']}}</li>
@empty
<p>Non ci sono persone registrate</p>
@endforelse
Con @extends definiamo il file dal quale ereditare. Questo è un dettaglio molto importante in questa cartella layouts appena creata potremmo avere tipi di layout diversi per pagine diverse, magari quello per le pagine di amministazione e quello per le pagine pubbliche.
Bene, la nostra pagina di layout ora verrà ereditata ma se andate a vedere il sorgente c’è un piccolo problema. Il template è stato stampato tutto dopo il codice della pagina test.blade.php. Possiamo notare come il titolo di default sia stato aggiunto. Noi abbiamo si esteso la view ma non gli abbiamo detto dove mettere il codice.
Ecco come possiamo dirglielo:
@extends('layouts/layout')
@section('title', $title)
@section('content')
<h1>{{$title}}</h1>
@forelse ($data as $person)
<li>{{$person['name']}} {{$person['surname']}}</li>
@empty
<p>Non ci sono persone registrate</p>
@endforelse
@endsection
Per quanto riguarda la section title gli abbiamo passato direttamente il parametro, mentre per la sezione content, visto che il contenuto è più grande ci sarà bisogno di aprire la section per poi chiuderla, tutto ciò che mettiamo qua in mezzo sarà inserita dove c’è il nostro segna posto nel template. Le sezioni possono essere quante vogliamo in una pagina, la cosa importante è che abbiano apertura e chiusura se non gli passiamo direttamente il contenuto come secondo parametro. Le section non devono per forza essere richiamate nella view figlia, non andrà in errore se non ci sarà nella view figlia il richiamo a title, inserirà il titolo di default, quando invece, come nel caso di content, non ci sono parametri di default, semplicemente nel punto del placeholder non verrà inserito alcun testo.
@yield non è l’unico modo per far ereditare le nostre pagine, mettiamo ad esempio di avere delle pagine in cui non servirà alcun javascript o comunque in cui per qualche motivo andremo a caricare file diversi. possiamo farlo con section:
@section('javascript')
<script src="/js/app.js"></script>
@show
Se andiamo a ricaricare la pagina nulla è cambiato, ma se andiamo a definire nel template la sezione javascript in questo modo:
@section('javascript', '');
Beh adesso vedrete che al caricamento della pagina non viene più inserito il file javascript, questo perchè la sezione di test.blade.php ha sovrascritto quella del template.
Se volessimo invece aggiungere ulteriori file js per una determinata pagina caricando comunque i file js del template lo potremo fare in questo modo:
@section('javascript');
@parent
****altro da inserire ****
@endsection
In questo modo viene messo il restante testo al posto del @show.
Sass preinstallato in Laravel
Chiaramente c’è bisogno di intervenire sulla pagina, il menù in position fixed ha bisogno di un nostro intervento in modo che si possa vedere il contenuto della pagina che altrimenti finisce sotto.
Chiaramente vogliamo usare SASS vero? allora andiamo sul nostro terminale nella cartella del progetto e digitiamo:
npm install
quando ha finito l’installazione di tutto ciò che di default aveva la nostra installazione di Laravel in package.json possiamo digitare sul terminale:
npm run watch
Questo fa si che laravel, più esattamente webpack, si metta in ascolto delle modifiche ai file javascript e scss. Ora lasciamo pure aperta la finestra del terminale continuerà a lavorare per noi e andiamo ad aggiungere un po’ di padding. Andiamo in resources/assets/sass/app.scss e aggiungiamo in fondo il seguente semplice codice css:
body{
padding-top: 70px;
}
Riaggiorniamo la pagina e vedremo il cambiamento. Durante il salvataggio il codice sass è stato compilato in css e sostituito il file nella cartella public/css. Ma tutto ciò lo vedremo nel dettaglio un’altra volta.
Component e Slots
Component ci permette di creare dei componenti che possiamo riutilizzare prendiamo ad esempio un componente di bootstrap come questo:
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="..." alt="...">
<div class="caption">
<h3>Thumbnail label</h3>
<p>...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
</div>
Andiamo nella nostra cartella views e creiamo una cartella components un file chiamato custom-content.blade.php e modifichiamolo in questo modo:
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="{{$url}}" alt="{{$title}}">
<div class="caption">
<h3>{{$title}}</h3>
{{$slot}}
</div>
</div>
</div>
</div>
Abbiamo messo delle variabili che saranno da passare al componente. $slot indica invece dove deve inserire il codice che viene passato al componente.
Ora capire il funzionamento è molto semplice andiamo su test.blade.php e aggiungiamo il seguente codice:
@component('components.custom-content', [
'title' => 'Immagine personalizzata',
'url' => 'https://placeholdit.co//i/400x300?'
])
testo da aggiungere
@endcomponent
Questo ci permette di riutilizzare il componente passandogli semplicemente parametri diversi. Anche in questo caso possiamo passare i parametri in modo diverso:
@component('components.custom-content')
@slot('title' , 'Immagine personalizzata')
@slot('url' , 'https://placeholdit.co//i/400x300?')
testo da aggiungere
@endcomponent
L’effetto è esattamente lo stesso quindi anche in questo caso si può decidere liberamente quale metodologia usare.
@include e @each
In maniera simile funziona @include, anche in questo caso possiamo passare parametri e viene incluso semplicemente il codice del file richiamato. Ad esempio potremmo spostare la nostra lista di persone. In view creiamo una cartella includes e andiamo a creare un nuovo file chiamato persons.blade.php e andiamo a tagliare questa parte di codice da test.blade per inserirla in persons.blade.php
<ul>
@forelse ($data as $person)
<li style="{{$loop->first || $loop->last ? 'text-decoration: underline;' : ''}}">
{{$loop->count}} {{$person['name']}} {{$person['surname']}}
</li>
@empty
<p>Non ci sono persone registrate</p>
@endforelse
</ul>
Al posto del codice tagliato possiamo mettere appunto l’include:
@include('includes.persons')
Perfezioniamo questo codice ora perchè c’è un problema, infatti se l’array è vuoto stamperà comunque il tag ul. Con l’include possiamo evitarlo semplicemente in questo modo:
@includeWhen(count($data), 'includes.persons')
Adesso l’include avviene solamente se la condizione count($data) è rispettata.
Anche con l’include posso passare dati che non troviamo nella view che lo contiene, proprio come facciamo con i component.
Ora passiamo all’array, anche qui c’è un modo diverso di scorrerlo che può tornare molto interessante e si tratta di @each. Creiamo in view un file chiamato content.blade.php e incolliamoci il seguente codice:
<li>
{{$person['name']}} {{$person['surname']}}
</li>
Lo riconoscete? era l’elenco con cui stampavamo a video le persone del nostro array. Ora andiamo sotto views/includes nel fine persons.blade.php andiamo ad eliminare il forelse e andiamo a mettere questa riga di codice:
@each ('content', $data, 'person')
Tramite @each andiamo a scorrere l’array $data e passiamo il contenuto a content, decidendo di chiamare il singolo valore dell’array person, quindi nella view content potremmo utilizzare direttamente $person.
di Massimiliano Salerno