Jump to content

Just a second opinion


duclet

Recommended Posts

I am currently writing a script that will hopefully handle all of my form processing in the future. Just started this recently and have only gotten to really finish up a couple of meaningful functions. There isn't any error or problem with it. I just want a second opinion of what people think of the code so far and if there are better ways to do certain things. I have set up a test page at:

 

http://dev.scripts.tiger-inc.com/php/Tests/DLForm.php

 

Obviously, this script uses some functionality of other scripts that I have written so if you see a class or function you don't recognize, just ignore it and assume that the function works as it is intended to be. Since I usually make my function names descriptive, you should be able to guess what that function should do. The comments in the code should be able to explain the process or logic behind things but if you still have questions, feel free to ask.

 

Again, I am only looking for a second opinion to see if there is a better way to handle certain situations. I know there are other scripts out there that handle form creation and stuff but this is only for me. Also, this is by no means complete either. Thanks for any helpful comments to be posted though. Here is the source code:

 

<?php
/* Load neccessary files */
loadClass('DLForm');

/**
* Form Management. This class makes use of the following namespaces:
*
* @author      Duc Tri Le
* @copyright   Copyright (c) 2008, Duc Tri Le
* @version     1.0 - : Initial release.
*              0.0 - February 7, 2008: Started.
*/
class DLForm {
    /* ********************************************************************** */
    /* Data Member */
    /* ********************************************************************** */
    /**
     * The time, in seconds, of how long to keep cached data.
     */
    const CacheTime = 2592000;      // 30 days

    /**
     * Represents an Input Button field.
     */
    const InputButton = 1;

    /**
     * Represents an Input Checkbox field.
     */
    const InputCheckbox = 2;

    /**
     * Represents an Input Checkbox field that is part of a group.
     */
    const InputCheckboxGroup = 13;

    /**
     * Represents an Input File field.
     */
    const InputFile = 3;

    /**
     * Represents an Input Hidden field.
     */
    const InputHidden = 4;

    /**
     * Represents an Input Password field.
     */
    const InputPassword = 5;

    /**
     * Represents an Input Radio field.
     */
    const InputRadio = 6;

    /**
     * Represents an Input Radio field that is part of a group.
     */
    const InputRadioGroup = 14;

    /**
     * Represents an Input Reset field.
     */
    const InputReset = 7;

    /**
     * Represents an Input Submit field.
     */
    const InputSubmit = 8;

    /**
     * Represents an Input Text field.
     */
    const InputText = 9;

    /**
     * Represents an Option field.
     */
    const Option = 10;

    /**
     * Represents a Select field.
     */
    const Select = 11;

    /**
     * Represents a Textarea field.
     */
    const Textarea = 12;

    /**
     * Used for validation: using a user defined function.
     */
    const ValidateCustom = 103;

    /**
     * Used for validation: an e-mail address.
     */
    const ValidateEmail = 100;

    /**
     * Used for validation: non empty string.
     */
    const ValidateRequired = 101;

    /**
     * An array containing all of the form fields.
     */
    private $fields;

    /* ********************************************************************** */
    /* Constructor */
    /* ********************************************************************** */
    /**
     * Create a new DLForm item.
     *
     * @return DLForm
     */
    public function __construct() { $this->fields = array(); }

