How would you use OOP to handle a form?

I’ve used PHP for basic procedural coding, and I’d like to start using an object-oriented approach. I get the syntax, and I get the concept, but I’m having trouble translating it to the real world. So suppose you have a basic form that you validate and then save. With a procedural approach, you’d do something like this (pseudocode with a PHP flavor).

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    validate form
    if ($no_errors == TRUE) {
        save form data
        $form_message = 'some confirmation message';
    }
    else {
        $form_message = 'some error message';
    }
}
else {
    //must be first time through
    $form_message = 'hello, please fill this out';
 }
?>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <h1>Customer Form</h1>
    <h2><?= $form_message ?></h2>
    <form method="post">
        <field 1>
        <field 2>
        <field 3>
        <field 4>
    </form>
</body>
</html>

So, PHP coders more advanced than me, how would you use OOP for the above? To clarify, I’m not looking for a general form processing engine. That’s way too complex for now. I’m just looking to translate the above into the OOP paradigm. Thanks!

Hi Robert,

With OOP, the code you’ve shown would pretty much stay the same - it’s the code you haven’t shown that would be different. Commonly you’d have a class to handle the form validation, and then another to handle saving the data. If you want some more specific information on this, feel free to ask.

While not really anything to do with procedural vs OOP, one thing I would do is separate the different concerns here into their own files - roughly speaking, one for your HTML, one or more for your model (in this example, for validating and saving the data) and one which controls the process. This pattern is often referred to as MVC, and is a very common way of structuring an application. It’s worth checking out this article for more detail on going from a flat PHP file (like your example) to a proper separation of concerns.

4 Likes

Ok, I think I get what you’re saying. Assuming it was a very simple form to sign up newsletter subscribers, you’d have a subscriber class with methods to echo the form, validate the data, and save the data (not working withing the MVC paradigm, of course). Then your main code indeed would look like pseudocode because all the details had been pushed down to the class.

I’m familiar with MVC, though I’ve never implemented an MVC system from scratch. I like Codeigniter, which was dying, but now has picked up with new owners and version 3. But aside from the controller and model classes Codeigniter requires you to create, I have not created any other classes in it.

No, those would be three separate responsibilities, so I’d split those into separate classes. Even if you’re not adhering to some sort of MVC pattern (there’s really no reason not to have some sort of separation of concerns), good OOP design involves having small classes which only have a single responsibility (I’d suggest reading about the SOLID design principles). Classes that do too much are difficult to change without risking breaking other parts of your application, and difficult to reuse.

Here’s an example of how your code might look using objects:

<?php

$errors = array();

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $form = new SubscriberFormValidator($_POST);
    
    if ($form->isValid())
    {
        $subscriber = new Subscriber;
        $subscriber->values($form->getValues());
        $subscriber->save();
        
        header('Location: http://www.example.com/subscribers/success.php');
        exit;
    }
    else
    {
        $errors = $form->getErrors();
    }
}

