In “Avoiding orphaned records” earlier in the chapter, I told you that using foreign key constraints in InnoDB tables automates the preservation of referential integrity. It does—
in the sense that it prevents you from deleting records in a parent table if there are still dependent records in a child table. Figure 16-16 shows what happened when I tried to delete William Shakespeare from the authorstable using InnoDB with a foreign key con- straint defined.
Figure 16-16.A foreign key constraint prevents the deletion of a record while it still has dependent records in a child table.
When I did the same thing with MyISAM tables, William Shakespeare vanished into cyber- oblivion without so much as a by-your-leave to his children. So, foreign key constraints are a good security measure, but you don’t want an ugly MySQL error message like that in Figure 16-16 on your website. Consequently, even if you’re using InnoDB tables, you need to incorporate the same sort of checks into a delete page as with MyISAM tables. In other words, when deleting a record from a parent table, you need to do the following:
1.Search the child table to see whether the record’s primary key has any matches in the foreign key column. In the example in Figure 16-2 earlier in the chapter, Shakespeare’s primary key is 32. So before you can delete his record, you need to check whether any records in the quotationstable have the same value as the for- eign key (author_id).
2.If there are any matches, display a message saying that the deletion cannot go ahead, and hide the delete button.
If there are no matching records, display the delete button, asking for confirmation.
The conditional logic that you used in the insert and update forms checked whether an author was already registered in the authors table. For the delete form, you need to perform a similar check, only this time in the quotationstable. Although you’re check- ing a different table, the script flow is exactly the same. If there are any matching records, you stop the server behavior from being executed. Otherwise, you let it go ahead. Consequently, you can adapt the existing script quite easily.
1.Open author_update.php, and save it as author_delete.php.
2.Change the title and heading to Delete Author. Use the Property inspector to change the Button nameand Valueof the submit button to deleteand Delete author, respectively.
3.In the Server Behaviors panel, highlight Recordset (checkAuthor), and delete it by clicking the minus button.
4.Do the same with Update Record.
5.Click the plus button in the Server Behaviorspanel, and select Delete Record. As in the previous chapter, you get the value of the record to be deleted from a hidden field, so make sure you choose Form Variablefor Primary key value. Check that your settings are the same as shown in the screenshot, and click OK.
6.Before deleting a record from the authorstable, you must check whether its pri- mary key is still in use in the quotations table. Create a new recordset called checkForeign. Use the Recordset dialog box in Advanced mode with the settings shown in the following screenshot:
Adapting the author update page to handle deletes
16
The WHEREclause selects records where quotations.author_idis equal to a vari- able (we’ll define that in a moment) and where quotations.author_idis the same as authors.author_id. As explained in the “The four essential SQL commands”
earlier in the chapter, the dot notation tableName.columnNameeliminates ambigu- ity in a SQL query when columns in different tables have the same name. What this SQL query is looking for is any record where author_idmatches the runtime vari- able var1.
7.The value of author_idis passed through the query string from author_list.php, so var1needs to be defined in the Variablesfield. Click the plus button alongside Variables, and use the following settings:
The primary key,author_id, is a number, so Typeneeds to be set to Integer. I have set Default Value to -1 because I don’t want the variable to default to a genuine value. Runtime valueis set to $_GET['author_id']because the value is passed through a query string in the URL. Remember, $_GETis used for URL variables and $_POST for form variables submitted using the POSTmethod. Click OKto close the Add Variabledialog box, and click OKagain to save the recordset.
8.Now it’s time to move the Delete Record server behavior from its current position so that it’s inside the elseclause previously occupied by both the Insert Record and Update Record server behaviors. Locate the following code, and cut it to your clipboard:
9.Paste the code from your clipboard to the position indicated here:
10.Next, amend the code shown on lines 54–59 of the preceding screenshot to match the name of the checkForeignrecordset like this:
// assume that no match has been found
$recordsExist = false;
//check whether recordset found any matches if ($totalRows_checkForeign > 0) {
// if found, reset $recordsExist
$recordsExist = true;
} else {
11.Scroll down until you find this line (it should be around line 90):
if ($_POST && $alreadyRegistered) {
The check for $_POSTis not needed this time, because the checkForeignrecordset will be created as soon as the page loads. You also need to change the variable to
$recordsExist. Change the line to look like this:
if ($recordsExist) {
12.In the next line, $_POST['first_name']and $_POST['family_name']need to be replaced with dynamic data from the checkForeign recordset. Highlight
$_POST['first_name'], and open the Bindings panel. Expand Recordset (checkForeign), select first_name, and click the Insert button. This will replace
$_POST['first_name'] with $row_checkForeign['first_name']. Do the same with $_POST['family_name'], selecting family_namefrom the Bindingspanel.
13.Change the remaining text in the warning paragraph, and add the opening part of an elseclause so that the entire PHP code block now looks like this:
<?php
if ($recordsExist) {
echo '<p class="warning">'.$row_checkForeign['first_name'].' '. ➥
$row_checkForeign['family_name'].' has dependent records. Cannot ➥ be deleted.</p>';
} else {
?>
16
14.Scroll all the way down to just after the closing </form>tag (around line 107), and insert a closing curly brace inside a pair of PHP tags like this:
<?php } ?>
What you have done is enclose the entire form in an elseclause, so it will be dis- played only if there are no dependent records in the quotationstable.
15.Switch back to Design view, click immediately to the right of the first PHP shield at the top of the page, and press Enter/Return to create a new paragraph. Type a warning that the delete operation cannot be undone, and apply the warningclass to the paragraph.
16.Save author_delete.php, and load author_list.phpinto your browser. Select an author that you know has dependent records in the quotationstable, and click DELETE. You should see a message like this:
17.Now insert a new author. When the name appears in the list, click DELETE. This time you should see a screen like the following one. Click Delete author. You will be taken back to the list of authors, and the new entry will have disappeared without a trace. You can check your code against author_delete.phpin examples/ch16.