Establecer y definir correctamente las relaciones en Laravel cuando construimos una APP, es uno de los pasos más importantes para lograr una solución solida y escalable.
Las relaciones que se dan entre los modelos son la base de todo lo que haremos después.
Laravel aporta una estructura sencilla para construir sus modelos y relaciones, dentro del mundo de Eloquent, el cual aporta un conjunto de convenciones, que en esencia son estas
Convenciones de Eloquent Model
Los nombres de la tablas se escriben en minúsculas, corresponderán con el nombre del modelo y se le agrega una s
, y si el modelo tiene un nombre compuesto por dos palabras, la s se añade al final de todo, separando las palabras con una guion bajo.
De este modo , la tabla del modelo Cliente
sería clientes y la de ClienteLike
sería cliente_likes
.
El campo primary key de una tabla debe tener el nombre de id
, con el atributo AUTO_INCREMENT,
en laravel 5 o bigIncrements
en Laravel 6.
Los modelos son clases extienden de la clase Model, un modelo al ser creado tiene esta estructura
<?php namespace App; use Illuminate\Database\Eloquent\Model; class NombreModelo extends Model { // }
Es aquí donde definiremos las relaciones y estructura del modelo, esto incluye la tabla a que se refiere, los campos que deberán ser llenados dentro de su tabla, y los cambios que queramos hacer en la estructura de la tabla que corresponde al modelo.
Las convenciones no son inviolables, sino una guía de organizar el código y su legibilidad pero pueden cambiarse todo lo que se desee dentro del modelo. Por ejemplo un modelo Productos variado puede quedar así
class Producto extends Model
{
// cambiamos el nombre de la tabla que controla el modelo en vez de productos, trabajara con mercancia
protected $table = 'mercancia';
// cambiamos la clave primaria, que por defecto es id pero usaremos el código ean definiendo ese campo en la propiedad primaryKey protected $primaryKey = 'ean_code'; // Anulamos los valores por defecto de los campos timestamp que Laravel crea automáticamente en cada tabla, cambiando su valor a false public $timestamps = false; // asignamos un nombre de conexión diferente protected $connection = 'connection-name'; // Establecemos aquellos atributos a los que se les pueden asignar valores protected $fillable = ['name',’fabricante’]; // Definimos en la variable guarded, los atributos que no pueden se asignados protected $guarded = ['price',’expire_date’];
}
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Producto extends Model { // cambiamos el nombre de la tabla que controla el modelo en vez de productos, trabajara con mercancia protected $table = 'mercancia'; // cambiamos la clave primaria, que por defecto es id pero usaremos el código ean definiendo ese campo en la propiedad primaryKey protected $primaryKey = 'ean_code'; // Anulamos los valores por defecto de los campos timestamp que Laravel crea automáticamente en cada tabla, cambiando su valor a false public $timestamps = false; // asignamos un nombre de conexión diferente protected $connection = 'connection-name'; // Establecemos aquellos atributos a los que se les pueden asignar valores protected $fillable = ['name',’fabricante’]; // Definimos en la variable guarded, los atributos que no pueden se asignados protected $guarded = ['price',’expire_date’]; }
Las relaciones pueden ser de uno a uno, de uno a muchos o de muchos a muchos, hay suficiente información sobre esto en la red, muy bien explicado, pero en esencia en una aplicación donde un cliente, con un buzón de correos individual, tendrá más de un rol, y habrá varios usuarios de la misma empresa, los modelos quedarían relacionados así.
Un cliente con un buzón de correo (de uno a uno), pertenece solo a una empresa (de uno a uno) y un cliente tiene varios roles(relación de uno a muchos)
Como puede verse las relaciones son bilaterales, por tanto la inversa es que entre buzon y cliente también es de uno a uno, entre empresa y clientes hay una relación de muchos a uno y entre roles y cliente también de uno a varios.
Cuando en ambos lados la relación es de uno a muchos, se considera una relación de muchos a muchos y debe crearse una tabla pivote que acoja solo aquellos valores de ambos modelos que no son coincidentes y que será la tabla objeto de las consultas.
Si a las relaciones son de uno a muchos de un lado y de uno a uno en el otro, es una relación de general de uno a muchos y si ambos lados son de uno a uno, pues asi queda de uno a uno.
Uno a Uno
Ejemplo Cliente y Buzón están relacionados uno a uno
namespace App; use Illuminate\Database\Eloquent\Model; class Cliente extends Model { public function buzon() { return $this->hasOne('App\Buzon'); // Si el id tiene un nombre diferente al que corresponde por convención buzons_id lo especificamos return $this->hasOne('App\Buzon', 'code_id', 'local_key'); } }
Definimos la otra clase
namespace App; use Illuminate\Database\Eloquent\Model; class Dni extends Model { public function cliente() { return $this->belongsTo('App\Cliente'); // Si el id tiene un nombre diferente al que corresponde por convención clientes_id lo especificamos return $this->belongsTo('App\Cliente', 'nombre_id', 'local_key'); } }
Uno a Muchos
En esta caso la definición es prácticamente igual
Una Empresa tiene muchos Clientes
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function clientes()
{
return $this->hasMany('App\Cliente');
// Si el id tiene un nombre diferente al que corresponde por convención clientes_id lo especificamos
return $this->hasMany('App\Cliente', 'name_id', 'local_key'); }
}
Un Cliente pertenece a una Empresa
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function empresa() { return $this->belongsTo('App\Empresa'); }
}
Muchos a Muchos
Un Cliente tiene varios Roles
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function roles() { return $this->belongsToMany('App\Role');
// Si el nombre de la tabla es diferente a lo predeterminado o el ID de la tabla tiene otro nombre.
return $this->belongsToMany('App\Role', 'cliente_roles', 'name_id', 'defin_id');
}
}
Un Rol tiene varios Clientes
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function clientes() { return $this->belongsToMany('App\Cliente');
// Si el nombre de la tabla es diferente a lo predeterminado o el ID de la tabla tiene otro nombre.
return $this->belongsToMany('App\User', 'cliente_roles', 'defin_id', 'name_id');
}
}
Aquí debemos crear una tabla intermedia, con el nombre cliente_roles, de las cual será donde obtengamos los datos. La idea básica es que esta tabla tendrá los id de las tablas que la conforman y otros campos que sean interesantes tener para nuestra aplicación
Definimos en la función withPivot los campos de la tabla intermedia, y el acceso a ellos.
namespace App; use Illuminate\Database\Eloquent\Model; class Cliente extends Model { public function roles() { return $this->belongsToMany('App\Role', 'cliente_roles') ->withPivot('create', 'read','update', 'delete'); } }
Y para acceder a los datos intermediamos la palabra pivot en la solicitud/orden que hacemos.
$user = App\Cliente::find(1); foreach ($cliente->roles as $role) { echo $role->pivot->create; }
Ademas podemos acceder directamente a las tablas para obtener diferentes resultados
// retorna App\Buzon App\Cliente::first()->buzon; Nos devolverá valores del modelo Buzon // retorna Illuminate\Database\Eloquent\Relations\BelongsToMany App\Cliente::first()->roles(); Nos devolverá valores del modelo Role, de acuerdo a su relación con el modelo cliente // retorna Illuminate\Database\Eloquent\Collection App\Cliente::first()->roles; Nos devolverá una colección
Y listo, esto es todo.
Espero modestamente que este artículo, sirva de ayuda a alguien.
Gracias.
…., si avanzo sígueme, si me detengo empújame, si retrocedo mátame…….