    /* ********************************************************************** */
    /* Public Methods */
    /* ********************************************************************** */
    /**
     * Add in a form field.
     *
     * @param string    $name           The name for the field.
     * @param int       $type           The type of the form fields. Use the
     *      provided constants for this parameter.
     * @param array     $attributes     (Optional) Any extra attributes for the
     *      field. The key of the array will be the attribute and its value is
     *      the attribute's value. Also note that the value will be surrounded
     *      by double quotes so be sure to add slashes appropriately. For all
     *      OPTION fields, the attribute of 'text' will be the text between
     *      the opening and closing option tags if it is given, otherwise
     *      'value' will be used. For all TEXTAREA fields, the attribute
     *      'value' will be the text between the opening and closing textarea
     *      tags and won't be surrounded by double quotes. It will also be
     *      passed through the function htmlentities. All other type of fields,
     *      if the attribute 'text' isn't given, then 'value' will be used as
     *      part of the label. Note that a label will not be included for a
     *      OPTION or SELECT field.
     * @param array     $options        (Optional) This is specifies
     *      configurations for this method. It consist of the following options:
     *      Key         Default         Description
     *      custom      ''              (callback) This is only used when
     *                                  'validate' is set to VALIDATECUSTOM.
     *                                  This can either be a function name or
     *                                  if it is a method, it needs to be a
     *                                  static method given as an array where
     *                                  the first item of the array is the class
     *                                  name and second item being the name of
     *                                  the method. Note that the the function/
     *                                  method will receive two parameters: the
     *                                  $name and the current value. The
     *                                  function/method should also return a
     *                                  boolean as its result.
     *      use_post    TRUE            (boolean) When this is set to TRUE, if
     *                                  there is a Post variable with the same
     *                                  name as the given $name, then the value
     *                                  of that Post variable will be used as
     *                                  the value.
     *      validate    0               (int) Specify whether or not the given
     *                                  field should be validated. Use the
     *                                  provided constants for this.
     */
    public function addField($name, $type) {
        // Get the optional parameters
        $attributes = @func_get_arg(2);
        $options = @func_get_arg(3);

        // Make sure they are arrays
        if(!is_array($attributes)) { $attributes = array(); }
        if(!is_array($options)) { $options = array(); }

        // Merge default options with given options
        $options = array_merge(
            array('custom' => '', 'use_post' => TRUE, 'validate' => 0),
            $options
        );

        // Validate input(s)
        $test1 = !DLCommon::isNonEmptyString($name);
        $test2 = !is_int($type);
        $test3 = !is_bool($options['use_post']);
        $test4 = !is_string($options['custom']) &&
                 !is_array($options['custom']);
        $test5 = !is_int($options['validate']);
        foreach($attributes as $attribute) {
            if(!is_string($attribute)) { $test6 = TRUE; }
        }
        if($test1 || $test2 || $test3 || $test4 || $test5 || $test6) {
            return DLCommon::exitScript(
                'DLForm->addField',
                compact('name', 'type', 'attributes', 'options'),
                compact('test1', 'test2', 'test3', 'test4', 'test5', 'test6')
            );
        }

        if($type === DLForm::Option) {
            // If it is an option field, we need to group them
            // Make sure that a select field exist, if not create it
            $t1 = !is_array($this->fields[$name]);
            $t2 = $t1 ? TRUE : $this->fields[$name]['type'] !== DLForm::Select;
            if($t2) {
                $this->addField($name, DLForm::Select, array(), $options);
            }

            // Get all of the option fields for the given select
            if(is_array($this->fields[$name]['children'])) {
                $children = $this->fields[$name]['children'];
            } else { $children = array(); }

            // Add the field
            $this->fields[$name]['children'][] = array(
                'name'       => $name,       'type'    => $type,
                'attributes' => $attributes, 'options' => $options
            );
        } elseif($type === DLForm::InputCheckboxGroup) {
            // If it is a checkbox or a radio and we want to group them
            // Add the field
            $this->fields[$name]['name']    = $name;
            $this->fields[$name]['type']    = $type;
            $this->fields[$name]['options'] = $options;
            $this->fields[$name]['children'][] = array(
                'name'       => $name,       'type'    => DLForm::InputCheckbox,
                'attributes' => $attributes, 'options' => $options
            );
        } elseif($type === DLForm::InputRadioGroup) {
            // If it is a checkbox or a radio and we want to group them
            // Add the field
            $this->fields[$name]['name']    = $name;
            $this->fields[$name]['type']    = $type;
            $this->fields[$name]['options'] = $options;
            $this->fields[$name]['children'][] = array(
                'name'       => $name,       'type'    => DLForm::InputRadio,
                'attributes' => $attributes, 'options' => $options
            );
        } else {
            // Add the field
            $this->fields[$name] = array(
                'name'       => $name,       'type'    => $type,
                'attributes' => $attributes, 'options' => $options
            );
        }
    }

