Establecer la relación
Vale, pero ¿cómo establecemos realmente la relación? ¿Cómo decimos
¿Este
StarshipPart
pertenece a esteStarship
?
Hasta ahora, hemos estado trabajando en AppFixtures
con Foundry. Volveremos a Foundry dentro de un rato, pero volvamos a la vieja escuela por un minuto para ver cómo funciona todo esto.
Empieza con new Starship()
... luego pegaré algo de código para establecer las propiedades necesarias. A continuación, añade $manager->persist($starship)
:
// ... lines 1 - 4 | |
use App\Entity\Starship; | |
// ... lines 6 - 12 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager): void | |
{ | |
StarshipFactory::createOne([ | |
// ... lines 18 - 22 | |
]); | |
$starship = new Starship(); | |
$starship->setName('USS Taco Tuesday'); | |
$starship->setClass('Tex-Mex'); | |
$starship->checkIn(); | |
$starship->setCaptain('James T. Nacho'); | |
$manager->persist($starship); | |
// ... lines 31 - 55 | |
} | |
} |
A continuación crea un nuevo StarshipPart
y al igual que antes, pegaré código para rellenar las propiedades. A continuación, asegúrate de que esto se guarda con $manager->persist($part)
, y por último, $manager->flush()
:
// ... lines 1 - 4 | |
use App\Entity\Starship; | |
use App\Entity\StarshipPart; | |
// ... lines 7 - 12 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager): void | |
{ | |
// ... lines 17 - 24 | |
$starship = new Starship(); | |
$starship->setName('USS Taco Tuesday'); | |
$starship->setClass('Tex-Mex'); | |
$starship->checkIn(); | |
$starship->setCaptain('James T. Nacho'); | |
$manager->persist($starship); | |
$part = new StarshipPart(); | |
$part->setName('spoiler'); | |
$part->setNotes('There\'s no air drag in space, but it looks cool.'); | |
$part->setPrice(500); | |
$manager->persist($part); | |
$manager->flush(); | |
// ... lines 38 - 55 | |
} | |
} |
Foundry suele llamar a persist()
y flush()
por nosotros. Pero como estamos en modo manual, tenemos que hacerlo nosotros.
Tenemos un Starship
y un StarshipPart
, pero aún no están relacionados. Pff, intenta cargarlos de todas formas. Dirígete a tu terminal y ejecuta:
symfony console doctrine:fixtures:load
Rutro:
starship_id
no puede ser nulo en la tablastarship_part
.
¿Por qué es necesaria esa columna? En StarshipPart
, la propiedad starship
tiene un atributo ManyToOne
y otro JoinColumn()
:
// ... lines 1 - 10 | |
class StarshipPart | |
{ | |
// ... lines 13 - 28 | |
#[ORM\ManyToOne(inversedBy: 'parts')] | |
#[ORM\JoinColumn(nullable: false)] | |
private ?Starship $starship = null; | |
// ... lines 32 - 84 | |
} |
Esto nos permite controlar la columna de clave foránea: nullable:
false significa que todoStarshipPart
debe pertenecer a un Starship
.
Asignación de la pieza a la nave
Entonces, ¿cómo decimos que esta pieza pertenece a este Starship
? La respuesta es maravillosamente sencilla. En cualquier lugar antes de flush()
, decimos$part->setStarship($starship)
:
// ... lines 1 - 12 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager): void | |
{ | |
// ... lines 17 - 36 | |
$part->setStarship($starship); | |
$manager->flush(); | |
// ... lines 39 - 56 | |
} | |
} |
Eso es todo. Con Doctrine, no establecemos ninguna propiedad starship_id
ni siquiera pasamos un ID, como $starship->getId()
. No Fijamos objetos. Doctrine se encarga de los aburridos detalles de la inserción: primero guarda el Starship
, luego utiliza su nuevo id
para establecer la columna starship_id
en la tabla starship_part
.
¡Qué listo!
Prueba de nuevo las fijaciones:
symfony console doctrine:fixtures:load
¡Sin errores! Comprueba las cosas:
symfony console doctrine:query:sql 'SELECT * FROM starship_part'
¡Et voila! Ahí está nuestra pieza única, felizmente vinculada a starship_id
75. Compruébalo:
symfony console doctrine:query:sql 'SELECT * FROM starship WHERE id = 75'
Ahí está: Starship
id 75 tiene un StarshipPart
id 1. ¡Somos geniales!
Doctrine: trabaja con objetos, no con IDs
Estas son las conclusiones: con las relaciones Doctrine, estás en el mundo de los objetos. Olvídate de los ID. Doctrine se encarga de esa parte por ti. Tú fijas el objeto y Doctrine hace el resto.
Pero ugh, esto es mucho trabajo en AppFixtures
para crear un únicoStarship
y un único StarshipPart
. Así que, a continuación, volvamos a utilizar Foundry para crear una flota de naves y un montón de piezas y enlazarlas todas de una sola vez. Aquí es donde Foundry brilla de verdad.
Hi, in Windows 10 and docker engine $part->setStarship($starship); not work.
Error
An exception occurred while executing a query: SQLSTATE[42703]: Undefined column: 7 ERROR: column "starship_id" of
relation "starship_part" does not exist
LINE 1: ...part (name, price, notes, created_at, updated_at, starship_i...
The first line in StarshipPart table does not exist