Laravel – impostare il nome dell’applicazione

Laravel logo

Il nome dell’applicazione può essere visualizzato nelle views di Laravel e può essere definito in almeno tre modi

file .env

Il file di configurazione delle variabil di ambiente è situato nella radice dell’albero dell’applicazione e si chiama .env.

Al suo interno si trova una variabile che possiamo personalizzare:

APP_NAME=MyBeautifulAppName

Poi, all’interno della view, ci riferiremo a questa variabile nel modo seguente

 {{env('APP_NAME')}}

Tuttavia il file .env non viene normalmente sottoposto a versione perché è caratteristico del singolo deploy su ogni server. Quindi tendo a non utilizzare questa variabile.

file config/app.php

Questo file contiene una variabile predefinita:

    'name' => env('APP_NAME', 'MyBeautifulAppName'),

Qui in realtà fa un’override del file .env, infatti utilizza la stessa variabile env, però è a runtime, cioè acquisisco il valore di default e lo metto in un’altra variabile name, eventualmente modificandolo. Per accedere al valore della variabile name in una view si scrive:

{{ config('app.name', 'Default name') }}

il secondo argomento essendo il default.

Condivisione di una variabile tra tutte le view

Il terzo metodo è il più elaborato ma consente una maggiore flessibilità: si definisce una variabile dal nome arbitrario nel file

<APP>/app/Providers/AppServiceProvider.php

e al suo interno, nel metodo boot(), si invoca il metodo statico View::share():

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::share('appTitle', "MyBeautifulAppName - powered by Laravel");
    }

La variabile è poi disponibile nelle view: {{$appTitle}}.

Se questi contenuti vi risultano utili, condivideteli. Ciao 🙂

Risorse web

Laravel – primi passi: localizzare un’applicazione con BabelEdit

BabelEdit è un programma che ci aiuta a localizzare l’applicazione. Si devono infatti personalizzare i file di localizzazione della lingua che già Laravel mette a disposizione nella cartella resources/lang. Fondamentalmente l’applicazione fa uso di etichette che poi recuperano per associazione il valore esteso del testo da visualizzare.

Per aiutare in questo tipo di attività, soprattuto se il lavoro di traduzione viene svolto da non programmatori, si può utilizzare questo software. Non sto facendo endorsement, voglio solo riportare una possibile soluzione cooperativa.

Download e installazione

Una volta installato, (al solito io uso Linux) lanciarlo con

$ BabelEdit
Dashboard di BabelEdit
Dashboard di BabelEdit

Utilizzo di BabelEdit

Ovviamente prima occorre dare l’OK per l’accettazione dei termini di licenza e per l’attivazione della Trial di 7 giorni.

Si carica il file delle etichette originarie (che sono quelle del plugin Auth):

Seleziona la sorgente dei dati
Seleziona la sorgente dei dati

Per il nostro progetto, i file di dizionario sono PHP. Si apre così la maschera per caricare i file da tradurre:

Configurazione dei linguaggi
Configurazione dei linguaggi

Si possono aggiungere i file origine e destinazione

BabelEdit aggiungere le lingue
BabelEdit aggiungere le lingue

Si associa il file alla lingua

Aggiunta nuova lingua
Aggiunta nuova lingua

Si ripetono questi passaggi per tutte le lingue che vogliamo trattare.

Cliccando su “Primary Language” selezioniamo qual è la lingua di riferimento da cui derivieremo tutte le traduzioni:

BabelEdit selezione lingua primaria
BabelEdit selezione lingua primaria

si apre la maschera di selezione del servizio

Babel configurazione del servizio di traduzione online
Babel configurazione del servizio di traduzione online

Apriamo un messaggio, vengono visualizzate le etichette così come sono state configurate nei due file di lingua. Cliccando in basso a destra lo scudo con stellina

Selezione del servizio di traduzione online
Selezione del servizio di traduzione online

si può vedere la traduzione proposta dal servizio online (ad esempio Google)

Babel traduzione automatica
Babel traduzione automatica

cliccando sulla proposta, il valore dell’etichetta viene modificato con quello proposto da Google. In assenza del servizio si può tradurre in autonomia.

Risorse web

Laravel – primi passi: il CRUD

CRUD con Laravel
Laravel logo

CRUD è l’acronimo per Create, Read, Update, Delete che sono le quattro operazioni fondamentali sui dati.

Laravel non ha molta automazione da questo punto di vista, dobbiamo costruirci le form HTML per creare e modificare i file, così come le viste per visualizzare tutti i dati oppure solo un record e alla fine la funzionalità di cancellazione.

Però ha un sistema di creazione di pagine di Blade che ci permettono il riutilizzo intelligente di molte parti di layout.

In questo aritcolo ci muoveremo su tutti e tre i domini del paradigma MVC.

CRUD 1: creiamo il template

