la relación hasOne es simplemente hasMany limitada a un solo registro y no se usa mucho.
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
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:
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:
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:
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:
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
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
/
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:
Las relaciones
Categoría
Para el modelo Categoría se proporciona esta relación (que reemplaza a la anterior):
Esta vez he planeado nombres de categorías realistas y no aleatorios:
También planeé 10 actores con nombres aleatorios:
También tenemos 40 películas. Y, por último, en la tabla dinámica también creé enlaces aleatorios entre categorías, actores y películas. Aquí hay una descripción general:
Vemos que para cada registro tenemos el nombre del modelo y la identificación como se esperaba.
La página de bienvenida
En la página de inicio en este momento tenemos esto:
Una lista de películas con botones de acción, y también una opción por categoría. Todo eso todavía funciona, pero sería bueno agregar también la elección por actor.
Usamos un compositor de vistas para generar el conjunto de categorías para las vistas (en AppServiceProvider ):