Laravel – primi passi: i Model

Spread the love

Abbiamo visto come intercettare una rotta (URI) e come gestirla con una funzione anonima, utilizzando sia una vista per visualizzare una pagina complessa che un output diretto.

Abbiamo poi visto come gestre questa rotta utilizzando un controller, e limitandoci a visualizzare una stringa di benvenuto.

Ora ci accingiamo a fare in modo che il controller esegua una query sul model in conseguenza ad una certa rotta. Per esempio abbiamo visto che esiste un metodo standard del controller chiamato index che effettuerà una query che estrae tutti i record del model (e quindi attraverso Eloquent, della tabella del database corrispondente a quel model).

Accesso diretto al database dal Controller (senza model)

Con questa modalità, che è quella dirty, sconsigliata, possiamo vedere come si possibile interagire direttamente con il database dal controller. Ma non è la prassi consigliata, lo facciamo vedere solo come primo approcio.

Occorre personalizzare il metodo index (ad esempio) del CompanyController come segue:

    public function index()
    {
        $companies = DB::select('select * from companies');
        return view('company.index', compact('companies'));
    }

la IDE si arrangia di solito ad importare le classi di cui abbiamo bisogno; in questo caso nel preambolo verrà aggiunto il namespace della classe DB per potervi accedere:

use Illuminate\Support\Facades\DB;

Accesso ai dati attraverso il model

Tuttavia impostando bene il model (dichiarando tutte le dipendenze uno a uno, uno a molti ecc) questi può fare molto meglio il lavoro per cui è sufficiente scrivere questo metodo, invece:

    public function index()
    {
        $companies = Company::all();
        return view('company.index', compact('companies'));
    }

il metodo all() è già definito nella classe Model di cui Company è un’estensione, non serve che lo scriviamo. Model ha una quantità di metodi già pronti per l’uso, più avanti ne vediamo anche un altro. Infatti la classe Company ha soltanto questa dichiarazione:

use Illuminate\Database\Eloquent\Model;

class Company extends Model
{
}

Dovremo personalizzare la classe Company solo se vorremo fare delle cose particolari.

Come si vede è estremamente semplice recuperare i dati attravero il model, non serve scrivere nessuna query, già Eloquent lo fa per noi.

Passaggio dei dati dal model alla view

L’altra “magia” che fa il controller è quella di inviare i dati ad una vista. Questa volta ci serve una pagina un po’ più elaborata del semplice output diretto.

Avendo utilizzato per la gestiione delle rotte il metodo resource() abbiamo tutte le rotte belle e pronte e serve creare per ogni rotta una pagina web sotto la directory resources/views/. La convenzione è che ogni view abbia una cartella dedicata ad ogni model: per esempio creeremo la cartella /resources/views/company e al suo interno definiremo tanti file quente sono le rotte da servire e cioè quanti sono i metodi del controller:

  • index
  • edit
  • create
  • ecc…

L’insieme delle rotte si può stampare con il comando php artisan route:list

route:list con resource
route:list con resource

Definiamo, tanto per partire due viste con Blade sotto /resources/views/company/ chiamandole con il nome del metodo del controller che le invocherà (anche questa è una convenzione da segurie per farci venire fuori i risultati con il minor sforzo):

  • index.blade.php (che conterrà la tabella con l’elenco delle company)
  • edit.blade.php (che conterrà la form di modifica di un record di company)

Il controller dovrà fornire alla view tutti i dati che vogliamo mostrare. Per esempio, per quanto riguarda la pagina delle company, vogliamo mostrae i dati della tabella company. Per questo mettiamo nella variabile $companies i dati ottenuti dal model come sopra e li passiamo alla view con la funzione compact($companies).

Nella view poi facciamo il ciclo. Una prima versione della view potrebbe essere questa, molto grezza:

@extends('layouts.app')

@section('content')
<h1>Companies</h1>
<table>
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Website</th>
        <th>Email</th>
        <th>latitude</th>
        <th>longitude</th>
        <th>company_type_id</th>
    </tr>
    @if (count($companies) > 0)
        @foreach($companies as $v)
    <tr>
        <td><a href="{{ route('company.show', $v->id) }}\edit">{{$v->id}}</a></td>
        <td>{{$v->name}}</td>
        <td>{{$v->website}}</td>
        <td>{{$v->email}}</td>
        <td>{{$v->latitude}}</td>
        <td>{{$v->longitude}}</td>
        <td>{{$v->company_type_id}}</td>
    </tr>
        @endforeach
    @else
    <tr>
        <td colspan="7">No records found</td>
    </tr>
    @endif
</table>
@endsection

