Strategies For Deleting Records

There are two different strategies to delete records from your database. The first is actually deleting records using the SQL delete from [table] where id=[id] statement. This is a reasonable approach and saves you space. However, something to consider is, once you delete the record, you can't bring it back. Another approach is to set a flag that the record to isDeleted=true. This is a good approach if you'd like to be able to easily recover a record. You just need to set the flag back to isDeleted=false and the record reappears.

We're going to look at both strategies here.

Strategy One - Deleting Records

The first strategy we'll look at is just straight up deleting the records. This approach is slightly easier to implement, because there are no updates to our database schema. Let's look at some code.

The first thing we'll implement is in the IndexViews index method. Here, we'll add a new form and create a checkbox for each name that allows us to select the employees that we want to delete. Then we click a button that deletes all the records in one go.

This code should be put into indexviews.php in your webroot directory. This code should replace the index method.

static public function index($employees) {
	IndexViews::header();

	// create a form so that we can send selected employees to the server
	?> 
	<form action="index.php" method="post">
	<input type="hidden" name="do" value="deleteEmployees">
	<input type="submit" value="Delete Selected Employees">
	
	<?php
	
	// echo the results to the browser
	foreach ($employees as $res) {
	?>
	<div>
		<input type="checkbox" name="nameIds[]" value="<?= $res["nameId"] ?>"> 
		<a href="index.php?do=update&nameId=<?= $res["nameId"] ?>">
			<?= $res["lastName"] ?>, <?= $res["firstName"] ?>, <?= $res["number"] ?>, <?= $res["phoneType"] ?>
		</a>
	</div>
	<?php
	}
	
	// end the form
	?>
	</form> 
	<?php

	IndexViews::employeeForm();
	IndexViews::footer();
}

The first thing you'll notice is that we've created a form that has a do value action of deleteEmployees. Then you'll see a submit button that submits our delete form. The button is shown at the top of the list of employees.

We've then updated our employee loop to add a checkbox to each employee with <input type="checkbox" name="nameIds[]" value="<?= $res["nameId"] ?>">.

You'll notice within that code, there is name="nameIds[]" and specifically nameIds[]. PHP does a special trick with checkboxes and radio buttons where if you add the square brackets [], it will create an array out of those values, which makes it really easy to work with those values. We'll do more with that in our updated controller and model.

Let's move on to our controller. We'll add a new controller action:

This code should be put into index.php in your webroot directory. This code should be inserted within our $_POSTS handler.

if ($_POST["do"] == "deleteEmployees") {
	
	// all your nameIds will come through PHP via an array
	$nameIds = [];
	if (isset($_POST["nameIds"]) == true) {
		$nameIds = $_POST["nameIds"];
	}
	
	if (count($nameIds) > 0) {
		IndexModels::deleteEmployees($nameIds);
	}
	
	// after we've deleted, forward the user back to our default screen
	header("Location: /");
	exit;
}

In this controller action, everything looks pretty standard. We've set up our validation to accept an array for our nameIds. If the nameIds array isn't empty, it will then get passed to our new deleteEmployees method in IndexModels.

We then add a new method to our IndexModels class. Let's look at that below:

This code should be put into indexmodels.php in your webroot directory. This code should added to the end of the class.

// nameIds is an array
static public function deleteEmployees($nameIds) {
	$db = new db;
	
	// loop through each nameId in the nameIds and delete the records
	foreach ($nameIds as $nameId) {
		$db->query(
			"delete from names where id=:nameId",
			[ ":nameId"=>$nameId, ]
		);
		
		$db->query(
			"delete from addresses where id=:nameId",
			[ ":nameId"=>$nameId, ]
		);
		
		$db->query(
			"delete from phones where id=:nameId",
			[ ":nameId"=>$nameId, ]
		);
	}
}

First, we create a loop that iterates over each nameId. Each nameId is then passed to each respective table to delete the record. The condition of the delete is if nameId equals a record in each table.

Strategy Two - Setting A Deleted Flag

In this section, we'll build on our previous example and just add the small bits we need to make this work.

The first thing we need to do is update our database schema to add a deleted flag to our names table.

alter table names add isDeleted boolean default false;

The next thing we need to do is update our index method within our IndexModels class.

select n.id as nameId, lastName, firstName, number, phoneType from names n, phones p where n.id=p.nameId and isDeleted=false

We've specifically added and isDeleted=false to the end of our query. This basically allows the query to only return records that have not been deleted. If a record has been deleted, then isDeleted will be true, and the record will be skipped.

The last update we need to make is to our deleteEmployees code. Change the code to the following:

// nameIds is an array
static public function deleteEmployees($nameIds) {
	$db = new db;
	
	// loop through each nameId in the nameIds and delete the records
	foreach ($nameIds as $nameId) {
		$db->query(
			"update names set isDeleted=true where id=:nameId",
			[ ":nameId"=>$nameId, ]
		);
	}
}

When a user clicks delete, the loop will still run, but all that happens is isDeleted gets set to true. Simple!