---
title: Laravel [02] (Una app CRUD)
tags: daw, Laravel, migrations, 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/H1m28_2-n)
## Laravel [02] (Relacions 1a1).
### Migracions amb relacions 1-1:

Eloquent: l'ORM que utilitza Laravel, ens permet definir relacions entre taules; com ja sabem, les relacions poden ser 1-1, 1-N o N-N. En aquesta sessió aprendrem a definir relacions 1-1 entre les nostres taules directament des del nostre projecte Laravel sense haver de tocar ni una sola sentència SQL i per tant de forma totalment independent del sistema gestor de base de dades triat.
Eloquent encara no està preparat per a treballar amb claus foranes compostes, de manera que totes les nostres taules hauran de tenir una clau primària d'un sol camp.
Enlloc de trastejar directament amb la nostra aplicació CRUD, explicarem el concepte amb un projecte nou de proves i un cop assolits els conceptes, passarem a implementar la nostra primera relació entre taules a la app principal. El nostre projecte de proves s'anomenarà relacions1a1 i ho crearem directament des de la consola, aprofitarem també per a crear una base de dades i passar-li tots els permisos a l'usuari laravel que ja tenim creat:
```bash=
isard@ubuntu:~/src$ composer create-project laravel/laravel relacions1a1
isard@ubuntu:~/src$ cd relacions1a1
isard@ubuntu:~/src/relacions1a1$ sudo mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 31
Server version: 10.6.12-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> create database relacions;
Query OK, 1 row affected (0,001 sec)
MariaDB [(none)]> grant all privileges on relacions.* to laravel@localhost;
Query OK, 0 rows affected (0,005 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0,001 sec)
```
Ara ja podem modificar el fitxer .env per a configurar l'accés a la base de dades:
```yaml=
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=relacions
DB_USERNAME=laravel
DB_PASSWORD=1234
```
A continuació crearem la nostra migració per a la taula capitals:
```bash=
isard@ubuntu:~/src/relacions1a1$ php artisan make:migration create_capitals_table
INFO Migration [database/migrations/2023_04_06_171429_create_capitals_table.php] created successfully.
```
I modifiquem la funció up() per a que contingui els camps que dessitjem:
```php=
public function up(): void
{
Schema::create('capitals', function (Blueprint $table) {
$table->id();
$table->string('nom');
$table->integer('poblacio');
$table->timestamps();
});
}
```
De manera anàloga creem també la migració per a la taula pais:
```bash=
isard@ubuntu:~/src/relacions1a1$ php artisan make:migration create_pais_table
INFO Migration [database/migrations/2023_04_06_172039_create_pais_table.php] created successfully.
```
I relitzem les modificacions pertinents:
```php=
public function up(): void
{
Schema::create('pais', function (Blueprint $table) {
$table->id();
$table->char('codi', 3);
$table->string('nom');
$table->string('continent');
$table->string('regio');
$table->float('superficie', 10, 2);
$table->integer('poblacio');
$table->unsignedBigInteger('capital_id');
$table->foreign('capital_id')->references('id')->on('capitals')->onDelete('cascade');
$table->timestamps();
});
}
```
:eye: Compte! el tipus de dades de capital_id és __unsignedBigInteger__ i hem definit la relació de clau forànea amb la id de la taula 'capitals'. Per defecte, la polĺitica seria 'restrict' així que la canviem a 'cascade' tot i que també podriem utlitzar 'set null'.
El següent pas lògic seria realitzar les migracions per materialitzar les consegüents taules a la base de dades:
```bash=
isard@ubuntu:~/src/relacions1a1$ php artisan migrate
INFO Preparing database.
Creating migration table ......................................... 24ms DONE
INFO Running migrations.
2014_10_12_000000_create_users_table ............................. 45ms DONE
2014_10_12_100000_create_password_reset_tokens_table ............. 45ms DONE
2019_08_19_000000_create_failed_jobs_table ....................... 35ms DONE
2019_12_14_000001_create_personal_access_tokens_table ............ 50ms DONE
2023_04_06_171429_create_capitals_table .......................... 10ms DONE
2023_04_06_172039_create_pais_table .............................. 54ms DONE
```
Verifiqueu que les taules estan creades i que s'ha establert la relació entre capitals i pais i podem fer proves important el contingut del fitxer 'capital_inserts.sql' que podeu trobar al Moodle del mòdul.
> mysql -u laravel -p relacions < ~/Baixades/capitals_inserts.sql
Ara el pas lògic següent és generar els models:
> php artisan make:model Capital
> php artisan make:model Pais
En aquest punt ens sorgeix un petit problema, la taula de països la hem anomenat: __pais__ i al model __Pais__ i per tant hem de definir el nom de la taula dins del model per a que Laravel sigui capaç de trobar-la correctament.
```php=
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Pais extends Model
{
protected $table = 'pais';
use HasFactory;
}
```
:eye: :fire: Les funcions que ens permeten rel·lacionar els dos models són respectivament en una rel·lació 1a1 són:
* hasOne(Model)
* belongsTo(Model)
I és important conèixer el sentit d'aquesta rel·lació. Com a regla general, al model de la taula que no conté la clau forànea, afegim la funció _hasOne_ i al que si conté la clau forànea la funció _belongsTo_
```php=
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Capital extends Model
{
use HasFactory;
public function pais() {
return $this->hasOne(Pais::class);
}
}
```
```php=
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Pais extends Model
{
use HasFactory;
protected $table = "pais";
public function capital() {
return $this->belongsTo(Capital::class);
}
}
```
Ara és el moment de definir les rutes que permeten accedir a la informació que tenim emmagatzemada a la nostra base de dades (de moment només afegirem la ruta GET):
```php=
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Pais;
use App\Models\Capital;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/capital/{id}', function ($id) {
return Capital::find($id);
});
Route::get('/pais/{id}', function ($id) {
return Pais::find($id);
});
```
Que ens proporcionen els següents resultats:
```bash=
isard@ubuntu:~$ curl -X GET http://localhost:8000/pais/1
{"id":1,"codi":"AFG","nom":"Afghanistan","continent":"Asia","regio":"Southern and Central Asia","superficie":652090,"poblacio":22720000,"capital_id":1,"created_at":null,"updated_at":null}
isard@ubuntu:~$ curl -X GET http://localhost:8000/capital/1
{"id":1,"nom":"Kabul","poblacio":1780000,"created_at":null,"updated_at":null}
```
I també podem ampliar els end-points, per a trobar països a partir de la id de la capital o a l'inrevés:
```php=
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Pais;
use App\Models\Capital;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/capital/{id}', function ($id) {
return Capital::find($id);
});
Route::get('/pais/{id}', function ($id) {
return Pais::find($id);
});
Route::get('/capital/{id}/pais', function ($id) {
return Capital::find($id)->pais;
});
Route::get('/pais/{id}/capital', function ($id) {
return Pais::find($id)->capital;
});
```
```bash=
isard@ubuntu:~$ curl -X GET http://localhost:8000/capital/1/pais
{"id":1,"codi":"AFG","nom":"Afghanistan","continent":"Asia","regio":"Southern and Central Asia","superficie":652090,"poblacio":22720000,"capital_id":1,"created_at":null,"updated_at":null}
isard@ubuntu:~$ curl -X GET http://localhost:8000/pais/1/capital
{"id":1,"nom":"Kabul","poblacio":1780000,"created_at":null,"updated_at":null}
```