Login to bookmark this video
Buy Access to Course
16.

Establecer relaciones de muchos a muchos

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Muy bien, vamos a sumergirnos en la parte final de ManyToMany. En una esquina, tenemos la entidad Starship, que está vinculada mediante una relaciónManyToMany con la entidad Droid. Esta relación nos proporciona una tabla adicional llamada "tabla de unión" que lleva la cuenta de los droides que se han subido a cada nave estelar. Pero, ¿cómo asignamos un Droid a un Starship? Salta a AppFixtures.

Añadir algunos droides

En primer lugar, vamos a añadir algunos droides a la mezcla. Añadiré código que construya tres droides. Importa la clase con una opción rápida o Alt + Enter:

66 lines | src/DataFixtures/AppFixtures.php
// ... lines 1 - 4
use App\Entity\Droid;
// ... lines 6 - 11
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
// ... lines 16 - 22
$droid1 = new Droid();
$droid1->setName('IHOP-123');
$droid1->setPrimaryFunction('Pancake chef');
$manager->persist($droid1);
$droid2 = new Droid();
$droid2->setName('D-3P0');
$droid2->setPrimaryFunction('C-3PO\'s voice coach');
$manager->persist($droid2);
$droid3 = new Droid();
$droid3->setName('BONK-5000');
$droid3->setPrimaryFunction('Comedy sidekick');
$manager->persist($droid3);
$manager->flush();
// ... lines 38 - 63
}
}

Y... ¡ya tenemos droides! Nada del otro mundo: crear un nuevoDroid, establecer las propiedades necesarias, persistir y vaciar.

Asignación de droides a naves estelares

Ahora pasemos a la parte divertida: asignar un Droid a un Starship. Crea una variable Starship y prepárate para la magia:

66 lines | src/DataFixtures/AppFixtures.php
// ... lines 1 - 11
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$starship = StarshipFactory::createOne([
// ... lines 17 - 21
]);
// ... lines 23 - 63
}
}

La forma de relacionar estas dos entidades es sorprendentemente sencilla, y te parecerá un déjà vu de nuestra relación OneToMany. ¡Apuesto a que incluso puedes adivinarlo!

Antes del flush() es: $starship->addDroid($droid1). Haz lo mismo con los otros dos droides: $starship->addDroid($droid2) y$starship->addDroid($droid3):

69 lines | src/DataFixtures/AppFixtures.php
// ... lines 1 - 11
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$starship = StarshipFactory::createOne([
// ... lines 17 - 21
]);
// ... lines 23 - 25
$starship->addDroid($droid1);
$manager->persist($droid1);
// ... lines 28 - 31
$starship->addDroid($droid2);
$manager->persist($droid2);
// ... lines 34 - 37
$starship->addDroid($droid3);
$manager->persist($droid3);
$manager->flush();
// ... lines 41 - 66
}
}

La tripulación está lista para sus tortitas hechas con droides, ¡así que probemos esto!

symfony console doctrine:fixtures:load

Sin errores. Para ver si realmente funciona, ejecuta:

symfony console doctrine:query:sql 'SELECT * FROM droid'

Como esperábamos: tres filas, una por cada droide que hemos creado. Ahora, echa un vistazo a la tabla de unión, starship_droid.

symfony console doctrine:query:sql 'SELECT * FROM starship_droid'

¡Guau! Tres filas, una por cada asignación de droide a nave.

La magia de Doctrine

La verdadera magia es que, con Doctrine, sólo tenemos que preocuparnos de relacionar un objeto Droid con un objeto Starship. Luego, se encarga del resto, gestionando la inserción y eliminación de filas en la tabla de unión.

Después de la descarga, sabemos que tenemos tres filas en la tabla de unión. Ahora, tras la descarga, elimina una asignación:$starship->removeDroid($droid1):

72 lines | src/DataFixtures/AppFixtures.php
// ... lines 1 - 11
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
// ... lines 16 - 39
$manager->flush();
$starship->removeDroid($droid1);
$manager->flush();
// ... lines 44 - 69
}
}

Recarga los accesorios y comprueba la tabla de unión.

symfony console doctrine:query:sql 'SELECT * FROM droid'

¡Sólo quedan dos filas! Doctrine ha eliminado la fila de nuestro droide eliminado.

Caras Propias vs Inversas

Un toque final en ManyToMany: ¿recuerdas cuando hablamos de lados propios e inversos de una relación? Como vimos, nuestros métodos sincronizan el otro lado de la relación, añadiendo el Droid al Starshipcuando llamamos a addDroid():

224 lines | src/Entity/Starship.php
// ... lines 1 - 15
class Starship
{
// ... lines 18 - 207
public function addDroid(Droid $droid): static
{
if (!$this->droids->contains($droid)) {
$this->droids->add($droid);
}
return $this;
}
// ... lines 216 - 222
}

Así que el lado propio no importa mucho.

Pero, ¿cuál es el lado propietario? En un ManyToMany, cualquiera de los dos lados podría ser el lado propietario.

Para averiguar quién es el propietario, mira la opción inversedBy. Dice ManyToMany y inversedBy: starships, lo que significa que la propiedad Droid.starships es el lado inverso.

Ahora bien, esto es casi trivial, pero si eres un maniático del control y quieres dictar el nombre de la tabla de unión, puedes añadir un atributo JoinTable. Pero recuerda que tiene que ir en el lado propietario. Aparte de eso, no te preocupes: no es gran cosa.

A continuación, vamos a utilizar la nueva relación para representar los droides asignados a cada nave.