    /**
     * Retrieve the HTML for the given $field.
     *
     * @param string    $name       The name of the form field.
     * @param array     $options        (Optional) This is specifies
     *      configurations for this method. It consist of the following options:
     *      Key         Default         Description
     *      - label     TRUE            (boolean) Specifies whether or not a
     *                                  label tag should be included with the
     *                                  resulting HTML.
     * @return string
     */
    public function getField($name) {
        // Get the optional parameters
        $options = @func_get_arg(1);

        // Make sure it is an arrays
        if(!is_array($options)) { $options = array(); }

        // Merge default options with given options
        $options = array_merge(array('label' => TRUE), $options);

        // Validate input
        $test1 = !in_array($name, array_keys($this->fields));
        $test2 = !is_bool($options['label']);
        if($test1 || $test2) {
            return DLCommon::cleanExit(
                'DLForm->getField',
                compact('name', 'options'),
                array('test1', 'test2')
            );
        }

        // Get the field
        $field = $this->fields[$name];

        // Templates
        $tpt = DLData::get(
            'DLForm.Templates.'.$field['type'], array('replace' => FALSE)
        );
        $tpt2 = DLData::get(
            'DLForm.Templates.Label', array('replace' => FALSE)
        );

        // Text Replacement Engine
        $DLT = new DLTemplate();

        // Depending on the field type, process appropriately
        switch($field['type']) {
            case DLForm::InputCheckbox:
            case DLForm::InputRadio:
                if(DLCommon::isNonEmptyString($field['attribute']['checked'])) {
                    $attribute = sprintf(
                        'checked="%s" ', $field['attribute']['checked']
                    );
                }
            case DLForm::InputButton:
            case DLForm::InputFile:
            case DLForm::InputHidden:
            case DLForm::InputPassword:
            case DLForm::InputReset:
            case DLForm::InputSubmit:
            case DLForm::InputText:
                // Make sure attribute is a string
                if(!is_string($attribute)) { $attribute = ''; }

                // Set some data
                $value      = $this->getValue($field);
                $attribute .= $this->getAttributes($field).$value['value'];
                $DLT->ar('id',         uniqid('DLForm_'));
                $DLT->ar('name',       $name);
                $DLT->ar('text',       $this->getText($field));
                $DLT->ar('attributes', $attribute);

                // Process
                $result = '';
                if($options['label']) { $result = $DLT->process($tpt2); }
                $result .= $DLT->process($tpt);

                return $result;
            case DLForm::InputCheckboxGroup:
                // Template
                $tpt3 = DLData::get(
                    'DLForm.Templates.'.DLForm::InputCheckbox,
                    array('replace' => FALSE)
                );

                // See if we have any post data we want to use
                $parentValue = $this->getValue(
                    $field, array('value_only' => TRUE)
                );

                // First get the HTML for the children
                $children = '';
                foreach($field['children'] as $child) {
                    // Get some data
                    $attributes = $this->getAttributes($child);
                    $text       = $this->getText($child);
                    $value      = $this->getValue(
                        $child, array('value_only' => TRUE)
                    );

                    // If we have post data & the data match
                    if($parentValue['is_post'] &&
                       in_array($value['value'], $parentValue['value'])) {
                        $checked = 'checked="checked" ';
                    } elseif(!$parentValue['is_post']) {
                        $checked = sprintf(
                            'checked="%s" ', $child['attributes']['checked']
                        );
                    } else { $checked = ''; }

                    // Set some data
                    $value = $this->getValue($child);
                    $DLT->ar('id',   uniqid('DLForm_'));
                    $DLT->ar('name', $name.'[]');
                    $DLT->ar('text', $text);
                    $DLT->ar(
                        'attributes', $attributes.$checked.$value['value']
                    );

                    // Process
                    if($options['label']) { $children .= $DLT->process($tpt2); }
                    $children .= $DLT->process($tpt3);
                    $DLT->reset();
                }

                // Set some data
                $DLT->ar('children', $children);

                // Process
                $result = $DLT->process($tpt);

                return $result;
            case DLForm::InputRadioGroup:
                // Template
                $tpt3 = DLData::get(
                    'DLForm.Templates.'.DLForm::InputRadio,
                    array('replace' => FALSE)
                );

                // See if we have any post data we want to use
                $parentValue = $this->getValue(
                    $field, array('value_only' => TRUE)
                );

                // First get the HTML for the children
                $children = '';
                foreach($field['children'] as $child) {
                    // Get some data
                    $attributes = $this->getAttributes($child);
                    $text       = $this->getText($child);
                    $value      = $this->getValue(
                        $child, array('value_only' => TRUE)
                    );

                    // If we have post data
                    if($parentValue['is_post'] &&
                       ($value['value'] == $parentValue['value'])) {
                        $checked = 'checked="checked" ';
                    } elseif(!$parentValue['is_post']) {
                        $checked = sprintf(
                            'checked="%s" ', $child['attributes']['checked']
                        );
                    } else { $checked = ''; }

                    // Set some data
                    $value = $this->getValue($child);
                    $DLT->ar('id',   uniqid('DLForm_'));
                    $DLT->ar('name', $name);
                    $DLT->ar('text', $text);
                    $DLT->ar(
                        'attributes', $attributes.$checked.$value['value']
                    );

                    // Process
                    if($options['label']) { $children .= $DLT->process($tpt2); }
                    $children .= $DLT->process($tpt3);
                    $DLT->reset();
                }

                // Set some data
                $DLT->ar('children', $children);

                // Process
                $result = $DLT->process($tpt);

                return $result;
            case DLForm::Select:
                // Template
                $tpt3 = DLData::get(
                    'DLForm.Templates.'.DLForm::Option,
                    array('replace' => FALSE)
                );

                // See if we have any post data we want to use
                $parentValue = $this->getValue(
                    $field, array('value_only' => TRUE)
                );

                // First get the HTML for the children
                $children = '';
                foreach($field['children'] as $child) {
                    // Get some data
                    $attributes = $this->getAttributes($child);
                    $text = $this->getText($child);
                    $value = $this->getValue(
                        $child, array('value_only' => TRUE)
                    );

                    // If we have post data
                    if($parentValue['is_post'] &&
                       is_string($parentValue['value']) &&
                       ($value['value'] == $parentValue['value'])) {
                        // And there is only one selected value
                        $selected = 'selected="selected" ';
                    } elseif($parentValue['is_post'] &&
                             is_array($parentValue['value']) &&
                             in_array($value['value'], $parentValue['value'])) {
                        // And there are multiple selections
                        $selected = 'selected="selected" ';
                    } elseif(!$parentValue['is_post']) {
                        $selected = sprintf(
                            'selected="%s" ', $child['attributes']['selected']
                        );
                    } else { $selected = ''; }

                    // Set some data
                    $value = $this->getValue($child);
                    $DLT->ar('id',   uniqid('DLForm_'));
                    $DLT->ar('text', $text);
                    $DLT->ar(
                        'attributes', $attributes.$selected.$value['value']
                    );

                    // Process
                    $children .= $DLT->process($tpt3);
                    $DLT->reset();
                }

                // Could this SELECT field have more than one value?
                if($field['attributes']['size'] > 1) { $name .= '[]'; }

                // Set some data
                $DLT->ar('id',         uniqid('DLForm_'));
                $DLT->ar('name',       $name);
                $DLT->ar('attributes', $this->getAttributes($field));
                $DLT->ar('text',       $this->getText($field));
                $DLT->ar('children',   $children);

                // Process
                $result = '';
                if($options['label']) { $result = $DLT->process($tpt2); }
                $result .= $DLT->process($tpt);

                return $result;
            case DLForm::Textarea:
                // Set some data
                $value = $this->getValue($field);
                $DLT->ar('id',         uniqid('DLForm_'));
                $DLT->ar('name',       $name);
                $DLT->ar('attributes', $this->getAttributes($field));
                $DLT->ar('text',       $this->getText($field));
                $DLT->ar('value',      $value['value']);

                // Process
                $result = '';
                if($options['label']) { $result = $DLT->process($tpt2); }
                $result .= $DLT->process($tpt);

                return $result;
            default:
                // Field doesn't exist
                return DLCommon::exitScript(
                    'DLForm->getValue', compact('field', 'options')
                );
        }
    }

