Agujero negro: Borrar entidades
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOh-oh, acabamos de enterarnos de que esta nave, el USS Leafy Cruiser, ha caído en un agujero negro. Por suerte, no había a bordo ningún personaje querido a largo plazo, pero esta nave está ahora espaguetizada. Como ya no existe en esta realidad, tenemos que eliminarla de nuestra base de datos.
app:ship:remove
Comando
Vamos a crear un comando para gestionar esto. En tu terminal, ejecuta:
symfony console make:command
Para el nombre, utiliza app:ship:remove
. Esto ha creado una nueva clase de comando.
Constructor de comandos
¡Ábrelo! src/Command/ShipRemoveCommand.php
. El creador añadió algo de código repetitivo para nosotros. Actualiza la descripción a Delete a starship
:
// ... lines 1 - 13 | |
( | |
name: 'app:ship:remove', | |
description: 'Delete a starship', | |
) | |
class ShipRemoveCommand extends Command | |
// ... lines 19 - 56 |
En el constructor, necesitamos inyectar dos cosas: private ShipRepository $shipRepo
y private EntityManagerInterface $em
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
public function __construct( | |
private StarshipRepository $shipRepo, | |
private EntityManagerInterface $em, | |
) { | |
parent::__construct(); | |
} | |
// ... lines 26 - 54 | |
} |
Cuando necesites encontrar o recuperar entidades, utiliza el repositorio. Cuando necesites gestionar entidades, como persistir, actualizar o eliminar, utiliza el gestor de entidades, o "EM" para abreviar.
Configuración del comando
En el método configure()
, elimina addOption()
. Para addArgument()
, cambia el nombre a slug
, establece InputArgument::REQUIRED
, y actualiza la descripción a The slug of the starship
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 26 | |
protected function configure(): void | |
{ | |
$this | |
->addArgument('slug', InputArgument::REQUIRED, 'The slug of the starship') | |
; | |
} | |
// ... lines 33 - 54 | |
} |
Lógica de mando
Abajo en execute()
, sustituye este $arg1 =
por $slug = $input->getArgument('slug')
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... line 36 | |
$slug = $input->getArgument('slug'); | |
// ... lines 38 - 53 | |
} | |
} |
A continuación, tenemos que encontrar el barco por esta babosa. Cada EntityRepository
ya tiene el método perfecto para ello. Escribe $ship = $this->shipRepo->findOneBy()
pasando un array donde la clave es la propiedad a buscar y el valor es el valor a buscar: ['slug' => $slug]
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... lines 36 - 37 | |
$ship = $this->shipRepo->findOneBy(['slug' => $slug]); | |
// ... lines 39 - 53 | |
} | |
} |
Al utilizar estos métodos de búsqueda preconfigurados, Doctrine escapa automáticamente los valores, por lo que no tienes que preocuparte por los ataques de inyección SQL.
Ajusta esta sentencia if
a if (!$ship)
. findOneBy()
devuelve null
si no se ha encontrado una entidad. Dentro, escribe $io->error('Starship not found.')
y devuelve Command::FAILURE
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... lines 36 - 39 | |
if (!$ship) { | |
$io->error('Starship not found.'); | |
return Command::FAILURE; | |
} | |
// ... lines 45 - 53 | |
} | |
} |
Escribe un comentario para informar al usuario de que estamos a punto de eliminar la nave estelar.$io->comment(sprintf('Removing starship %s', $ship->getName()))
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... lines 36 - 45 | |
$io->comment(sprintf('Removing starship: %s', $ship->getName())); | |
// ... lines 47 - 53 | |
} | |
} |
Elimina esta repetición adicional y escribe $this->em->remove($ship)
. Al igual que con persist()
,remove()
en realidad no elimina la entidad directamente, sino que la añade a una cola de entidades que se eliminarán cuando llamemos a $this->em->flush()
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... lines 36 - 47 | |
$this->em->remove($ship); | |
$this->em->flush(); | |
// ... lines 50 - 53 | |
} | |
} |
Añade un mensaje de éxito con $io->success('Starship removed.')
:
// ... lines 1 - 17 | |
class ShipRemoveCommand extends Command | |
{ | |
// ... lines 20 - 33 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
// ... lines 36 - 50 | |
$io->success('Starship removed.'); | |
return Command::SUCCESS; | |
} | |
} |
¡Comando realizado!
Vuelve a nuestra aplicación y actualiza la página para asegurarte de que el barco sigue ahí. Ahora, copia el slug de la URL.
Ejecutar el comando
De nuevo en tu terminal, Ejecuta:
symfony console app:ship:remove
Pega el slug copiado y ejecuta. ¡Éxito! Nave estelar eliminada. Ejecuta de nuevo el mismo comando.
symfony console app:ship:remove leafy-cruiser-ncc-0001
"Nave estelar no encontrada" ¡Perfecto! De nuevo en la aplicación, actualiza la página. 404. ¡La nave ha desaparecido de la base de datos!
¡Muy bien! Hemos visto cómo persistir y eliminar entidades. A continuación, veremos cómo actualizar la entidad nave estelar.