Now that we know how to include things from other files, we can start talking about a hugely important programming concept:

Separation of Concerns...

is the principle that every component of a program should do exactly one thing, or more generally, that each thing is responsible for one "concern".

Every function does one thing. Every file contains the code for one aspect of the program's overall work.

For instance, in a program that shows a form for the user to fill out and then does something with the data, we have (at least) 3 general concerns:

  1. Displaying the form to the user,
  2. Getting the response from the user, and
  3. Processing the submitted response.

So, at a minimum, we can think of our program being composed of 3 files, one that contains the code that displays the form, and another that contains code for processing the response, and a third that decides what to show when, and where to send the incoming data.

Quite likely, the program will use some kind of data modeling to do it's processing. So very quickly we'll have to deal with a 3rd concern -- data modeling.

These three overall concerns are commonly separated into a schema called Model, View, Controller (MVC). The Model is the "business logic" that addresses the need or needs the program is trying to solve. The View is how the information is presented to various users at different points during the program's operation. The Controller is the logic that determines what view needs to be shown at any point, and then what to do with any information the user sends back, routing it back to the relevant data Model.

Let's build a simple program to get a feel for this.

Exercise

Because this is a new program, let's make a new directory in your PHP root directory, let's call it snacktime. Then our first file in the new directory is index.php. We call it index.php because that's the name of the file the webserver will look for by default in any directory, and the Controller will be the default starting point for any interaction with our program. It will allow us (on most webservers) to access the program in the browser by entering the url:

http://localhost/snacktime/

Next, we'll need a View file to allow the user to pick a snack from a snack menu. Create a second file in the snacktime directory called menu.php.

And finally, we'll need a file to process the data the comes back (our Model file). Let's call it kitchen.php.

First off, we need our controller to present the menu. That's easy enough with our include statement:

<?php
include 'menu.php';

So at the start, our Controller pulls in the contents of the menu. We just need to make sure the menu has something to show our hungry snackers. In a web browser we do that by displaying text in HTML (Hyper Text Markup Language) format.

In our menu.php file, let's put the following:

<!doctype html>
<html lang="en">
<head>
    <title>Snack Menu</title>
</head>
<body>
<h1>Snack Menu</h1>
<form method="post">
    <p>Choose a snack!</p>
    <p>
        <label for="apple-button">Apple</label>
        <input id="apple-button" name="snack-choice" type="radio" value="apple"><br>
        <label for="banana-button">Banana</label>
        <input id="banana-button" name="snack-choice" type="radio" value="banana"><br>
        <label for="cookie-button">Cookie</label>
        <input id="cookie-button" name="snack-choice" type="radio" value="cookie">
    </p>
    <p><input type="submit" name="submit" value="Place Order"></p>
</form>
</body>
</html>

Notice there's no PHP at all here. It's all HTML. If you've ever worked with a markup language like TeX for a math or science term paper, you'll already have a basic understanding of markup languages in general, but let's go through it to review how HTML is structured.

The markup language idea, generally, is that we can surround anything with "tags" that will tell an interpreter how to display it. HT Markup Language is tailored to web browsers (the interpreter) to allow display of things online enabiling headings, forms, links and such.

In the above, we start with <!doctype html> that tells the browser what kind of markup we're sending. (Browsers can read several other types of markup besides HTML.)

Next is the <html> tag itself, along with an attribute contained in the tag. Tag attributes are key/value pairs that define something the browser needs to know to render the tag correctly. Here we have lang="en" indicating that the document is in English. Everything between <html> and </html> is English HyperText. (We could theoretically, include 2 languages on the same page by sending a second section with <html lang="fr">.)

Other tags used here are:

  • <head> - The Document Head, which is stuff that's not displayed on the page as text, or used in other places around the browser.
  • <title> - The Document Title that the browser shows you in the browser tab when you go to the page.
  • <body> - The stuff that actually shows up on the page.
  • <h1> - A 1st level heading. Standard headings go from <h1> to <h6> and like any term paper headings, are organized in order of importance.
  • <form> - Designating the contents of a form. Duh.
  • <p> - A Paragraph, or basic block of text.
  • <label> - A text label for a form input. The for attribute connects it to the name attribute of the input that it's labeling.
  • <input> - A form input field. These come in several kinds, as indicated by their attribute. Here we are using radio buttons and a submit button.

Note with the radio inputs, that we've given them all the same name attribute. The input's name will become it's identifier when the browser sends it's data back to us. So we use the same name for all the options, and supply a different value to each, so we'll be able to tell which snack-choice shows up when the form gets submitted.

The last thing worth noting about the <form> itself is that we've given it a method="post" attribute. The other option here is method="get". GET will send the form submission as a part of the URL, exposing the submitted info to plain sight. POST hides the submitted data in a different part of the transmission that does not expose the information.

So, now that we've done that, we can load localhost/snacktime/ into the browser bar and with any luck see our menu form displayed.

Now, all we need is to make the magic happen to actually get what we ask for when you click "Place Order"! To do that, we need to look at what happens when we click that button.

<form> actually has another attribute we left off.

<form action="somefile.php" method="post">

would have sent the form's data to somefile.php. Because we left it out, the default is to send the data to whatever is the current file. In our case, that's index.php. When we click that button, the browser packages all that information up into an "HTTP POST request" and sends it back our webserver saying, "here, webserver, this data is for your index.php file to process." Because of the .php filename, the webserver sends it along to the PHP interpretor. The interpreter packages the data up into an array, and then calls the first line of our index.php program where the array is available to us as the variable $_POST.

