Ultima Laravel
Share
Explore
Modelos

icon picker
Polimorfismo

La relación 1:1 o 1:n

Las principales relaciones que ofrece Eloquent:
hasMany y belongsTo
la relación hasOne es simplemente hasMany limitada a un solo registro y no se usa mucho.
image.png
Nosotros a tiene una b ( hasOne ) o a tiene varias b ( hasMany ).
Lo contrario: b es propiedad de a (belongsTo ).

La relación n:n


image.png
Tenemos a pertenece a uno o más b (belongsToMany)).
Y tenemos que b pertenece a uno o más a (belongsToMany ).

Relación de una tabla a varias tablas

Tipo de relación 1:n

Ahora imagina esta situación:
image.png
La tabla c se puede relacionar con la tabla a o con la tabla b . En esta situación, ¿cómo administrar una clave externa en la tabla c? ¿Cómo llamarlo y cómo saber con qué tabla está en relación?
Podemos ver claramente que necesitaremos otro dato: seguramente conocer la tabla en relación .
Como necesitamos dos piezas de información, necesitamos dos columnas:
image.png
Entonces tenemos dos columnas:
relatable_id : la clave externa que almacena la identificación del registro relacionado
relatable_type : la clase del modelo relacionable.
Aquí está la figura completa con los nombres de estas relaciones:
image.png
morphOne : es el hasOne pero de varias tablas.
morphMany : es el hasMany pero de varias tablas.
morphTo :belongsTo pero destinado a varias tablas.

Tipo de relación n:n

Podemos tener el mismo razonamiento para una relación n:n con varias tablas en un lado de la relación:
image.png
morphToMany : este es el belongsToMany pero de varias tablas.
morphedByMany : este es el belongsToMany pero en la dirección de varias tablas.

Los datos

Vamos a ver un ejemplo de la gestión de películas introduciendo el polimorfismo. Hasta entonces teníamos categorías y películas, vamos a agregar actores, ¡todavía es bastante relevante para las películas! Un actor puede actuar en varias películas y una película tiene varios actores, así que de nuevo tenemos una relación n:n . Obviamente, podríamos usar una segunda tabla dinámica, pero será más elegante con solo una y polimorfismo.

Migraciones

Nada cambia en la migración de categorías y películas. Eliminamos la tabla dinámica que habíamos creado. Y creamos una migración para nuestra nueva tabla dinámica:
php artisan make:migration filmables
image.png
Y vamos a proporcionar este código:
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Filmables extends Migration
{
public function up()
{
Schema::create('filmables', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->foreignId('film_id')
->constrained()
->onDelete('cascade')
->onUpdate('cascade');
$table->morphs('filmable');
});
}

public function down()
{
Schema::dropIfExists('filmables');
}
}

El método morphs es útil porque crea automáticamente las dos columnas para la relación polimórfica.
También necesitamos una migración y un modelo para los actores:
php ar
image.png
/


Con este código:
Schema::create('actors', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('slug')->unique();
$table->timestamps();
});
Solo proporcionamos un nombre y un slug, en cuanto a las categorías.
Regeneramos las tablas:
php artisan migrate:fresh
Si todo va bien, deberíamos tener las 4 tablas que nos interesan:

image.png

Las relaciones

Categoría

Para el modelo Categoría se proporciona esta relación (que reemplaza a la anterior):
protected $fillable = ['name', 'slug'];

public function films()
{
return $this->morphToMany(Film::class, 'filmable');
}

Actor

Será lo mismo para el modelo Actor :
public function films()
{
return $this->morphToMany(Film::class, 'filmable');
}

Film

Para el modelo Film , se proporcionan estas dos relaciones:
public function categories()
{
return $this->morphedByMany(Category::class, 'filmable');
}

public function actors()
{
return $this->morphedByMany(Actor::class, 'filmable');
}

Factory

Llenaremos las tablas para nuestras pruebas.
Necesitaremos una fábrica para los actores:
php artisan make:factory ActorFactory
image.png
Con este código:
<?php

namespace Database\Factories;

use App\Models\Actor;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class ActorFactory extends Factory
{

protected $model = Actor::class;

public function definition()
{
$name = $this->faker->name();
return [
'name' => $name,
'slug' => Str::slug($name),
];
}
}
Todo lo que queda es modificar el código de DatabaseSeeder :
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\{ Film, Category, Actor };
use Illuminate\Support\Str;

class DatabaseSeeder extends Seeder
{
/**
Share
 
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.