Del linguaggio Blade parliamo in un articolo a parte, qui ci interessa vedere come vengono acceduti i dati che il controller passa alla view. La view vede un array di oggetti che si chiama $companies e cicla su questo array prelevando per ogni ciclo gli attributi dell’oggetto-componente dell’array $v. Il risultato è il seguente, è molto grezzo ma ci consente di vedere che stiamo progredendo rapidamente:

Laravel: company index page
Laravel: company index page

Una attenzione particolare va alla costruzione del link che ci consente di navigare dall’elenco delle Company al singolo record per poterlo editare. Notate il costrutto veramente efficiente e semplice:

href="{{ route('company.edit', $v->id) }}"

la funzione route() chiama per nome la risorsa che gestisce l’edit; è la rotta che leggiamo dalla tabella sopra, generata con artisan:

GET|HEAD  | company/{company}/edit | company.edit    | App\Http\Controllers\CompanyController@edit

Laravel trasforma questa indicazione in un URI vero e proprio, assegnando anche l’id del record da modificare:

<a href="http://www.logisticmapper.local/company/1/edit">1</a>

View per l’editazione del record

In questa vista index.blade avevamo soltanto una variabile da visualizzare (che il controller passa alla view) che è il recordset. Più in generale alla view devono essere passati dati diversi che conviene impacchettare in un array associativo, come vediamo nel secondo esempio che invece riguarda la view che contiene la form HTML di gestione di un singolo record:

    public function edit($id)
    {
        //
        $company = Company::find($id);
        $company_types= CompanyType::all();
        $array = array(
            'company' =>$company,
            'company_types' => $company_types,
            'company_type_id' => $company->company_type_id
        );

        return  view('company.edit', compact('array'));
    }

Per questa view abbiamo bisogno di tre cose:

  1. il record da editare: queste informazioni vengono prelevate dal model Company, che è la rappresentazione ORM della tabella companies, con il metodo find() a cui passiamo l’$id del record che ci arriva dalla request ed è il parametro passato al controller. Il risultato è equivalente alla select sul record $id della tabella companies. Ma è molto meno stressante. Vale la pena di notare che tutto questo passaggio di parametri $id è fluido, non dobbiamo preoccuaprci del nome di campi e delle variabili, per il fatto che abbiamo adottato la convenzione.
  2. l’elenco delle company_types che deve consentirci di costruire la combobox omonima: per questo invochiamo un altro Model, CompanyType, che è quello che sovrintende alla tabella company_types. Qui ci servono tutti i valori della tabella per cui utilizziamo il metodo all() di Eloquent.
  3. il valore della chiave esterna company_type_id per questo record che ci deve aiutare a posizionare la combobox nella selezione corretta; lo estraiamo direttamente dall’oggetto $company e lo mettiamo a disposizione della vista in modo separato (non sarebbe necessario, ma ci consente di scrivere molto meno nella view).

Il controller quindi definisce una variabile $array che è un vettore associativo con le tre componenti che abbiamo enumerato sopra e che vengono passate alla view come array di oggetti con la funzione compact().

Finalmente la view che mostra la form di editing è la segente (company/edit.blade.php):

@extends('layouts.app')

@section('content')
<h1>Company</h1>
<form action="">

<table>
    @if ($array['company']->id != null)
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Website</th>
        <th>Email</th>
        <th>latitude</th>
        <th>longitude</th>
        <th>company_type_id</th>
    </tr>
    <tr>
        <td>
            <input type="text" size="2" readonly name="id" value="{{$array['company']->id}}">
        </td>
        <td>
            <input type="text" name="name" value="{{$array['company']->name}}" >
        </td>
        <td>
            <input type="text" name="name" value="{{$array['company']->website}}" >
        </td>
        <td>
            <input type="text" name="name" value="{{$array['company']->email}}" >
        </td>
        <td>
            <input type="text" name="name" value="{{$array['company']->latitude}}" >
        </td>
        <td>
            <input type="text" name="name" value="{{$array['company']->longitude}}" >
        </td>
        <td>
            <select name="company_type_id">
                @foreach($array['company_types'] as $v)
                <option value="{{$v->id}}" @if ($v->id == $array['company_type_id']) selected @endif>
                    {{$v->name}}
                </option>
                @endforeach
            </select>
        </td>
    </tr>
    @else
    <tr>
        <td colspan="7">No records found</td>
    </tr>
    @endif
</table>
    <p><a href="{{route('company.index')}}"><< Companies</a></p>
</form>

@endsection

Il risutato è questo:

Laravel Model: company edit
Laravel Model: company edit

Riferimenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.