Приглашаем посетить
Культурология (cult-lib.ru)

Modeling a Complex Web Component

Table of Contents
Previous Next

Modeling a Complex Web Component

In this section we'll model the form engine discussed as a God class earlier. In this example, you'll learn even more ways to structure your objects as well as a few neat design patterns that you can use for other problems. Let's define the requirements for our form engine. The form engine should:

It might seem like a complex module at first, but if we keep the architecture simple and design it correctly we will have eliminated the complexity to a large extent. There is actually a more flexible design to a form engine, but it requires many other external classes for it be constructed. The point of this example is to illustrate all the concepts we've learned up to this point and see how to build it using objects.

First, a Form object needs to be defined since it is the main object in our engine. A form should be able to display itself using a style, add elements and buttons, create the client-side validation code (using JavaScript code), be able to validate itself on the server, and display the complete error message should anything go wrong with the validation.

Next we'll need an object structure to model all the possible form elements and buttons that can be added to the form. We'll use a parent class called FormElement and we'll extend it to include all our form elements that we wish to add. Some possible form elements can be text fields, date fields, text areas, passwords, file uploads, or multi-selection combo boxes. By making FormElement the parent class and taking advantage of polymorphism, we'll be able to add as many form elements as we want without changing the logic to display, validate, and generate JavaScript code. Let's look at the object model:

Click To expand

This model is a pretty standard containment-inheritance hierarchy that we've seen in the examples in this chapter except for two curveballs. For one, the containment showed in the diagram states that form elements are not contained inside forms. Though they are physically contained inside forms, they behave differently when the Form object is first constructed. We have added methods, namely addElement() and addButton(), to add form elements to the form. A form with no elements is still valid although not really useful.

The second complexity is the containment relationship and add() methods in the ComboBox and MultiComboBox objects. This makes it easy to add elements to a combo box just like it would be to add it to the form. It's practically transparent. The importance of our code lies in the fact that the display() method from any FormElement subtype can be implemented in any way. We can simply draw the select tags and option tags as we need to and we won't be violating any rules described in our inheritance model. A smaller and similar inheritance structure can be made for the buttons:

Click To expand

So now we have a good foundation for the form structure, but how do we make it look good? We'll use a separate FormStyle class that will allow us the possibility of styling our forms in any way we choose. Here we choose to use HTML. Often the presentation logic of the object is placed in the same location as the application logic, which is not good practice. Style components or decorators give us the opportunity to put this presentation logic elsewhere, making our object more cohesive. An inherent benefit from using decorators or style components is that you can change the style of the object without having to change the object's logic, which makes it more maintainable as well as reusable.

We will use the power of delegation to style our forms. A common design pattern is to use a decorator object to add extra presentation information to an object. It is easier to implement a contained object due to the structured nature of HTML. This makes the entire model flow much nicer and there aren't any drawbacks as we still achieve the same functionality in comparison to using a decorator class.

Here is a simple UML diagram that illustrates a form with a style component:

Click To expand

Here, I extended the FormStyle class with three styles. The DefaultStyle is the style that is chosen by the Form object in its constructor. The others are two arbitrary styles that could be replaced by anything you like. With this architecture we can have forms looking very fancy by only creating new style objects:


    $form->setStyle(new ExtraNetStyle());
    $form->display();

If we wanted to change the colours to something a bit different, we would just have to change the line of code as shown below:

    $form->setStyle(new NewStyle());
    $form->display();

and we will not have to change any of the form engine's logic.

The second last piece of code to output the form engine is a data validation object. We already built one when we were talking about delegation. The object model for this is shown below:

Click To expand

To manage multiple forms, we'll need the actual FormEngine object, which is our last object. This FormEngine will be our tool to manage multiple forms and will be the guide to reproduce the JavaScript library code when using multiple forms. This object also acts as a factory class since we can create forms through it. Here is the object model:

Click To expand

The reason why we have the FormEngine object create forms is that it can tabulate the details that are needed for the JavaScript code. This is so we can have multiple forms with client-side data validation. That nearly completes our form. Here is some sample code showing how easy it is to construct the form that was displayed earlier:

    $formEngine = new FormEngine();
    $form = $formEngine->create("form", "Form Name", $PHP_SELF, "post");

    $form->addElement(new FormHeader('General Information'));

    $form->addElement(new TextField('name', '', 'Name', ALPHA,
        "You have failed to enter your name", true));

    $form->addElement(new HiddenField('userID', '1'));

    $form->addElement(new PasswordField('password', '', 'Password',
        PASSWORD,
        "You have failed to choose a password larger than 4 characters",
        true));

    $form->addElement(new TextField('email', '', 'Email Address', EMAIL,
        "You have entered your email address incorrectly", true));

    $form->addElement(
        new TextArea('description', '', 'Description', ALPHANUMERIC,
            "You have failed to enter any description about yourself",
            false, array("rows" => 10, "cols" => 40,)));

    $form->addElement(new DateField('startdate', '', 'Start Date',
        false));

    $form->addElement(new FileBrowser('file', 'File', false));

    $combo = new ComboBox('wagetype', 'S', 'Wage Type', true);
    $combo->add('Hourly', 'H');
    $combo->add('Salary', 'S');
    $form->addElement($combo);

    $combo = new MultiComboBox('position', $position, 'Position', false);
    $combo->add('Planner', 'P');
    $combo->add('Manager', 'M');
    $combo->add('Engineer', 'E');
    $combo->add('Analyst', 'A');
    $form->addElement($combo);

    $form->addButton(new SubmitButton('submit', 'Submit'));
    $form->addButton(new ResetButton('reset', 'Reset'));

    if ($submit == 'Submit') {
        $isValid = $form->validate();

        if ($isValid) {
            echo("everything okay");
            // start processing info into database or whatever
        } else {
            echo($form->getErrorMessage());
            $form->display();
            $formEngine->displayJavascriptLibraryCode();
            echo($form->generateJavaScriptCode());
        }
    } else {
        $formEngine->displayJavascriptLibraryCode();
        $form->display();
        echo($form->generateJavaScriptCode());
    }

What, no code about the implementation? What ever am I to do? That's an easy question to answer; write it. If you're going to learn OO and appreciate all the concepts that you've learned, your first attempt should be to complete this module. It's not an entire waste of time since you'll be able to use it a lot in your programs. Say goodbye to those free modules on the net and use something that you've created on your own, something that you can say you understand the foundation of, beyond the code.


Table of Contents
Previous Next