Login to bookmark this video
Buy Access to Course
13.

Black Hole: Deleting Entities

|

Share this awesome video!

|

Lucky you! You found an early release chapter - it will be fully polished and published shortly!

This Chapter isn't quite ready...

Get Notified About this Course!

We will send you messages regarding this course only
and nothing else, we promise.
You can unsubscribe anytime by emailing us at:
privacy@symfonycasts.com

Oh-oh, we just got word that this ship, the USS Leafy Cruiser, has fallen into a black hole. Luckily, no long-term, beloved characters were on board, but this ship is now spaghettified. Since it no longer exists in this reality, we need to remove it from our database.

app:ship:remove Command

Let's create a command to handle this. At your terminal, run:

symfony console make:command

For the name, use app:ship:remove. This created a new command class.

Command Constructor

Open it! src/Command/ShipRemoveCommand.php. The maker added some boilerplate code for us. Update the description to Delete a starship:

56 lines | src/Command/ShipRemoveCommand.php
// ... lines 1 - 13
#[AsCommand(
name: 'app:ship:remove',
description: 'Delete a starship',
)]
class ShipRemoveCommand extends Command
// ... lines 19 - 56

In the constructor, we need to inject two things: private ShipRepository $shipRepo and private EntityManagerInterface $em:

56 lines | src/Command/ShipRemoveCommand.php
// ... lines 1 - 17
class ShipRemoveCommand extends Command
{
public function __construct(
private StarshipRepository $shipRepo,
private EntityManagerInterface $em,
) {
parent::__construct();
}
// ... lines 26 - 54
}

Whenever you need to find or fetch entities, use the repository. When you need to manage entities, like persisting, updating, or deleting, use the entity manager, or "EM" for short.

Command Configuration

In the configure() method, remove addOption(). For addArgument(), change the name to slug, set InputArgument::REQUIRED, and update the description to The slug of the starship:

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}

Command Logic

Down in execute(), replace this $arg1 = with $slug = $input->getArgument('slug'):

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}
}

Next, we need to find the ship by this slug. Each EntityRepository already has the perfect method for this. Write $ship = $this->shipRepo->findOneBy() passing an array where the key is the property to search on and the value is the value to search for: ['slug' => $slug]:

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}
}

When using these out-of-the-box find methods, Doctrine automatically escapes the values, so you don't need to worry about SQL injection attacks.

Adjust this if statement to if (!$ship). findOneBy() returns null if an entity wasn't found. Inside, write $io->error('Starship not found.') and return Command::FAILURE:

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}
}

Write a comment to let the user know we're about to remove the starship. $io->comment(sprintf('Removing starship %s', $ship->getName())):

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}
}

Remove this extra boilerplate and write $this->em->remove($ship). Like with persist(), remove() doesn't actually delete the entity directly, it adds it to a queue of entities that will be deleted when we call $this->em->flush():

56 lines | src/Command/ShipRemoveCommand.php
// ... 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
}
}

Add a success message with $io->success('Starship removed.'):

56 lines | src/Command/ShipRemoveCommand.php
// ... 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;
}
}

Command done!

Jump back to our app and refresh the page to make doubly sure the ship is still there. Now, copy the slug from the URL.

Running the Command

Back in your terminal, run:

symfony console app:ship:remove

Paste the copied slug and execute. Success! Starship removed. Run the same command again.

symfony console app:ship:remove leafy-cruiser-ncc-0001

"Starship not found." Perfect! Back in the app, refresh the page. 404. The ship is gone from the database!

Okay! We've seen persisting and removing entities. Next, we'll see how to update the starship entity.