    /**
     * Nicely output the content of this class. Serves as a debugging service.
     *
     * @return string
     */
    public function toString() {
        ob_start();

        echo '<pre>';

        foreach($this->fields as $field) {
            printf("<h2>%s:</h2><div>%s</div>\n",
                   $field['name'], print_r($field, 1));
        }

        echo '</pre>';

        $result = ob_get_contents();
        ob_end_clean();

        return $result;
    }

    /* ********************************************************************** */
    /* Private Methods */
    /* ********************************************************************** */
    /**
     * Retrieve a string representation of the attributes for the given $field.
     * Note that this will not return the 'text' or 'value' attribute. Use the
     * method 'getText' and 'getValue' for that. The attribute 'selected' is
     * also omitted from this and is retrieved via the method 'getValue' as
     * well.
     *
     * @param array     $field      An associative array that contains the
     *      field information.
     * @return string
     */
    private function getAttributes($field) {
        // Validate input
        if(!is_array($field)) {
            return DLCommon::exitScript(
                'DLForm->getAttributes',
                compact('field'),
                array('test1' => TRUE)
            );
        }

        // If the data is for the field InputCheckboxGroup or InputRadioGroup,
        // just return an empty string
        switch($field['type']) {
            case DLForm::InputCheckboxGroup:
            case DLForm::InputRadioGroup:
                 return '';
        }

        // Create the string
        $result = '';
        foreach($field['attributes'] as $attribute => $value) {
            switch($attribute) {
                case 'checked': case 'selected': case 'text': case 'value':
                    break;
                default:
                    $result .= sprintf(
                        '%s="%s" ', $attribute, addcslashes($value, '"')
                    );
            }
        }

        return $result;
    }