Come prima operazione creiamo un template che riutilizzeremo in tutta l’applicazione. Lo creiamo in resources/views/layouts/app.blade,php:

<!doctype html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>Logistic Mapper</title>
</head>
<body>
<div class="container">

    @yield('content')

</div>

@yield('footer')

</body>
</html>

La direttiva @yield prenderà il contenuto della sezione content della vista chiamata e la metterà qui. Quindi se il controller chiama la view ‘edit.blade’ il suo contenuto verrà calcolato (cioè verranno messi dentro i dati) e poi prenderà posto dentro il tag “container”. È analoga ad una direttiva include. Quindi tutte le view avranno il titolo Logistic Mapper in questo caso.

CRUD 2: rassegna dei metodi da implementare

Create

Cominciamo con la creazione di nuovi records, operazione che nel dominio dei database è una insert.

La rotta per l’operazione create è la seguente:

| GET|HEAD  | company/create     | company.create  | App\Http\Controllers\CompanyController@create     |

Attenzione: questa azione consiste nella visualizzazione della form vuota (non stiamo ancora creando alcun record).
Il verbo HTTP a cui viene associata è GET e il nome della rotta è company.create. Ciò significa che la pagina web che dobbiamo progettare starà sotto /resources/view/company e si chiamerà create.blade.phpe verrà invocata dal metodo create del controller CompanyController.

La view che creiamo è questa:

@extends('layouts.app')

@section('content')
<h1>Brand New Company</h1>
<form action="/company" method="post">
    @csrf
<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>
    <tr>
        <td>
            <input type="text" size="2" readonly name="id" >
        </td>
        <td>
            <input type="text" name="name" >
        </td>
        <td>
            <input type="text" name="website" >
        </td>
        <td>
            <input type="text" name="email" >
        </td>
        <td>
            <input type="text" name="latitude" >
        </td>
        <td>
            <input type="text" name="longitude" >
        </td>
        <td>
            <select name="company_type_id">
                @foreach($company_types as $v)
                <option value="{{$v->id}}">
                    {{$v->name}}
                </option>
                @endforeach
            </select>
        </td>
    </tr>
    <tr>
        <td colspan="7"><input type="submit"></td>
    </tr>
</table>
    <p><a href="{{route('company.index')}}"><< Companies</a></p>
</form>

@endsection

La prima direttiva (@extends) indica in quale template deve essere inclusa questa pagina web, ed è layouts/app.blade.php (blade.php è un suffisso standard, il formato in dot notation della vista è layouts.app).

La seconda dichiarazione @section è la sezione content, che è il frammento che dev’essere incluso nel template layouts.app.

Segue la form. Attenzione!

  • la action dev’essere semplicemente /company: la risorsa da invocare davvero non è decisa qui ma è decisa a livello della tabella di routing, in questo caso è il metodo CompanyController@create
  • il method dev’essere conguente con il metodo espresso nella tabella di routing , quindi GET.
  • c’è un’ulteriore direttiva @csrf che serve per evitare che il metodo venga chiamato via HTTP da un’altro sito. Ci siamo già occupati di questo attacco in questo post.

Come si vede ho una serie di campi di tipo testo e una combobox che devo popolare in anticipo. Il controller deve fare tutte queste cose:

    public function create()
    {
        $company_types= CompanyType::all();

        return view('company.create', compact('company_types'));
    }

La query su CompanyType serve appunto per procurarsi la combo box. Per questo si usa il metodo all() del model. Il risultato questo:

Create company
Create company

Store

DOpo aver compilato il modulo, occorre salvare il dato. L’operazion Eloquent equivalente all’insert come detto è store. Quindi per vedere come dobbiamo comprtarci dobbiamo studiarci la riga corrispondente della tabella di routing:

| POST      | company   | company.store | App\Http\Controllers\CompanyController@store     |

In questo caso il form HTML dovrà utlizzare il metodo POST che in questo caso viene preso davvero in consderazionie e non viene riscritto da alcuna direttiva. Inoltre il metodo di controller sarà CompanyController@store . Anche se è prevista la view company.store non si verrà usata perché verrà fatto un redirecto verso l’elenco di tutte le Company (company.index) in caso di successo.

Quindi il metodo store è il seguente:

    public function store(Request $request)
    {
        $company = new Company($request->all());
        $company->save();

        return redirect(route('company.index'));
    }

È semplicissimo: si crea un nuovo oggetto della classe Company inizializzandolo con i valori dell’array $request->all().

Attenzione! se tentiamo di passare come argomento semplcemente $request, Laravel s’incazza perché $request è un oggetto, mentre il costruttore del model vuole un array.

Il metodo save() di Eloquent si trasforma in una insert della tabella companies.

Finalmente, viene inviata al browser una direttiva di redirect verso la view company.index.

Edit

Il terzo metodo ci consente di editare i dati per poi eseguire un update. Quindi questo metodo serve per visualizzare la form di modifica e non per modificare i dati, operazioe che sarò in carico al metodo update.