$view = new View('templates/subscribe_form', compact('errors');
echo $view->render();

It’s worth noting that using MVC (or some variation thereof) doesn’t mean having to use a framework, although I believe the majority of PHP frameworks to stick to MVC or something similar. It’s much easier to work on an app when the application logic and the database access isn’t all mixed together with the HTML like a giant plate of spaghetti!

1 Like

Ok, I hadn’t heard about SOLID before. Some of my confusion stemmed from having picked up somewhere that changes shouldn’t affect multiple classes. In other words, one class shouldn’t know anything about another class. The way you broke it down, for form validation class has to know what data the subscriber class defines as valid. Also, if we add a field to subscriber, for example, we’ll have to make changes to all three classes. I think it also doesn’t help that OO is often taught as modeling actual, real-life objects. It may not be the best example of this, but the Wiki intro to OO says,

Objects sometimes correspond to things found in the real world. . . . An online shopping system will have objects such as “shopping cart,” “customer,” and “product.” The shopping system will support behaviors such as “place order,” “make payment,” and “offer discount.”

Sounds more like “place order” and “make payment” would be two different classes, not two different methods in the Shopping_cart class?

The info on SOLID helps clarify things for me. Thanks.

I did know about separation of concerns. The only PHP I mix with HTML is to echo values and a few IFs to determine if we echo this or that, but no actual processing code.

Hi Robert, sorry for the late reply.

In this example there might initially be a correspondence between the properties of the input form and the database model, but that’s not necessarily always going to be the case. Often we want to include additional form fields, such as captcha inputs or password confirmation fields, that aren’t reflected in the data model. A degree of coupling between the validation and the persistence classes is inevitable, but it’s a trade off against the benefits of following the Single Responsibility Principle (SRP).

The Wikipedia article doesn’t actually state that those methods are part of the shopping cart class. In reality, you might have an Order class which contains behaviour related to the processing the order (and is constructed from a ShoppingCart object).

We might actually want a makePayment() method on our Order class, but you’re right to think that making a payment is a separate responsibility, and there are good reasons for keeping it that way: we might initially create our e-commerce system to only accept credit card payments, but what happens if later we decide to add payment via PayPal? If we put the payment logic in the Order class, we’ll have to modify it every time we want to add a new payment system, which is not a good design.

Instead we make the implementation of the payment processors the responsibility of separate classes, so we might end up with CreditCardProcessor and PaypalProcessor which we’d pass to the makePayment method:

$paymentProcessor = new PaypalProcessor;
$order->makePayment($paymentProcessor);

There are also other techniques we can use to avoid objects having too many responsibilities. Objects can be aggregates - that is, we can pass other objects into the constructor, which are stored as properties and delegated to internally for certain functionality.

No problem, and good to hear from you.

There are also other techniques we can use to avoid objects having too many responsibilities. Objects can be aggregates

I went and found an excellent example included in the well known Head First book on OO patterns. I think it’s the first one in the book. It’s called the Decorator Pattern, and it allows dynamically creating objects that weren’t even foreseen. The example itself is about coffee, to which you can add soy, milk, mocha, foam, etc, in any combination and in any quantity.

I think I’ll resort to that when I rewrite a finished PHP application I have. The application lets users take surveys. The surveys are described in INI files. Surveys have a variable number of sections with different types of questions: single answer, multiple answer, etc. That seems well suited to aggregate objects.

But I still need to learn more about breaking the application down into classes/objects. I’ve downloaded a couple of free ebooks on that, which I’ll be hitting after Christmas.

Have a Merry Christmas!

Here I have broken down the survey application I mentioned into classes/objects. What do you think?

You may have to view it at 100% zoom to read it. I have the form object create both the initial form and the confirmation form, which shows the entered data and has all controls disabled. Does that violate the single purpose rule? I hope it doesn’t.

Hi Robert,

Thanks, Christmas went very well! How was yours?

I’m assuming that your Loader class is reading in the questions/specification for a given survey from somewhere (DB or a file, perhaps) and the Form class then builds the HTML for the form from the specification? That looks reasonable to me, although I’d also have a class in there for loading a view template in which to display the form and any status messages to the user.

No, for me that would still be part of the class’s responsibility of creating a HTML form from a set of data. Whether the inputs contain values, or are enabled/disabled is determined by what data you pass into the class.

Thank you, I had a nice Christmas with my family.

I’m assuming that your Loader class is reading in the questions/ specification for a given survey from somewhere (DB or a file, perhaps) and the Form class then builds the HTML for the form from the specification?

Yes. On purpose, my app doesn’t use a DB. The survey is described in a text file in INI format

// sample_survey.ini
[meta]
name = "Sample Survey"
hello = "Please complete this survey"
goodbye = "Thank you for taking this survey!"

[section_1]
type = 1
title = "Preferences"
questions[] = "What size Coke do you prefer?"
questions[] = "What size popcorn do you prefer?"
questions[] = "What size candy bar do you prefer?"
answers[] = "Small"
answers[] = "Med."
answers[] = "Large"

[section_2]
type = 2
title = "Lifestyle"
questions[] = "What kind of car do you drive?"
answers[] = "I don't drive"
answers[] = "Honda"
answers[] = "Toyota"
answers[] = "Ford"
answers[] = "General Motors"
answers[] = "Other"

[section_3]
type = 3
questions[] = "Things you like about your job"
answers[] = "Short commute"
answers[] = "Good supervisor"
answers[] = "Fulfilling"
answers[] = "High status"
answers[] = "Fun environment"
answers[] = "Pays well"
answers[] = "I don't like my job"

I chose INI over XML format because PHP has a very convenient function that loads an INI format into an array. I accumulate the results of the survey to a CVS file by the same name as the INI file. The difference between type 2 and type 3 is that type 2 accepts only one answer, while type 3 is “check all that apply.”

I'd also have a class in there for loading a view template in which to display the form and any status messages to the user.

Once my form object creates the form, its render method just echoes the form out. By view template, do you mean an HTML skeleton with placeholders where PHP can insert values? I’ll try that but the skeleton would be very minimal, consisting of little more than the html, head, and body tags. Because each survey can be so variable, the entire form has to be built from scratch. However, I only have loops and conditionals mixed in with the HTML code. Still the code is messy and I don’t see how to avoid that. Here’s the procedural code for building the input control for a type 2 survey question.

case 2: // 2 = One question, multiple choice, single answer
  // output question
  echo '<p>', $qnum++, '. ', $section_data['questions'][0], '<br />', 
    '<input type="hidden" ', 'name="form_data[', $section_name, '][responses][0]" ',
    'value="0">', "\n";
  // output answer choices
  foreach ($section_data['answers'] as $k => $answer) {
    echo '<input type="radio" ',
      'name="form_data[', $section_name, '][responses][0]" value="', ($k + 1), '"',
      (($form_data[$section_name]['responses'][0] == $k + 1) ? ' checked="checked"' : ''),
      (($caller == 'confirm') ? ' disabled="disabled"' : ''), '>', $answer,
      (($k < count($section_data['answers']) - 1) ? '<br />' : '</p>' . "\n"), "\n";
  }
  break;

The HTML the messy code produces, however, is nice and clean, in my opinion.

<h3>Lifestyle</h3>
<p>5. What kind of car do you drive?<br />
<input type="hidden" name="form_data[section_2][responses][0]" value="0">
<input type="radio" name="form_data[section_2][responses][0]" value="1">I don't drive<br />
<input type="radio" name="form_data[section_2][responses][0]" value="2">Honda<br />
<input type="radio" name="form_data[section_2][responses][0]" value="3">Toyota<br />
<input type="radio" name="form_data[section_2][responses][0]" value="4">Ford<br />
<input type="radio" name="form_data[section_2][responses][0]" value="5">General Motors<br />
<input type="radio" name="form_data[section_2][responses][0]" value="6">Other</p>

that would still be part of the class’s responsibility of creating a HTML form from a set of data.

I’m relieved to hear that. The more I search on the single responsibility principle, the more it seems like it’s a holy grail that lots and lots of people don’t follow. There are tons of sample applications out there where the classes model things like cats and dogs, and the dog class has methods for eat, run, bark, and roll over.

Anyway, I realize you’re not a personal tutor, but if I could ask your opinion on one final question. Which is the better practice when methods in two different classes work on the same piece of data: one, pass the data to the method in the second class as an argument and receive it back as a returned value, or two, keep the data as a public property in the first class and have the second class access it in the first class? Here is a contrived example of each.

// example of first way
class A {
    public $pi = 3.1415
    function whatever() {
        $x = new B;
        $y = $x->modify($this->pi);
        echo 'modified pi to ', $y
    }

class B {
    function modify($pi) {
        $new_pi = transmogrify($pi);
        return $new_pi;
    }

// example of second way
class A {
    public $pi = 3.1415
    function whatever() {
        $x = new B;
        $x->modify();
        echo 'modified pi to ', $this->pi;
    }

class B {
    function modify() {
        transmogrify($a->pi);
    }

Thanks a lot! You’ve been very helpful. Best wishes for the new year!

That is a framework to handle all of that. Otherwise you’d need a class thats able to create the form. Then a class that can render it, and a class that validates it. The validation class could be feed the form data which would have the validation rules per element.

1 Like

Hi Robert,

I’d recommend taking a look at the zebra-form library that animedreamz73 linked to, especially the add() method of the main class and the individual input type classes it delegates to. It should give you some ideas you could use to build an object oriented version of your form builder.

How you define a class’s responsibility is important - you don’t want to split up responsibilities too finely or too coarsely (and end up with ‘God’ classes that do way too much). Also, keep in mind that the SRP is only a principle, not a hard and fast rule, and is supposed to guide you towards good design. It has to be balanced against other concerns such as the level of cohesion between your class methods.

A class with high cohesion will contain methods that are closely related in terms of their functionality - they make sense being grouped together. In the case of your dog class, it makes sense for it to contain eat, run and bark methods as they are all things that a dog does, not something external that is done to a dog.

Another thing to keep in mind when designing a class though is always think about what is likely to change. If there’s a possibility you might want to alter or substitute some functionality later on then it would be better off in a separate class. Going back to the dog example, you could make the argument that rolling over is a trick, and you might want to teach the dog new tricks in future. In this case, the tricks would be better off as separate classes.

Generally it would be better to pass the value you want to work with into the method that does the work, as this doesn’t couple class B to class A - the value could in fact come from somewhere else and the code would still work, so your class is more easily reusable.

Having said that, where possible, the data and the methods that operate on it should be packaged together in the same object, as that’s really one of the core ideas behind OOP.

Thanks, for you too :slight_smile:

1 Like

Generally it would be better to pass the value you want to work with into the method that does the work, as this doesn’t couple class B to class A

Argh! Yes, of course! And I know that. I know about not coupling functions or modules together tightly. I just need to take that knowledge to OOP. I swear, I’m setting up my own mental blocks here.

Ok, thanks again, and back to the salt mines for now. :smile:

I apologize for not having thanked you earlier. Thank you! That framework you suggested is just perfect as an example of how to do it. It’s not too big nor too small. It’s very helpful to illustrate exactly what I was asking in this thread.

Yep, I been in the game a long time, just remembered this project from a while back. Glad it could help you.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.