Modelos

icon picker
Polimorfismo ?????????

La relación 1:1 o 1:n

Las principales relaciones que ofrece Eloquent:
hasMany y pertenecen a Muchos .
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 ( pertenece a ).

La relación n:n


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

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 : pertenece a 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 pertenecen a muchos pero de varias tablas.
morphedByMany : este es el pertenecen a muchos 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 ( 'actores' , función ( Blueprint $tabla ) {
$tabla- > id () ;
$tabla- > cadena ( 'nombre' ) -> único () ;
$tabla- > cadena ( 'slug' ) -> único () ;
$tabla -> marcas de tiempo () ;
}) ;
Solo proporcionamos un nombre y un slug, en cuanto a las categorías.
Regeneramos las tablas:
php artesanal migrar:fresco
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' ] ;
películas de función pública ()
{
return $ this- > morphToMany ( Film :: class , 'filmable' ) ;
}

Actor

Será lo mismo para el modelo Actor :
películas de función pública ()
{
return $ this- > morphToMany ( Film :: class , 'filmable' ) ;
}

Película

Para el modelo Film , se proporcionan estas dos relaciones:
categorías de función pública ()
{
return $ this- > morphedByMany ( Categoría :: clase , 'filmable' ) ;
}
actores de la función pública ()
{
return $ this- > morphedByMany ( Actor :: class , 'filmable' ) ;
}

La población

Llenaremos las tablas para nuestras pruebas.
Necesitaremos una fábrica para los actores:
php artesanal hacer: fábrica ActorFactory
image.png
Con este código:
< ?php
espacio de nombres Base de datos\Fábricas;
use App\Models\Actor;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Soporte\Str;
clase ActorFactory extiende Factory
{
protegido $modelo = Actor :: clase ;
definición de función pública ()
{
$nombre = $esto -> farsante -> nombre () ;
volver [
'nombre' = > $nombre,
'slug' = > Str::slug ( $nombre ) ,
] ;
}
}
Todo lo que queda es modificar el código de DatabaseSeeder :
< ?php
espacio de nombres Base de datos\Sembradores;
use Illuminate\Database\Seeder;
use App\Models\ { Película, Categoría, Actor } ;
use Illuminate\Soporte\Str;
clase DatabaseSeeder extiende Seeder
{
/**
* Sembrar la base de datos de la aplicación.
*
* @retorno nulo
*/
ejecución de función pública ()
{
Actor::factory () -> contar ( 10)->crear () ;
$categorias = [
'Comedia' ,
'drama' ,
'Compartir' ,
'Fantástico' ,
'Terror' ,
'animado' ,
'Espionaje' ,
'Guerra' ,
'Policía' ,
'Pornográfico' ,
] ;
foreach ( $categorías como $categoría ) {
Categoría::create ([ 'nombre' = > $categoría, 'slug' = > Str::slug ( $categoría )]) ;
}
$ids = rango ( 1 , 10 ) ;
Película::fábrica () -> contar ( 40)->crear () -> cada ( función ( $película ) uso ( $ids ) {
barajar ( $ids ) ;
$ película- > categorías () -> adjuntar ( array_slice ( $ ids, 0 , rand ( 1,4 ) )) ;
barajar ( $ids ) ;
$ película- > actores () -> adjuntar ( array_slice ( $ ids, 0 , rand ( 1,4 ) )) ;
}) ;
}
}
Y corremos la población:
php artesanal db: semilla
Esta vez he planeado nombres de categorías realistas y no aleatorios:
image.png
También planeé 10 actores con nombres aleatorios:
image.png
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:
image.png
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:
image.png
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 ):
arranque de función pública ()
{
Ver::compositor ([ 'índice' , 'crear' , 'editar' ] , función ( $ver ) {
$ver- > with ( 'categorías' , Categoría::todas ()) ;
}) ;
}
Añadiremos los actores:
use App\Models\ { Categoría, Actor } ;
...
$ver- > with ( 'actores' , Actor::all ()) ;

La carretera

También necesitamos agregar una ruta para la selección de películas por actor:
Ruta::controlador ( MovieController::clase)->grupo ( función () {
...
Ruta::get ( 'actor/{slug}/películas' , 'índice' ) -> nombre ( 'películas.actor' ) ;
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.