Al solito ci facciamo guidare dalla tabella di routing

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

Qui l’URI di accesso alla pagiba di edit era già stato generato nella pagina index dalla funzione

route('company.edit', $v->id)

l’URI generato è proprio del tipo company/{company}/edit come indicato dalla tabella di routing, dove il segnaposto {company} è sostituito dal valore numerico della chiave primaria della company. Il verbo HTTP utilizzato anche in quetso è GET (Apache deve servirci una pagina web).

Il metodo edit del CompanyController deve caricare dal database i dati da inserire nella form di modifica:

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

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

Viene caricato

  • l’array $company con i dati del record;
  • l’array $company_type
  • il valore $company_type_id che ci serve solo per posizionare correttamente la combo box; non sarebbe necessaria ma la scrittura della view ne risulta così un po’ più chiara.

La view è la seguente:

@extends('layouts.app')

@section('content')
<h1>Company edit</h1>
<form action="/company/{{$array['company']->id}}" method="post">
    @csrf
    @method('PUT')
<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="website" value="{{$array['company']->website}}" >
        </td>
        <td>
            <input type="text" name="email" value="{{$array['company']->email}}" >
        </td>
        <td>
            <input type="text" name="latitude" value="{{$array['company']->latitude}}" >
        </td>
        <td>
            <input type="text" name="longitude" 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>
    <tr>
        <td colspan="7"><input type="submit"></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

Qui la riflessione più grossa la dobbiamo fare sulla action della form: essa deve invocare il metodo update, quindi, guardando la tabella di routing:

PUT|PATCH|company/{company}| company.update | App\Http\Controllers\CompanyController@update |

dobbiamo utillizzare il verbo HTTP PUT e impostare la action su company/{company}.

Il metodo di Controller update sarà

    public function update(Request $request, $id)
    {
        $company = Company::find($id);

        $company->update($request->all());

        return redirect(route('company.index'));
    }

Viene creato l’oggetto $company da una query sul model per ID, viene passato al metodo update l’array $request->all() e alla fine viene rediretto il browser sull’indice.

Perché per operazioni diverse siamo verbi HTTP diversi?

La RFC-2616 (Hyper Text Transfer Protocol HTTP/1.1) stabilisce che il metodo PUT va usato per sostituire una risorsa esistente nel server. Ci si ricordi che all’inizio HTTP era un protocollo che si usava solo per lavorare coi file.

Il metodo POST invece va usato per trasferire dati (nuovi) dal client al srever, quindi il risultato è la creazione di una nuova risorsa.

Per questo il metodo PUT è idempotente: se applicato più volte, produce lo stesso risultato.

Il metodo POST invece non lo è, ogni volta che lo si applica vengono create nuove risorse; questo è proprio il comportamento delle operazioni database di Update (PUT) e Insert (Post), per cui questo è il senso di utilizzare i verbi HTTP in modo appropriato per le varie operazioni.

Questa distinzione va fatta anche quando si progetta l’interfaccia API di un server.

Riferimenti

Laravel – primi passi: i Model

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

Laravel – primi passi: i Controller

Proseguendo con l’invocazione delle rotte con Laravel, facciamo un riassunto: abbiamo visto come invocare l’applicazione usando una rotta. E abbiamo visto come si può usare il metodo statico Route::get() per associare un percorso URI (rotta) ad una funzione anonima. La quale al suo interno può emettere un output semplice (echo) oppure invocare una vista Blade.

Il passo successivo è quello di alzare il tiro ed effettuare una elaborazione più complessa a fronte dell’URI di richiesta.

Il componente naturale che viene chiamato per gestire una richesta è il controller. Come si ricorderà, il controller è il centro dell’applicazione (vedi l’articolo Laravel – primi passi – MVC) ed è quindi in questa sede che va gestito il processo.

Ma vediamo prima di tutto come creare un nuovo controller.

In generale dovremo creare un controller per ogni tabella del database:

una tabella -> un model -> un controller con diverse azioni -> diverse view, una per ogni azione, ma non solo.

Lo facciamo da Artisan con il quale, oltre a creare le migrazioni per defnire le tabelle, crea anche i Controller (e tantissime altre cose ancora):

$ php artisan make:controller CompanyController

Un piccolo inciso:

  • il comando è make:controller
  • il nome del controller va scritto in CamelCase con il nome della tabella al singolare. Questo perché se ci adeguiamo alla convenzione, ci risparmiamo tonnellate di file di configurazione da gestire (convention over configuration). In ogni caso è possibile derogare dalla convenzione agendo su opportuni file.

Per un sinottico delle convenzioni sui nomi delle variabili si consulti questo articolo.

Il comando sopra ci crea un controller vuoto (c’è sola la dichiarazione della classe), ma riempiamolo un po’. Se invece del precedente, lanciamo questo comando:

