Estendere Validator

Il buon Christian Giupponi oggi ci spiega come personalizzare il Validator di Laravel, estendendone le funzionalità!
francesco
Christian Giupponi
30/06/2016 in Tutorial

Laravel fa della semplicità il suo cavallo di battaglia. Ci fornisce un sacco di tool utilissimi, facili da usare e soprattutto da estendere!

Sicuramente, ti sarà capitato di dover creare un form ed avere a che fare con la sua validazione.

Ufficialmente Laravel fornisce tantissime regole utili per la validazione ma può capitare di dover controllare dei dati in un modo diverso o comunque specifico per il progetto che stai creando.

In questo breve articolo vedrai come è facile creare regole di validazione personalizzate, prenderemo in esempio una regola che permetterà di varificare l'età dell'utente basandosi sulla data di nascita ricevuta.

Nei prossimi paragrafi vedrai come costruire la regola minAge, un controllo su un'ipotetica età minima, per controllare se l'utente può o meno proseguire.

Seguendo passo passo questo articolo avrai una regola funzionante e utilizzabile fin da subito nei tuoi progetti. Ecco un esempio di come si utilizzerà la regola all'interno della validazione dati:

'data_di_nascita' => 'required|minAge'
'data_di_nascita' => 'required|minAge:18'

Il primo esempio non ha nessun parametro: di default controlerà che l'utente abbia almeno 13 anni. Nel secondo esempio invece abbiamo definito una età minima di 18 anni.

Creazione del Controller

Questo passaggio ovviamente non è obbligatorio, se hai già un Controller pronto puoi procedere al paragrafo successivo.

Da terminale dai il seguente comando:

php artisan make:controller TestValidationController

Al suo interno, crea due metodi:

public function minAge(){
	// Qui il codice per resituire la view
	return view('validation.minage');
}
	
public function minAgePost( Request $request ){
	// Qui il codice da processare dopo la validazione dati
}

Creazione del Form

Anche questo passaggio non è obbligatorio, se hai già un form pronto puoi procedere al paragrafo successivo. Crea il file minage.blade.php all'interno della cartella resources/views/ e inserisci al suo interno questo codice:

@if( count( $errors ) > 0 )
		<div class="alert alert-danger">
				<ul>
        @foreach( $errors->all() as $error )
					 <li>{{ $error }}</li>
    	  @endforeach
        </ul>
		</div>
@endif

<form action="{{ route('minage.submit') }}" method="post">
		{{ csrf_field() }}
		Data di nascita: <input type="text" name="data_di_nascita">
		<input type="submit" value="Salva">
</form>

Estendere Validator

Come per la maggior parte delle classi di Laravel, anche Validator può essere esteso per implementare nuove funzionalità.

Per prima cosa è consgiabile creare all'interno della cartella app una nuova cartella che andrà a contenere la nostra classe. Crea quindi una cartella Validations in app.

A questo punto crea la classe che andrà a contenere tutte le regole di validazione peronalizzate che andrai a creare, :

<?php namespace App\Validations;
	
use Illuminate\Validation\Validator;
	
class CustomValidations extends Validator 
{
		// Elenco metodi
}

In questo modo avrai tutti i metodi di validazione all'interno di una unica classe, potrai organizzarli come meglio credi creando anche più classi che svolgono compiti specifici.

Ad esempio potresti creare una classe che si occupa solo delle regole di validazione dell'età, una che si occupa del codice fiscale e così via.

Il ServiceProvider

Come anticipato in questa classe andremo ad insere più regole ( se necessario ) ed è necessario far sapere a Laravel che questa classe deve essere inizializzata quando viene richiesta una istanza di Validator, per farlo è sufficiente creare un ServiceProvidercon il comando:

php artisan make:provider CustomValidationsServiceProvider

Apri quindi la nuova classe CustomValidationsServiceProvider creata in app/Providers/CustomValidationsServiceProvider.php e al suo interno modifica il metodo boot, inserendo questo codice:

public function boot()
{
        // Registro la mia classe che contiene le regole custom
        $this->app->validator->resolver(function($translator, $data, $rules, $messages)
        {
            return new CustomValidations($translator, $data, $rules, $messages);
        });
}

Assicurati di inserire prima della dichiarazione della classe

use App\Validation\CustomValidation;

Adesso non devi far altro che modificare il file config/app.php aggiungendo il nuovo provider:

'App\Providers\CustomValidationsServiceProvider',

Scriviamo la Regola

Riapri il file CustomValidation.php e al suo interno aggiungi un nuovo metodo che dovrà avere lo stesso nome della regola che vuoi creare ( preceduta dal suffisso validate ), nel nostro caso:

public function validateMinAge($attribute, $value, $parameters)
{
		// Logica
}

La nostra regola non sarà molto complicata, infatti tutto quello che dovremo fare è confrontare la data odierna con la data di nascita e calcolare se l'utente ha l'età maggiore o uguale a quella impostata.

Ecco gli step necessari:

  1. Verificare se la regola ha impostato in modo esplicito un limite di età
  2. Recuperare la data odierna
  3. Recuperare la data di nascita inserita
  4. Calcolare la differenza tra le due date
  5. Verificare se l'età è sufficiente

Il tutto si trasforma in:

public function validateMinAge($attribute, $value, $parameters)
{
	// Se non ho nessn parametro l'età minima è 13
  $minAge = ( ! empty($parameters)) ? (int) $parameters[0] : 13;

  //Recupero la data di oggi
  $today = Carbon::now();

  //Trasformo la data inserita dall'utente
  $userDate = Carbon::createFromFormat("d/m/Y", $value);

  // Faccio la differenza tra le due date e vedo se l'utente
  // ha l'età minima consentita per proseguire
  return $today->diff($userDate)->y >= $minAge;
}

Adesso che tutto è pronto non ci resta che provare la nuova regola. Se hai seguito i primi paragrafi adesso avrai a disposizione 2 metodi nel controller TestValidationController. Assicurati che il secondo metodo nelle routes abbia come name minage.submit:

Route::get('validation/minAge', 'TestValidationController@minAge');
Route::post('validation/minAge', 'TestValidationController@minAgePost')->name('minage.submit');

A questo punto è necessario dire al nostro metodo minAgePost che deve eseguire la validazione, in questo caso abbiamo due possibilità.

  1. Creare una FormRequest
  2. Utilizzare il metodo validate

Essendo questo un esempio ababstanza banale utilizzeremo il secondo metodo. All'interno del metodo minAgePost aggiungi:

$this->validate($request, ['data_di_nascita' => 'required|minAge:18]);
return "Puoi accedere";

In questo modo lasceremo al metodo validate il compito di verificare i dati e, in caso di errore, saremo reindirizzati al form che ci mostrerà l'errore ricevuto.

Visualizza il form e inserisci una data nel formato gg/mm/AAAA, ed effettua qualche prova, se inserisci una età >= 18 vedrai il messaggio Puoi accedere, altrimenti visualizzerai il form con l'elenco degli errori.

Questo è solo un esempio banale di come puoi creare regole custom, puoi migliroare questo codice facendo in modo di accettare solo l'anno di nascita, l'unico limite è la fantasia!