---
title: Laravel [01] (Una app CRUD)
tags: daw, Laravel, rutes, M7
---
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licencia de Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a><br />Este obra está bajo una <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 4.0 Internacional</a>.
[Enllaç a Hackmk.io](https://hackmd.io/@JdaXaviQ/S1-ILmdxn)
## Laravel [01] (Una app CRUD, quick but not very dirty).
### Creació i configuració del projecte:
```bash=
$ cd /home/isard/src
$ composer create-project laravel/laravel una_app_crud
```
A continuació configurem el nostre Apache2 per a que serveixi la nostra app:
Afegim les següents línies al nostre fitxer de configuració /etc/apache2/apache2.conf
```
<Directory /home/isard/src/una_app_crud/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
```
I canviem el virtual host per defecte per a que apunti a aquesta nova ubicació:
```
DocumentRoot /home/isard/src/una_app_crud/public
```
Modifiquem un parell de permisos per a que l'usuari www-data pugui accedir còmodament a la nostra aplicació, reiniciem Apache i provem la nostra nova app.
```bash=
$ chmod 751 /home/isard
$ chmod -R 777 /home/isard/src/una_app_crud/storage
$ sudo systemctl restart apache2
$ firefox localhost/
```

### Generant contingut
Primer de tot anem a preparar la nostra pàgina principal. Heu de reproduir la estructura de carpetes i fitxers següents:

```bash=
$ mkdir -p /home/isard/src/una_app_crud/resources/views/layouts/partials
$ cd /home/isard/src/una_app_crud/resources/views/layouts/partials
$ touch footer.blade.php header.blade.php meta.blade.php ../master.blade.php
```
Contigut de meta.blade.php
```php=
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('pageTitle') | MyCrudApp</title>
```
Contingut de header.blade.php:
```php=
<nav class="navbar">
<a class="navbar-brand" href="{{asset('/')}}">MyCrudApp</a>
<div class="nav_container" id="navContainer">
<ul class="nav_ul">
<li class="nav-item">
<a class="nav-link" href="{{asset('/')}}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="navMenuLink">
Menu
</a>
</li>
</ul>
</div>
</nav>
```
Contingut de footer.blade.php
```php=
<h3>Peu de pàgina</h3>
```
Contingut de master.blade.php
```php=
<!DOCTYPE html>
<html lang="ca">
<head>
@include('layouts.partials.meta')
@yield('scripts')
</head>
<body>
@include('layouts.partials.header')
<div class="container">
@yield('content')
</div>
@include('layouts.partials.footer')
</body>
</html>
```
Contingut de welcome.blade.php:
```php=
@extends('layouts.master')
@section('pageTitle', 'Home')
@section('content')
<div class="contingut">
<h1>Hola, tècnics superiors en desenvolupament!</h1>
<p>Una altra app CRUD, però aquesta feta amb Laravel.</p>
</div>
@endsection
```
### La persistència de dades.
Com que som a una classe, intentaré ser original i les nostres dades aniran sobre estudiants; de moment tindrem una única taula anomenada estudiants, amb els següents camps:
* id
* nom
* cognom
* edat
* email
Passes a seguir:
1.- Crear una nova base de dades.
2.- Connectar el nostre projecte Laravel a la nostra base de dades mySQL.
3.- Generar la nostra migració d'estudiants.
4.- Executar la migració.
5.- Crear un model per a la taula estudiants.
#### Creació de la base de dades:
Es possible crear la base de dades directament des de laravel si s'escau, però no ho he considerat adient per la nostra activitat.
```bash=
$ sudo mysql
MariaDB [(none)]> create database laraveldb;
Query OK, 1 row affected (0,002 sec)
MariaDB [(none)]> ALTER DATABASE laraveldb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Query OK, 1 row affected (0,001 sec)
MariaDB [(none)]> create user 'laravel'@'localhost' identified by '1234';
Query OK, 0 rows affected (0,008 sec)
MariaDB [(none)]> grant all privileges on laraveldb.* to 'laravel'@'localhost';
Query OK, 0 rows affected (0,003 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0,002 sec)
```
Ara configurem el fitxer .env per a subministrar-li les credencials de connexió a la base de dades.
```bash=
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=laraveldb
DB_USERNAME=laravel
DB_PASSWORD=1234
```
#### La nostra primera migració.
```bash=
$ cd /home/isard/src/una_app_crud/
$ php artisan make:migration create_estudiants_table
INFO Migration [database/migrations/2023_03_26_102803_create_estudiants_table.php] created successfully.
```
Aquesta darrera comanda ens hauria d'haver creat un nou fitxer a la carpeta /database/migrations/ amb un nom semblant a: __2023_02_26_102803_create_estudiants_table.php__
Si editem aquest fitxer trobarem dues funcions: up() i down(), aquestes funcions són les encarregades de crear i destruir la taula estudiants quan ho necessitem i les podem editar al nostre gust, per exemple per afegir-hi més camps a la nostra futura nova taula. En el nostre cas, modificarem la funció up() i la deixarem així:
```php=
public function up(): void
{
Schema::create('estudiants', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('nom');
$table->string('cognom');
$table->integer('edat');
$table->string('email');
$table->timestamps();
});
}
```
Abans de còrrer la nostra primera migració ens hem d'assegurar que tenim instal·lats els connectors adients per a la nostra base de dades:
```bash=
$ sudo apt install php-mdb2-driver-mysql
$ php artisan migrate
INFO Preparing database.
Creating migration table ......................................... 25ms DONE
INFO Running migrations.
2014_10_12_000000_create_users_table ............................ 485ms DONE
2014_10_12_100000_create_password_reset_tokens_table ............. 39ms DONE
2019_08_19_000000_create_failed_jobs_table ....................... 35ms DONE
2019_12_14_000001_create_personal_access_tokens_table ........... 125ms DONE
2023_03_26_103552_create_estudiants_table ........................ 17ms DONE
```
Com poder apreciar a continuació se n'han creat diverses taules relacionades amb el nostre projecte a la base de dades, entre elles la que contindrà la informació dels nostres estudiants:


En aquest punt tenim una taula que al haver-se creat sota el control de Laravel, també pot èsser actualitzada des de Laravel mitjançant migracions.
#### El model Estudiant.
Ara ens toca crear el seu model i això o com a mínim la part inicial també li podem delegar a Artisan:
```bash=
$ php artisan make:model Estudiant
```
i ens crearà el fitxer: 'una_app_crud/app/Models/Estudiant.php' que per dins tindrà aquesta pinta:
```php=
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Estudiant extends Model
{
use HasFactory;
}
```
Modificarem el codi per afegir una propietat que combinada amb Eloquent i Laravel omplir de forma massiva les propietats dels _nostres estudiants_.
```php=
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Estudiant extends Model
{
use HasFactory;
protected $fillable = [
'nom',
'cognom',
'edat',
'email'
];
}
```
No us preocupeu gaire si no veieu com utilitzar aquesta propietat ara mateix, quedarà força més clar més endavant amb un exemple més endavant.
### El controlador EstudiantController.
Deixarem aquí el desenvolupament de la persistència dels nostres estudiants i passarem a implementar el controlador associat.
Encarreguen a Artisan que generi el controlador EstudiantController per nosaltres i li passem el paràmetre --resource per a indicar-li que volem implementar el CRUD complert.
```bash=
~/src/una_app_crud$ php artisan make:controller EstudiantController --resource
INFO Controller [app/Http/Controllers/EstudiantController.php] created successfully.
~/src/una_app_crud$ cat ./app/Http/Controllers/EstudiantController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Estudiant;
class EstudiantController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}
```
:bomb: Boooom! Ens ha generat un controlador amb l'esquelet de les funcions necessàries per realitzar un CRUD complert.
Per a que puguem enllaçar-lo amb el seu model introduirem la següent línia al codi generat del fitxer EstudiantController:
```php=
use App\Models\Estudiant;
```
#### funció index()
És la funció encarregada de retornar el llistat complert de tots els estudiants.
```php=
public function index()
{
$estudiants = Estudiant::all();
return view('estudiants.index', compact('estudiants','estudiants'));
}
```
#### funció create()
Ens durà a una vista on podrem crear un nou estudiant des de zero.
```php=
public function create()
{
return view('estudiants.create');
}
```
#### funció store()
Desa un nou usuari, per exemple un acabat de crear desprès de cridar a la funció create().
```php=
public function store(Request $request)
{
$this->validate($request, [
'nom' => 'required',
'cognom' => 'required',
'edat' => 'required|numeric',
'email' => 'required|email',
]);
$input = $request->all();
Estudiant::create($input);
return redirect()->route('estudiants.index');
}
```
#### funció show()
Obté un estudiant a partir de la seva id.
```php=
public function show($id)
{
$estudiant = Estudiant::findOrFail($id);
return view('estudiants.show', compact('estudiant','estudiant'));
}
```
#### funció edit()
De la mateixa forma que show(), obté un estudiant a partir de la seva id, però en aquest cas ens el presenta en un formulari per a poder-lo modificar.
```php=
public function edit($id)
{
$estudiant = Estudiant::find($id);
return view('estudiants.edit', compact('estudiant','estudiant'));
}
```
#### funció update()
Recupera un estudiant de la base de dades, el modifica amb les dades passades com a parámetre i desa les modificacions a la base de dades.
```php=
public function update(Request $request, $id)
{
$estudiant = Estudiant::findOrFail($id);
$this->validate($request, [
'nom' => 'required',
'cognom' => 'required',
'edat' => 'required|numeric',
'email' => 'required|email',
]);
$input = $request->all();
$estudiant->fill($input)->save();
return redirect()->route('estudiants.index');
}
```
#### funció destroy()
Esborra un estudiant de la base de dades.
```php=
public function destroy($id)
{
$estudiant = Estudiant::findOrFail($id);
$estudiant->delete();
return redirect()->route('estudiants.index');
}
```
#### Rutes:
Totes aquestes funcions no poden ser executades si no les enllaçem amb el client a través de rutes, per exemple:
> Route::get('/estudiants/index', [EstudiantController::class, 'index']);
Però no serà aquesta la manera en que generarem les nostres rutes per a realitzar el CRUD dels nostres usuaris. Aprofitarem que varem crear el nostre controlador amb el modificador --resource i que el CRUD el fem amb les funcions generades automàticament per Laravel per a utilitzar una ruta especial de Laravel que aten totes les crides CRUD sense haver d'especificar-les una a una. Afegirem la següent línia al fitxer: routes/web.php
> Route::resource('estudiants', '\App\Http\Controllers\EstudiantController');
Un cop arrivats a aquest punt, hariem poder veure les següents rutes si li preguntem a artisan quines rutes té el nostre projecte:
```php=
~/src/una_app_crud$ php artisan route:list
GET|HEAD / .................................................................................................................................
POST _ignition/execute-solution .......................... ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController
GET|HEAD _ignition/health-check ...................................... ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
POST _ignition/update-config ................................... ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
GET|HEAD api/user ..........................................................................................................................
GET|HEAD estudiants ........................................................................... estudiants.index › EstudiantController@index
POST estudiants ........................................................................... estudiants.store › EstudiantController@store
GET|HEAD estudiants/create .................................................................. estudiants.create › EstudiantController@create
GET|HEAD estudiants/{estudiant} ................................................................. estudiants.show › EstudiantController@show
PUT|PATCH estudiants/{estudiant} ............................................................. estudiants.update › EstudiantController@update
DELETE estudiants/{estudiant} ........................................................... estudiants.destroy › EstudiantController@destroy
GET|HEAD estudiants/{estudiant}/edit ............................................................ estudiants.edit › EstudiantController@edit
GET|HEAD sanctum/csrf-cookie ............................................. sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show
Showing [13] routes
```
### Vistes.
#### Vista index.
Aquesta vista serà el cor de la nostra aplicació, des d'aquí crearem els enllaços a la resta de funcionalitats.
* Creació del fitxer de la vista
```bash=
$ cd /home/isard/src/una_app_crud/
$ mkdir -p ./resources/views/estudiants
$ touch ./resources/views/estudiants/index.blade.php
```
Omplir el fitxer index.blade.php que acavem de crear amb el següent contingut:
```php=
@extends('layouts.master')
@section('pageTitle', 'Index Estudiants')
@section('content')
<h1>Index d'estudiants</h1>
<a href="{{route('estudiants.create')}}">Create New</a>
<hr/>
<table class="table">
<thead>
<th>Nom</th>
<th>Cognom</th>
<th>Edat</th>
<th>Email</th>
<th colspan="3">Accions</th>
</thead>
<?php $even = FALSE; ?>
@foreach($estudiants as $estudiant)
<tr class= <?php echo $even ? '"even_row"' : '"odd_row"'; $even = !$even ?>>
<td>{{$estudiant->nom}}</td>
<td>{{$estudiant->cognom}}</td>
<td>{{$estudiant->edat}}</td>
<td>{{$estudiant->email}}</td>
<td>
<div>
<a href="{{route('estudiants.show', $estudiant->id)}}" >Details</a>
<a href="{{route('estudiants.edit', $estudiant->id)}}" >Edit</a>
<form class="inline_form" action="{{ route('estudiants.destroy', $estudiant->id) }}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button>Delete User</button>
</form>
</div>
</td>
</tr>
@endforeach
</table>
@endsection
```
#### Vista create.
En aquesta vista utilitzarem un paquet de Laravel anomenat [Laravel Collective](https://laravelcollective.com/docs/6.x/html) que ens ajudarà a manegar el contigut dels formularis HTML. Per a istal·lar el paquet anirem al directori arrel del nostre projecte i executarem la següent comanda:
```bash=
$ cd /home/isard/src/una_app_crud
$ composer require laravelcollective/html
Info from https://repo.packagist.org: #StandWithUkraine
./composer.json has been updated
Running composer update laravelcollective/html
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
- Locking laravelcollective/html (v6.4.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
- Downloading laravelcollective/html (v6.4.0)
- Installing laravelcollective/html (v6.4.0): Extracting archive
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
INFO Discovering packages.
laravel/sail ......................................................................................................................... DONE
laravel/sanctum ...................................................................................................................... DONE
laravel/tinker ....................................................................................................................... DONE
laravelcollective/html ............................................................................................................... DONE
nesbot/carbon ........................................................................................................................ DONE
nunomaduro/collision ................................................................................................................. DONE
nunomaduro/termwind .................................................................................................................. DONE
spatie/laravel-ignition .............................................................................................................. DONE
80 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
INFO No publishable resources for tag [laravel-assets].
No security vulnerability advisories found
Using version ^6.4 for laravelcollective/html
$ touch ./resources/views/estudiants/create.blade.php
$ php artisan cache:clear
$ sudo chmod -R 777 storage/
$ composer dump-autoload
```
Contingut de create.blade.php:
```php=
@extends('layouts.master')
@section('pageTitle', 'Create Estudiant')
@section('content')
<h1>Crea un nou estudiant</h1>
<hr/>
<!-- if validation in the controller fails, show the errors -->
@if ($errors->any())
<div>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Open the form with the store function route. -->
{{ Form::open(['action' => 'App\Http\Controllers\EstudiantController@store'])}}
<!-- Include the CRSF token -->
{{Form::token()}}
<!-- build our form inputs -->
<div class="form-group">
{{Form::label('nom', 'Nom')}}
{{Form::text('nom', '', ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('cognom', 'Cognom')}}
{{Form::text('cognom', '', ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('edat', 'Edat')}}
{{Form::number('edat', '', ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('email', 'Adreça email')}}
{{Form::text('email', '', ['class' => 'form-control'])}}
</div>
<!-- build the submission button -->
{{Form::submit('Crear!', ['class' => 'btn btn-primary'])}}
{{ Form::close() }}
@endsection
```
#### Vista show.
show.blade.php
```php=
@extends('layouts.master')
@section('pageTitle', 'Detalls Estudiant')
@section('content')
<h1>Detalls d'estudiant</h1>
<hr/>
<dl>
<dt>Nom</dt>
<dd>{{$estudiant->nom}}</dd>
<dt>Cognom</dt>
<dd>{{$estudiant->cognom}}</dd>
<dt>Edat</dt>
<dd>{{$estudiant->edat}}</dd>
<dt>Email</dt>
<dd>{{$estudiant->email}}</dd>
</dl>
<div>
<a href="{{route('estudiants.edit', $estudiant->id)}}">Edit</a>
<form action="{{ route('estudiants.destroy', $estudiant->id) }}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button>Delete User</button>
</form>
</div>
@endsection
```
#### Vista edit.
edit.blade.php
```php=
@extends('layouts.master')
@section('pageTitle', 'Edit Students Details')
@section('content')
<h1>Edit Student</h1>
<hr/>
<!-- if validation in the controller fails, show the errors -->
@if ($errors->any())
<div>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Open the form with the store function route. -->
{{ Form::open(['action' => ['\App\Http\Controllers\EstudiantController@update', $estudiant->id], 'method' => 'PUT']) }}
<!-- Include the CRSF token -->
{{Form::token()}}
<!-- build our form inputs -->
<div class="form-group">
{{Form::label('nom', 'Nom')}}
{{Form::text('nom', $estudiant->nom, ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('cognom', 'Cognom')}}
{{Form::text('cognom', $estudiant->cognom, ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('edat', 'Edat')}}
{{Form::number('edat', $estudiant->edat, ['class' => 'form-control'])}}
</div>
<div class="form-group">
{{Form::label('email', 'Adreça email')}}
{{Form::text('email', $estudiant->email, ['class' => 'form-control'])}}
</div>
{{Form::submit('Actualitza!')}}
{{ Form::close() }}
@endsection
```
### Retocant el menú de navegació.
Ara que ja tenim enllestides les rutes i les vistes associades, podem retocar el menú de navegació per a incloure les noves funcionalitats.
#### Nou contingut de la plantilla parcial header.blade.php
```php=
<nav class="navbar">
<a class="navbar-brand" href="{{asset('/')}}">MyCrudApp</a>
<div class="nav_container" id="navContainer">
<ul class="nav_ul">
<li class="nav-item">
<a class="nav-link" href="{{asset('/')}}">Home</a>
</li>
<li class="nav-item">
<a href="{{route('estudiants.index')}}">Index</a>
</li>
<li class="nav-item">
<a href="{{route('estudiants.create')}}">Create</a>
</li>
</ul>
</div>
</nav>
```
### Aplicant estils.
/home/isard/src/una_app_crud/public/css/style.css
```css=
.navbar{
margin: 1em;
}
.navbar-brand {
margin: 1em;
display: block;
}
.nav_container * {
display: inline;
}
.nav_container li {
background-color: lightsteelblue;
padding: 0.3em;
margin: 3px;
border-radius: 0.3em;
}
.inline_form {
display: inline;
}
.even_row {
background-color: cornsilk;
}
.odd_row {
background-color: azure;
}
```
I així hauria d'haber quedat la pàgina desprès d'aplicar els estils ;)

### I si fem també una API?
Com és evident, Laravel no ens permet només crear pàgines web, també podem generar APIs i seguir aprofitant els recursos que ens proporciona el framework.
En un primer pas, oferirem el llistat d'estudiants a la mateixa ruta que la pàgina web, però emprant el prefix /api devant de la ruta original.

Per aconsseguir que funcioni aquesta ruta, primer hem d'afegir-la al fitxer ./routes/api.php
```php=
Route::get('/estudiants', '\App\Http\Controllers\EstudiantController@index_api');
```
La ruta utilitzarà el controlador pre-existent EstudiantController, però l'haurem d'editar per a afegir-li el mètode index_api:
```php=
/**
* Display a listing of the resource.
*/
public function index()
{
$estudiants = Estudiant::all();
return view('estudiants.index', compact('estudiants','estudiants'));
}
public function index_api()
{
// $estudiants = Estudiant::all();
// return response()->json($estudiants);
return Estudiant::all();
}
```
El codi comentat és més evident, però el codi actiu a banda de ser més compacte il·lustra com Laravel converteix directament a JSON els resultats de consultes Eloquent(ORM) quan les envia com a resposta.