$ php artisan make:controller --resource CompanyController

il controller avrà al suo interno già definito 7 risorse che sono i metodi standard per effettuare le operazioni di CRUD sul modello:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class CompanyController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index() // elenco di tutti i record
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create() // for di inserimento nuovo record
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request) // salvataggio in insert
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id) // mostra un singolo record
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id) // form di modifica di un record esistente
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id) // salvataggio in update
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id) // delete di un record
    {
        //
    }
}

Ora se personalizziamo nel modo seguente il metodo index():

    public function index()
    {
        return "This is the Company index";
    }

e definiamo la rotta così

Nota: dalla versione 8 di Laravel in poi, nella definzione della rotta, il controller deve essere specificato con tutto il suo namespace:

Route::get('/company', 'App\Http\Controllers\CompanyController@index');

il risultato sarà

Laravel: metodo index del controller
Laravel: metodo index del controller

È possibile anche passare parametri dalla rotta al controller. Per esempio lo faremo quendo vorremo mostrare un singolo record utlizzando il metodo show del controller; definiamo quindi la rotta nel file routes/web.php (nota il segnaposto {id} per il parametro della rotta):

Route::get('/company/{id}', 'App\Http\Controllers\CompanyController@show');

e quindi scriviamo il metodo show del CompanyController che gestice questa rotta(nota il parametro di ingresso $id):

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show(int $id):string
    {
        //
        return "This is company # ".$id;
    }

Il risultato è il seguente:

Metodo show per gestire la rotta
Metodo show per gestire la rotta

Ultimo paragrafo per resentare la rotta speciale resource che praticamente genera per noi tutte le rotte standard che riguardano uno stesso modello e tutti i controller stadard.

Avremo un rotta per l’index e un metodo di controller per l’index; una rotta di show e un cotnroller per lo show. e così va.

Basta creare una route di tipo resource:

Route::resource('company', 'App\Http\Controllers\CompanyController');

se ci facciamo visualizzare la tabella delle rotte da Artisan vediamo:

$ php artisan route:list

e questa è la tabella delle rotte che verrà visulizzata:

route:list con resource
route:list con resource

sono stati generati tutte le rotte, qassegnata ad ognuna un nome e associato il verbo del protocollo HTTP corrspondente (PUT/PATCH per update, POST per store e così via).

Se proviamo dal browser le varie rotte non avrò neanche un errore 404, nel senso che trova la risorsa che magari provoca un errore 500, oppure funziona: sono infatti da implementare le view che servono le rotte di tipo create, edit, update e delete. Inoltre, se si analizza la tabella delle rotte,si vedrà che l’URI non cambia al cambiare del metodo per show, update delete: in questo caso viene utilizzato un diverso verbo del protocollo HTTP!

Nel prossimo articolo farà la comparsa il model, vedremo così come il Controller chiede i dati al model.

Riferimenti

Laravel: convention over configuration

Laravel adotta lo schema convieni anziché configurare che in sostanza vuol dire adeguarsi ad uno standard convenuto per i nomi dei file in modo tale da evitare di dover scrivere e manutenere prolissi file di configurazione in cui, oggetto per oggetto, definiamo il nome che devia dalla convenzione.

Un esempio rende tutto chiaro.

Se abbiamo un modello CompanyType (in CamelCase al singolare), dovremo comportarci così per tutti gli altri oggetti

  • il nome della tabella è al plurale (company_types)
  • il nome del controller è al singolare (CompanyController)
  • i nomi delle chiavi esterne prendono dalla tabella al singolare e aggiungono _id (company_type_id)
  • i nomi delle rotte sono al plurale (/companies)

Più avanti estenderò questa lista aggiungendo altre convenzioni. Ma intanto riassumo n una tabella:

OggettoModalitàOKKO
Controllersingolare, CamelCasePostControllerPostsController
Routepluraleposts/1post/1
Named Routesnake_case con notazione puntoposts.show_activeshow-active-posts
Modelsingolare, CamelCasePostPosts
Tabella DBplurale, snake_casecompany_typescompany_type
Proprietà Modelsnake_case$model->created_at$model->createdAt
Foreign Keynome model singolare suffisso _idcompany_type_idcompanyTypeId, id_company_types
VariabilicamelCase$postAuthor$post_auhtor
Alcune convenzioni sul naming degli oggetti PHP per Laravel

Riferimenti

Git: caricare un nuovo progetto su Bitbucket

Atlassian_Bitbucket_Logo
Atlassian_Bitbucket_Logo
git
git

Qui di seguito scrivo una breve guida passo passo per caricare su Bitbucket un repository Git e utilizzarlo come copia di riferimento nello sviluppo. Bitbucket consente di ospitare repository remoti privati con alcune limitazioni.

Git: creare il repository in locale

Come primo passaggio occorre inzializzare il repository git in locale:

