The add form...
... and the edit form...
... are almost the same. Can we combine their code? Have one page to do both?
Ethan
Why do that?
Good question, Ethan. The same code will work add and edit, or most of it will, anyway. If we change things, like add a new field to comedians, we only have to change one program, not two.
Differences
Here's the edit workflow again.
The differences from the add page are marked.
The edit page loads existing data from the DB (1), before showing the form. The add form doesn't do that.
The edit page sends the comedian's id to the processing page (2). The add form doesn't.
They use different SQL (3).
There are other minor things, like page title, but that's mostly it.
Our goal is to have one page, with one URL, handle the form for add and edit.
How to tell edit from add?
We need a way on our form program to tell edit from add. How?
Adela
Well, edit has an id, like, which comedian you're editing. When you add a new comedian, there isn't an id. Could we use that?
Hmm, maybe. How will we know whether the form has an id or not? There will be just one URL for both operations, remember.
Georgina
Oo! Check the URL! Edit has ?=comedian_id=something
on the end. Add does not.
Right! If there's an id there, it's an edit. If not, it's an add.
Code
We're going to look at code for the form, but before we do, notice that three variables are central:
$comedianId
$comedianName
$comedianComments
Each one is a field of the comedian entity. Let' call them field variables (FVs).
Here's how they change during the program.
- The field variables are set to MT.
- If it's an edit:
- Replace the current values of the field variables with values from the DB.
- If there's POST data:
- Replace the current values of the field variables with values from the POST.
- If the field variables contain good data:
- Put the field variables into the session.
- Jump to processing.
- Show widgets, with values from the field variables.
OK, so what happens if the user (Alice) is starting to add a new record?
Hi! I'm Alice!
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: No, skip it, leave FVs MT
- Replace the current values of the field variables with values from the DB.
- If there's POST data: No, skip it, leave FVs MT
- Replace the current values of the field variables with values from the POST.
- If the field variables contain good data:
- Put the field variables into the session.
- Jump to processing.
- Show widgets, with values from the field variables. Show MT widgets
That's what we want. MT widgets.
Now, suppose Alice is adding a new entity, types some invalid data, and hits the submit button. Here' what happens next.
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: No, skip it, leave FVs MT
- Replace the current values of the field variables with values from the DB.
- If there's POST data: There is
- Replace the current values of the field variables with values from the POST. Do it
- If the field variables contain good data: Nope
- Put the field variables into the session.
- Jump to processing.
- Show widgets, with values from the field variables. Show widgets with values from the POST
That's what we want. Alice sees the values to she typed.
Alice fixes the errors, and submits again:
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: No, skip it, leave FVs MT
- Replace the current values of the field variables with values from the DB.
- If there's POST data: There is
- Replace the current values of the field variables with values from the POST. Do it
- If the field variables contain good data: Yes
- Put the field variables into the session. Do it
- Jump to processing. Jump
- Show widgets, with values from the field variables.
That's what we want. The processing page will get the values that were in the POST, which we know are valid.
OK, let's go to edit. Alice clicks a link to edit an existing record.
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: Aye
- Replace the current values of the field variables with values from the DB. Do this
- If there's POST data: Nope
- Replace the current values of the field variables with values from the POST.
- If the field variables contain good data:
- Put the field variables into the session.
- Jump to processing.
- Show widgets, with values from the field variables. Show widgets with data from the DB
That's what we want. The form shows the current data for the entity, from the DB.
Alice changes one of the fields, but makes an error.
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: Aye
- Replace the current values of the field variables with values from the DB. Do this
- If there's POST data: Aye
- Replace the current values of the field variables with values from the POST. Do it
- If the field variables contain good data: Nope
- Put the field variables into the session.
- Jump to processing.
- Show widgets, with values from the field variables. Show widgets with data from the POST
That's what we want.
Alice fixes everything.
- The field variables are set to MT. Do this, FVs MT
- If it's an edit: Aye
- Replace the current values of the field variables with values from the DB. Do this
- If there's POST data: Aye
- Replace the current values of the field variables with values from the POST. Do it
- If the field variables contain good data: Indeed
- Put the field variables into the session. Do it
- Jump to processing. Jump
- Show widgets, with values from the field variables. Show widgets with data from the POST
That's what we want. W00t!
Here's the code:
- <?php
- /**
- * Add/edit comedian.
- * This page validates, as well as showing the form.
- */
- session_start();
- require_once 'library/useful-stuff.php';
- $errorMessage = '';
- // Make variables for field values.
- // Initialize them.
- $comedianName = null;
- $comedianComments = null;
- // If edit, there will be a comedian id in the URL.
- $comedianId = getParamFromGet('comedian_id');
- if (! is_null($comedianId)) {
- // Edit.
- $errorMessage = checkComedianId($comedianId);
- if ($errorMessage == '') {
- // Load existing data.
- $comedianEntity = getComedianWithId($comedianId);
- if (is_null($comedianEntity)) {
- $errorMessage = "Sorry, something went wrong loading comedian with id $comedianId";
- }
- else {
- // Store entity field values in variables, for later.
- $comedianName = $comedianEntity['name'];
- $comedianComments = $comedianEntity['comments'];
- }
- }
- }
- // Is there post data?
- if ($errorMessage == '' && $_POST) {
- // User filled in data and sent it to this page.
- // Grab the data filled in.
- // It will overwrite existing data in the field variables.
- $comedianName = getParamFromPost('name');
- $comedianComments = getParamFromPost('comments');
- // Validate.
- $errorMessage .= checkName($comedianName);
- // Is everything OK?
- if ($errorMessage == '') {
- // No errors.
- // Stash data for processing later.
- $_SESSION['comedian_id'] = $comedianId;
- $_SESSION['comedian_name'] = $comedianName;
- $_SESSION['comedian_comments'] = $comedianComments;
- // Off to processing.
- header('Location: save-comedian.php');
- exit();
- }
- }
- ?><!doctype html>
- <html lang="en">
- <head>
- <?php
- if (is_null($comedianId)) {
- $pageTitle = 'Add comedian';
- }
- else {
- $pageTitle = 'Edit comedian';
- }
- require_once 'library/page-components/head.php';
- ?>
- </head>
- <body>
- <?php
- require_once 'library/page-components/top.php';
- print "<h1>$pageTitle</h1>\n";
- if ($errorMessage != '') {
- print "<p class='error-message'>$errorMessage</p>\n";
- }
- ?>
- <form method="post">
- <p>
- <label>Name:
- <input type="text" name="name" value="<?php
- if (! is_null($comedianName)) {
- print $comedianName;
- }
- ?>">
- </label>
- </p>
- <p>
- <label>Comments:
- <textarea name="comments"><?php
- if (! is_null($comedianComments)) {
- print $comedianComments;
- }
- ?></textarea>
- </label>
- </p>
- <p>
- <button type="submit">Save</button>
- </p>
- </form>
- <?php
- require_once 'library/page-components/footer.php';
- ?>
- </body>
- </html>
Line 15 works out whether it's an add, or edit, by seeing if there's an id at the end of the URL.
- $comedianId = getParamFromGet('comedian_id');
- if (! is_null($comedianId)) {
It it's an add, $comedianId
will be null. If an edit, $comedianId
will have the id of the comedian to change.
Line 48 sends data for processing. It looks like one page, save-comedian.php
, will handle both adding, and updating.
- header('Location: save-comedian.php');
Lines 56 to 61 set the page title, depending on the operation.
- if (is_null($comedianId)) {
- $pageTitle = 'Add comedian';
- }
- else {
- $pageTitle = 'Edit comedian';
- }
Ray
Gotta say, it's satisfying being able to understand how it works.
Aye, it is! You've learned a lot.
Processing
Here's the code that saves the data.
- <?php
- session_start();
- require_once 'library/useful-stuff.php';
- // Get the data to save.
- $comedianId = $_SESSION['comedian_id'];
- $comedianName = $_SESSION['comedian_name'];
- $comedianComments = $_SESSION['comedian_comments'];
- // Save the data into the DB.
- if (is_null($comedianId)) {
- $sql = "
- INSERT INTO comedians (
- name, comments
- )
- VALUES (
- :name, :comments
- )
- ";
- $params = [
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ];
- }
- else {
- $sql = "
- UPDATE comedians SET
- name = :name,
- comments = :comments
- WHERE
- comedian_id = :id;
- ";
- $params = [
- 'id' => $comedianId,
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ];
- }
- /** @var PDO $dbConnection */
- $stmnt = $dbConnection->prepare($sql);
- $isWorked = $stmnt->execute($params);
- if (is_null($comedianId)) {
- // Get the id of the new comedian.
- $comedianId = $dbConnection->lastInsertId();
- }
- // Jump to the view page, passing new record id.
- header("Location: view-comedian.php?comedian_id=$comedianId");
Line 9 decides whether to run INSERT or UPDATE, based on whether there's an id.
Line 39 is a little different. It runs for both INSERT and UPDATE:
- $isWorked = $stmnt->execute($params);
But earlier, did this for INSERT...
- $stmnt->execute([
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ]);
... and this for UPDATE...
- $stmnt->execute([
- 'id' => $comedianId,
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ]);
The second one has an extra value, since UPDATE needs to know which id it's editing.
Notice that both execute
s use an array. You can tell because of the brackets: [ ]
. The array are different. One has an extra element.
So, I extracted the array from execute()
. The INSERT code does this:
- $params = [
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ];
The UPDATE code does this:
- $params = [
- 'id' => $comedianId,
- 'name' => $comedianName,
- 'comments' => $comedianComments
- ];
This runs for both:
- $isWorked = $stmnt->execute($params);
Exercise
todo
Up next
Let's help the user delete comedian records.