    /**
     * Retrieve the text for the given $field. By default, if the attribute
     * 'text' exist for the given $field, it is returned, otherwise, the value
     * of the attribute 'value' will be used instead. If 'value' is also empty,
     * then use the 'name' of the field, capitalizing the first letter.
     *
     * @param array     $field      The field in which the text should be
     *      retrieved for.
     * @return string
     */
    private function getText($field) {
        // Validate input
        if(!is_array($field)) {
            return DLCommon::exitScript(
                'DLForm->getText', compact('field'), array('test1' => TRUE)
            );
        }

        // Get the text from the attributes
        $result = $field['attributes']['text'];

        // Make sure we have a non-empty string, otherwise, get the value
        if(!DLCommon::isNonEmptyString($result)) {
            $result = $this->getValue($field, array('value_only' => TRUE));
            $result = $result['value'];
        }

        // If we still have a empty string, get the name
        if(!DLCommon::isNonEmptyString($result)) {
            $result = ucfirst($field['name']);
        }

        return $result;
    }

    /**
     * Retrieve the value for the given $field. This method will return an
     * associative array with the following keys:
     *  - is_post:  specifies whether or not the value is from POST
     *  - value:    the actual value itself
     *
     * @param array     $field      The field in which the value should be
     *      retrieved for.
     * @param array     $options        (Optional) This is specifies
     *      configurations for this method. It consist of the following options:
     *      Key             Default         Description
     *      - value_only    FALSE           (boolean) If set to TRUE, then only
     *                                      the value will be returned,
     *                                      otherwise, the value will be wrapped
     *                                      around by the value attribute.
     * @return array
     */
    private function getValue($field) {
        // Get the optional parameters
        $options = @func_get_arg(1);

        // Make sure it is an arrays
        if(!is_array($options)) { $options = array(); }

        // Merge default options with given options
        $options = array_merge(array('value_only' => FALSE), $options);

        // Validate input
        $test1 = !is_array($field);
        $test2 = !is_bool($options['value_only']);
        if($test1 || $test2) {
            return DLCommon::exitScript(
                'DLForm->getValue',
                compact('field', 'options'),
                compact('test1', 'test2')
            );
        }

        // Depending on the field type, process appropriately
        $use_post = $field['options']['use_post'];
        switch($field['type']) {
            case DLForm::InputButton:
            case DLForm::InputCheckbox:
            case DLForm::InputFile:
            case DLForm::InputHidden:
            case DLForm::InputPassword:
            case DLForm::InputRadio:
            case DLForm::InputReset:
            case DLForm::InputSubmit:
            case DLForm::Option:
                // These can never use post data to have its value overwritten
                $result['is_post'] = FALSE;
                $result['value']   = $field['attributes']['value'];
                break;
            case DLForm::InputCheckboxGroup:
            case DLForm::InputRadioGroup:
            case DLForm::InputText:
            case DLForm::Select:
                // These could read data from post
                // See if we should be using the post value and it exist
                if($use_post && isset($_POST[$field['name']])) {
                    $result['is_post'] = TRUE;
                    $result['value']   = $_POST[$field['name']];
                } else {
                    $result['is_post'] = FALSE;
                    $result['value']   = $field['attributes']['value'];
                }
                break;
            case DLForm::Textarea:
                // These can read from post but should be html entified
                if($use_post && isset($_POST[$field['name']])) {
                    $result['is_post'] = TRUE;
                    $result['value']   = $_POST[$field['name']];
                } else {
                    $result['is_post'] = FALSE;
                    $result['value']   = $field['attributes']['value'];
                }

                $result['value'] = htmlentities($result['value']);
                break;
            default:
                // Field doesn't exist
                return DLCommon::exitScript(
                    'DLForm->getValue', compact('field', 'options')
                );
        }

        // Return the value only if it is requested and it isn't a TEXTAREA
        if(!$options['value_only'] && ($field['type'] !== DLForm::Textarea)) {
            $result['value'] = sprintf(
                'value="%s" ', addcslashes($result['value'], '"')
            );
        }

        return $result;
    }
}
?>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.