$ cd /my/proj/repo/
$ git init
$ git add *
$ git commit -m "Importazione iniziale"

Qui è neceessario individuare il nome che git ha attribuito al branch principale per poterlo replicare in remoto:

$ git branch
* master

La versione di Git che ho a bordo è

$ git --version
git version 2.30.2

Bitbucket: creare il repository in remoto

Dopodiché bisogna creare un nuovo repository su Bitbucket, un repository vuoto in cui il branch principale divrà chiamarsi master (Bitbucket da’ l’opzione di chiamare come si vuole il branch principale, ma è bene fare molta attenzione su questo punto!).

Il progetto Laravel contiene già i file Readme.md e .gitignore quindi non è necessario generarli lato Bitbucket.

In “impostazioni avanzate” della maschera di creazione del repository Bitbucket possiamo scegliere il linguaggio con cui stiamo sviluppando, i questo caso PHP.

Quindi colleghiamo il repo locale con quello remoto con il comando:

$ git remote add origin git@bitbucket.org:mxaos/complex.git

Qui si è scelto di chiare “origin” il repository remoto come si fa spesso. Ma lo possiamo chiamare come vogliamo. Ora si può sparare sù il repository:

$ git push -u origin master

Se il risultato è il seguente:

sign_and_send_pubkey: signing failed for RSA "/home/marcob/.ssh/id_rsa" from agent: agent refused operation
git@bitbucket.org: Permission denied (publickey).
fatal: Impossibile leggere dal repository remoto.

Assicurati di disporre dei privilegi d'accesso corretti
e che il repository esista.

c’è un problema con l’autenticazione con SSH. Vedere questo articolo per risolvere il problema.

In sostanza occorre avviare l’agente ssh (se lo si deve fare ogni volta, è preferibile aggiungerlo negli script di avvio di Linux).

Infatti il risultato dopo l’esportazione delle variabili di ambiente di ssh-agent è il seguente

$ git push -u origin master
Enter passphrase for key '/home/marcob/.ssh/id_rsa': 
Enumerazione degli oggetti in corso: 109, fatto.
Conteggio degli oggetti in corso: 100% (109/109), fatto.
Compressione delta in corso, uso fino a 4 thread
Compressione oggetti in corso: 100% (92/92), fatto.
Scrittura degli oggetti in corso: 100% (109/109), 226.50 KiB | 4.36 MiB/s, fatto.
109 oggetti totali (7 delta), 0 riutilizzati (0 delta), 0 riutilizzati nel file pack
remote: Resolving deltas: 100% (7/7), done.
To bitbucket.org:mxaos/complex.git
 * [new branch]      master -> master
Branch 'master' impostato per tracciare il branch remoto 'master' da 'origin'.

La situzione in remoto ora è la seguente

Git: caricare un nuovo repository su Bitbucket da progetto locale
Git: caricare un nuovo repository su Bitbucket da progetto locale

Riferimenti

SSH: problema di autenticazione su Bitbucket

ssh
ssh

Ho un nuovo repository su Bitbucket. Ho generato una chiave con ssh-keygen e ho caricato la chiave pubblica su Bitbucket.

Tuttavia il comando seguente mi va in errore:

$ git pull remote master
sign_and_send_pubkey: signing failed for RSA "/home/marcob/.ssh/id_rsa" from agent: agent refused operation
git@bitbucket.org: Permission denied (publickey).
fatal: Impossibile leggere dal repository remoto.

Assicurati di disporre dei privilegi d'accesso corretti
e che il repository esista.

Il problema è che, dopo aver generato la chiave, mi sono dimenticato di aggiungerla al keyring utlizzato dall’agent ssh. Quindi è necessario lanciare questo comando:

$ ssh-add
Enter passphrase for /home/marcob/.ssh/id_rsa: 
Identity added: /home/marcob/.ssh/id_rsa (marcob@jsbach)

Alla fine si può verificare che la chiave è stata aggiunta

$ ssh-add -l
4096 SHA256:dCoHG9JO4UicfP5ct55GGTIN6U0bDzNrnUj70zbdkSc marcob@jsbach (RSA)

Due parole sulla autenticazione a chiave pubblica SSH

Posso effettuare un’autenticazione su un server remoto con questi ingredienti:

  1. Un repository locale in cui risiede una coppia di chiavi RSA (generate con l’utility ssh-keygen)
  2. Un agente locale (ssh-agent) che gestisce le coppie RSA generate in locale
  3. Un server in cui gira un demone OpenSSH
  4. Un agente remoto che colloquia con l’agente locale

Inoltre, il protocollo SSH implementa l’inoltro dell’agente, un meccanismo per cui un client SSH consente a un server SSH di utilizzare l’agente ssh locale sul server a cui l’utente accede, come se fosse locale.