So... we need to go back to index and see if we have any data. Let's modify index.php as follows:

<?php
if (isset($_POST['submit']) && 'Place Order' === $_POST['submit']) {
    echo 'We have an order!';
} else {
    include 'menu.php';
}

Here, we're just checking to see if the value of our submit button has come back. (Remember we gave our submit input the name 'submit'. If we have a submit key in the $_POST array, we know the form has been submitted and we should process the order instead of showing the menu. We need to make 2 checks here:

First we check if there is a submit item in the $_POST array (because if there is not, checking for the value of something that doesn't exist will give us an error).

Then we check whether the submit has the value we gave it from the form. (If it doesn't we might start to suspect that someone -- a hacker? -- submitted it from somewhere else!)

If either of these check fails, we're going to go straight to a new Menu Order page immediately. Either the form is being loaded for the first time and there is no data to process, or someone is trying to do something nasty, or something has gone so wrong that we need to just start over from scratch.

Give it a try. Select a menu item and click "Place Order". You should see the program get excited about having an order. Or place an order without selecting anything, and get the form again.

So, now that we know we have submitted data to handle, we need to do something in the kitchen!

Let's modify our index.php Controller again to send program flow to the kitchen when we have an order. We want the kitchen to fulfill the order, and inform the Controller of the result. (Then the Controller will have to decide what to do with that, too! But one step at a time.)

Between if and else, let's change our index.php as follows:

...... {
    require_once 'kitchen.php';
    $order = fulfillOrder();
}

And in kitchen.php let's create the "logic" that will get that order out to our snackers.

<?php

function fulfillOrder(): string
{
    if (! isset $_POST['snack-choice']) {
        return 'Sorry, your order ticket was blank.';
    }

    $snackRequest = $_POST['snack-choice'];

    if ('apple' === $snackRequest) {
        return 'apple.png';
    }

    if ('banana' === $snackRequest) {
        return 'banana.png';
    }

    if ('cookie' === $snackRequest) {
        return 'cookie.png';
    }

    return "Sorry, we don't have the snack you requested.";
}

So, in the kitchen, the first thing we do is look to see if we have the right data to work with. Someone might have submitted the form without making a selection. In that case, we return early. There's nothing more we can do.

Next, we load the $_POST['snack-choice'] into our own variable. While this isn't strictly necessary, it's a best practice to not work with the submitted data directly. There are a couple reasons for this:

  • We might need to look at that data again later in another part of the program, and if we change it in the $_POST array other parts of the program using that data will not have access to the original submission. And,
  • Extracting the data from the "raw" submission allows us the chance to check (or "validate") it and if necessary "sanitize" it. User submitted data should always be treated as possibly dangerous, containing mistakes (from well-intentioned users) or attempted program hacks. If we work with the raw submission, we open ourselves up to all kinds of trouble.

(In this example, since we're not putting this out into the wild, and running it only on our sandboxed development server we'll learn how to "clean up" data down the road.)

Once we know we have a request, we go through several possibilities to sort out what it is. In each case we just return a string, which is the name of an image file, which will be our virtual snack.

If we reach the end of the possibilities we know about, we'll return a "Sorry, we don't have that."

Now, back again to the Controller. We have to decide what to do with the fulfilled order. Let's deal first with what happens if the Kitchen tells us the order can't be filled. In that case, we need to tell the snacker what went wrong and give them a chance to try again.

Just before the else, let's handle that situation:

...
    if ('Sorry, your order ticket was blank.' === $order
        || 'Sorry, we don\'t have the snack you requested.' === $order) {
        include 'menu.php';
    } else {

Now, we've got to provide for showing that error message in the menu.php view. Let's add in there:

<h1>Snack Menu</h1>
<?php if ($order): ?>
    <p><?php echo $order; ?></p>
<?php endif; ?>
<form method="post">

Here's an example of processing a bit of PHP inside a template/view file. We open a short php segment to start a conditional, insert the variable, and then close the conditional. (Also note the alternative syntax of the if statement using a colon instead of the opening brackets, and replace closing the brackets with the endif; statement.

Finally, if we have any other response, we know we're ready to serve it up. Let's create a serve.php view file for that:

<!doctype html>
<html lang="en">
<head>
    <title>Service with a Smile</title>
    <style>
        img {
            max-width: 200px;
            height: auto;
        }
    </style>
</head>
<body>
<h1>Service with a Smile!</h1>
<p>Thank you for your order!</p>
<p>Here is your snack:</p>
<p><img src="http://localhost/snacktime/<?php echo $order; ?>"></p>
</body>
</html>

We have a a couple new HTML tags here:

In the <head> section we have <style>, which contains some styling code in a format called CSS. (We'll get to styling things down the road: that's a whole new can of worms!) And we have in the <body> section a new <img> tag that takes a src (source) attribute. We point that source to the URL of an image file, and the browser replaces the tag with the image. So all we need are the image files, which you can download from here by right-clicking the images below, saving them and placing them into your snacktime directory with the appropriate file names.

And with that your snacktime program is complete! Congratulations on your first PHP project!

(And now you deserve to get a real snack from the refrigerator!)

Here are some snack images you can use:

(Feature apple photo by Mackenzie Marco on Unsplash)