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.
 
            
Hi again:
Why do we use the Command option to delete a record and not the Delete function in the controller? In previous versions of Symfony, we had the following functions in a single controller: new, show, edit, and delete. What is the advantage of putting delete in a command?