Quando l’utente contatta il client SSH sul server, il client tenterà di contattare l’agente implementato dal server e il server inoltra la richiesta al client che ha originariamente contattato il server, che la inoltra ulteriormente all’agente locale. In questo modo, ssh-agent e agent forwarding implementano il single sign-on che può progredire in modo transitivo.

Comunque: se oggi funziona e dopo un po’ non funziona più, è perché dev’essere riavviato l’ssh-agent.

SSH agent

ssh-agent è in sostanza un portachiavi. Un programma per contenere chiavi private usate per l’autenticazione a chiave pubblica.

Attraverso l’uso di variabili d’ambiente, l’agente può essere individuato da ssh e utilizzato automaticamente per l’autenticazione durante la registrazione in altre macchine.

L’avvio del portachiavi con inizializzazione delle variabili di ambiente viene fatta con il comando

$ eval `ssh-agent -s`

Per esempio le variabili possono assumere valori come questi:

SSH_AUTH_SOCK=/tmp/ssh-9OGf5JBFxGy6/agent.20980; export SSH_AUTH_SOCK;
SSH_AGENT_PID=20981; export SSH_AGENT_PID;
echo Agent pid 20981;

Qui le variabili inizializzate sono due: SSH_AUTH_SOCK e SSH_AGENT_PID.

SSH può accedere al portachiavi utilizzando queste due informazioni.

Se l’agente vi chiede nuovamente la passphrase

Vuol dire che non avete aggiunto la chiave al keyring; anzi, probabilmente non è colpa vostra: lo avete fatto ma l’accesso al portachiavi è come sempre a tempo: dopo un po’ di tempo dovete riaprirlo a mano. Potete però decidere per quanto tenerlo aperto con questo comando:

$ ssh-add -t 1h30m

per esempio così rimane aperto per un’ora e mezza. Ricordatevi comunque che è bene che il portachiavi si chiuda dopo un po’.

Comunque è sufficiente ridigitare:

$ ssh-add

Per verificare che sono state aggiunte le chiavi

$ ssh-add -l
4096 SHA256:dCoHG9JO4UicfP5ct55GGTIN6U0bDzNrnUj70zbdkSc marcob@jsbach (RSA)

Ricapitolando

Prima dell’apertura del portachiavi questa è la risposta del server Git da cui voglio scaricare gli aggiornamenti:

$ git pull origin master 
sign_and_send_pubkey: signing failed for RSA "/home/marcob/.ssh/id_rsa" from agent: agent refused operation
git@bitbucket.org: Permission denied (publickey).
fatal: Impossibile leggere dal repository remoto.

Assicurati di disporre dei privilegi d'accesso corretti
e che il repository esista.

Quindi riapro il portachiavi:

$ eval `ssh-agent -s`
Agent pid 170012

Ora se provo a ridare il comando non avrò più l’errore ma mi verrà chesta la passphrase della mia chiave privata:

$ git pull origin master 
Enter passphrase for key '/home/marcob/.ssh/id_rsa': 

Se voglio anche non dover ridigitare la password, aggiungo la mia chiave privata al portachiavi (devo però digitare la passphrase almeno questa volta)

$ ssh-add
Enter passphrase for /home/marcob/.ssh/id_rsa: 
Identity added: /home/marcob/.ssh/id_rsa (marcob@jsbach)

Per le successive invocazioni con il Git server remoto non mi verrà più chiesta la password (fino allo scadere del timeout del portachiavi):

$ git pull origin master
Da bitbucket.org:mxaos/logisticmapper
 * branch            master     -> FETCH_HEAD
Già aggiornato.

Riferimenti SSH

Laravel – primi passi – le rotte (routes)

Laravel: cominciamo con le rotte (routes)
Laravel: cominciamo con le rotte (routes)

Routes: credo che il modo più semplice di imparare come funziona il framework MVC Laravel sia quello di partire con le rotte. Rotte proprio come le linee ideali seguite da una nave.

Almeno questa è la mia esperienza.

Cosa sono le rotte (routes)?

Cosa sono le rotte? In inglese routes, sono gli URI (Uniform Resource Identifier), i link che vengono generati dall’applicazione, quelli che compaiono sulla barra degli indirizzi del browser:

Routes: sono gli url nella barra degli indirizzi
Routes: sono gli URI nella barra degli indirizzi

Il principale URI generato dall’applicazione è la home page, nel mio esempio:

http://www.complex.local/

È un’applicazione di esempio locale per la quale ho configurato un virtual host Apache.

Per vedere come viene servita questa rotta (che in sostanza è risorsa di più alto livello, la radice e si indica con /) bisogna fare riferimento al file <APP>/routes/web.php.

Attenzione: sto usando la versione 8.73.1 di Laravel e, rispetto al passato, l’organizzazione delle cartelle è leggermente cambiata. Con <APP> intendo la cartella radice dell’applicazione (nel mio caso il nome della cartella è /complex. Al suo interno c’è tutta l’organizzazione delle cartelle di Laravel, tra cui una che si chiama /app (che non è <APP>, bensì la prima sottocartella di questa, in ordine alfabetico).
Nella cartella /app c’è la maggior parte del materiale che utilizzeremo (i model e i controller per esempio).
Un’altra cartella importante è la cartella /database dove troveremo tutte le migrazioni.
Infine , nella cartella /resources/views ci sono le viste e, nella separata cartella /routes, le rotte.

Ebbene, ecco il contenuto del file <APP>/routes/web.php:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Questo programma utilizza la classe di Laravel Route e in particolare il suo metodo get(), che è definito con una closure che non è altro che una funzione definita sul posto, detta più propriamente funzione anonima perché è senza nome. Questa closure ritorna la funzione view() a cui passo l’argomento 'welcome'.

Nota: view() è una funzione, non un metodo. Infatti non è definita all’interno di una classe ma all’interno di un file, helpers.php, situato sotto <APP>/vendor/laravel/framework/src/Illuminate/Foundation.

Il primo importante parametro del metodo get() è proprio la rotta da servire. In questo caso la ‘/’, la home page.

Il secondo parametro altrettanto importante è cosa deve fare Laravel quando dal browser arriva la richiesta di servire la rotta indicata. In questo caso ciò che deve fare Laravel è scritto dentro alla closure, e deve ritornare la view di nome ‘welcome’.

Cos’è questa view 'welcome'? È un file PHP scritto in Blade che si trova sotto <APP>/resources/views/welcome.blade.php. Quindi ogni volta che di decide il nome di una nuova view deve essere necessariamente associata ad un nuovo file all’interno della cartella <APP>/resources/views/.

Per esempio, se dobbiamo servire una rotta return view('edit'); ci dovrà essere un form HTML scritto dentro al file <APP>/resources/views/edit.blade.php.

Quindi in generale:

Route::get([URL], function () {
    return view([view file name]);
});

Ora, la view di home generata automaticamente da Laravel è piuttosto complessa:

laravel 8.73.1 standard home
laravel 8.73.1 standard home

Facciamone una più semplice:

$ cd resources/views/
$ cp welcome.blade.php welcome.blade.ORIG.php

e modifichiamo a piacere l’orginale (welcome.blade.php):

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">

        <!-- Styles -->
        <style>
            /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;...}
        </style>

        <style>
            body {
                font-family: 'Nunito', sans-serif;
            }
        </style>
    </head>
    <body class="antialiased">
        <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center py-4 sm:pt-0">
            <h1>Buongiorno Laravel!</h1>
            <p>Questa è la home page</p>
        </div>
    </body>
</html>

Ho lasciato un po’ di “codice” html/css per fare vedere lo scheletro della pagina, come vengono caricati gli stili, come si usa il linguaggio di templating Blade (es. str_replace()) – per vedere come si possano iniettare piccoli frammenti di codice per automatizzare la pagina – e Bootstrap con la definizione delle classi.

Ma proprio il minimo indispensabile.

Il cuore della view è:

<h1>Buongiorno Laravel!</h1>
<p>Questa è la home page</p>

Il risultato è un po’ deludente ma siamo risuciti a servire la nostra prima rotta

laravel home modificata
laravel home modificata

Routes: il metodo statico Route::get()

Ho glissato su un aspetto tecnico piuttosto importante, il frammento di programma che chiama la view è scritto così:

<?php
Route::get($path, <closure>)

la scrittura Route::get() è l’invocazione statica di un metodo di una classe. Qui spiego meglio cosa vuol dire.

Se non definisco una rotta, non la posso chiamare dal browser. Per esempio se provo ad invocare

http://www.complex.local/esempio

il risultato è un errore 404

Route errore 404
Route errore 404

Se però definisco la rotta:

Route::get('/esempio', function () {
    return 'view di esempio';
});

la vista che appare è la seguente

Route: view di esempio
Route: view di esempio

Possiamo anche passare parametri nell’URL e intercettarli all’interno dei nostri programmi per farne ciò che vogliamo. Ad esempio se definiamo questa rotta nel file /routes/web.php:

Route::get('/company/{id}', function ($id) {
    return 'Company '.$id;
});

Otteniamo

Route per passare un parametro
Route per passare un parametro

Posso passare anche più parametri nel modo seguente (attenzione all’ordine in cui li scrivo e li nomino!):

Route::get('/company/{id}/{type_id}', function ($id, $type_id) {
    return 'Company '.$id. ' is of type '.$type_id;
});

Il risultato è il seguente

Route per passare più parametri
Route per passare più parametri

Questo esempio che segue illustra la possibilità di dare un nome, una etichetta, ad una rotta.

Route::get('/user/example', array('as' => 'user.home', function() {
    $uri = route('user.home');
    print 'The URI is '.$uri;
}));

Il risultato è questo che per ora ci dice poco:

Route name
Route name

Tutte le rotte che definiamo le possiamo tenere sotto controllo con artisan:

Route: lista delle rotte
Route: lista delle rotte

L’ultima lista dell’elenco è quella a cui abbiamo anche attriibuto un nome. In pratica lo potremo usare così:

<a href="route('user.home')">User home</a>

e laravel ci porterà a http://www.complex.local/user/example.

Ricordatevi di fare in modo che apache possa scrivere il file <APP>/storage/logs/laravel.log:

 $ sudo chmod 777 storage/logs/laravel.log 
[sudo] password di marcob: 
$

o risulterà un errore.

Ulteriori modi di utilizzare le rotte è chiamando i metodi di un controller invece di una funzione anonima. Ma lo vediamo la prossima puntata.

Riferimenti

Laravel – primi passi – MVC

Laravel logo
Laravel logo

Laravel primi passi: ispirandomi alle lezioni di Edwin Diaz ripropongo qui un approccio smooth.

Laravel è un framework per applicazioni scritte PHP che implementa un’architettura MVC.

Framework sta per infrastruttura software fatta di file, classi, metodi e proprietà, che aiutano a sviluppare un’applicazione.

È in se stessa un’applicazione, ma sapendola configurare e personalizzare, con essa possiamo fare ciò vogliamo.

Molte operazioni saranno quasi gratis, come le operazioni su un database, ma occorrerà comunque scrivere parecchio per realizzare ciò che vogliamo. Il fatto è che utiizzando il framework siamo costretti a sviluppare in modo ordinato e coerente e possiamo tenere sotto controllo gli errori, testare il software e documentarlo.

Un altro aspetto positivo dell’adozione di un paradigma MVC standard è che potrai essere affiancato da altri programmatori che non dovranno imparare come tu scrivi il software, che è il peggior problema quando si mettono le mani in codice scritto da altri: ognuno ha il suo stile e si fa il suo piccolo framework.

Anche qui ci sarà una curva di apprendimento ma lo standard è molto più robusto, scalabile, testato e documentato del piccolo framework personale

Laravel: architettura MVC

L’arhitettura MVC è un design pattern, cioè un paradigma progettuale, un modo di progettare, in cui il funzionamento di un software viene pensato come composto da tre componenti:

  • M per Model: il modello è la rappresentazione dei dati all’interno dell’applicazione. I dati risiedono in un database ma, nel contesto di una programmmazione ad oggetti, anche loro all’interno del software, devono venire rappresentati come degli oggetti del linguaggio che si sta usando. Per questo il modello in sostanza è implementato da un’architettura che si chiama ORM, Object Relationship Manager, ed è la parte di Laravel che si occupa di interagire con il database, come dice il nome, mappando il database sugli oggetti PHP. Nella stragrande maggioranza dei casi si può dire che ad ogni tabella del database corrisponde una classe del modello.
    ORM ce ne sono tanti, ogni linguaggio ha il suo. Per esempio un ORM di Java è Hibernate. L’ORM di PHP adottato da Laravel si chiama Eloquent. Con Eloquent possiamo fare le più semplici interrogazioni e query con join senza ricorrere alla scrittura diretta di istruzioni SQL. Possiamo anche creare e distruggere oggetti database senza ricorre al DDL (il Data Definition Language, per intederci le istruzioni di tipo CREATE TABLE) del DBMS . È comunque abbastanza flessibile da consentire anche di scrivere direttamente in SQL query troppo complicate rimanendo nel framework.
  • V per View: è la parte visuale dell’applicazione, l’html prodotto dall’applicazione e la gestione dell’interazione con il browser. Il fatto che l’interfaccia debba essere sollevata da interazioni dirette con il database dovrebbe essere chiara a chiunque abbia sperimentato un po’ di programazione old style che mescolava dentro ogni singola pagina: HTML, CSS, PHP, SQL, Javascript… Un vero incubo!
    Anche per le view esistono plugin per semplificare ulteriormente la produzione: per esempio il framework Blade consente di progettare pagine che acquisiscono dati dal Model attraverso il Controller e fanno operazioni di tipo ciclo o test o semplicemente output delle variabili nell’HTML.
    Utilizzando anche il tool HTML/CSS Bootstrap possiamo progettare in modo rapido e responsive le nostre pagine senza impazzire con il CSS al cambiare della UI.
  • C per Controller: devo dire che per me è stato il componente più difficile da imparare ma quando ho capito cos’è, si è semplificato tutto di brutto. Viene definito come il man in the middle, e un po’ di verità c’è. Ma la sostanza è che il controller è l’applicazione. È in assoluto la parte più importante del pattern MVC, quella in cui scarichiamo la maggior parte della nostra creatività. Ciò che vogliamo che l’applicazione faccia, lo definiamo nel controller. È il regista che prende gli attori (model) e li fa recitare nelle scene del set (view). Quindi la maggior parte del codice che scriveremo sarà dentro al controller.

Riferimenti