Location: PHPKode > projects > Moc10 PHP Library > library/Moc10/Form.php
<?php
/**
 * Moc10 Library
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.TXT.
 * It is also available through the world-wide-web at this URL:
 * http://www.moc10phplibrary.com/LICENSE.TXT
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to hide@address.com so we can send you a copy immediately.
 *
 * @category   Moc10
 * @package    Moc10_Form
 * @author     Nick Sagona, III <hide@address.com>
 * @copyright  Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
 * @license    http://www.moc10phplibrary.com/LICENSE.TXT     New BSD License
 */

/**
 * Moc10_Form
 *
 * @category   Moc10
 * @package    Moc10_Form
 * @author     Nick Sagona, III <hide@address.com>
 * @copyright  Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
 * @license    http://www.moc10phplibrary.com/LICENSE.TXT     New BSD License
 * @version    1.9.7
 */

class Moc10_Form extends Moc10_Dom
{

    /**
     * Form element node
     * @var Moc10_Dom_Child
     */
    protected $_form = null;

    /**
     * Form action
     * @var string
     */
    protected $_action = null;

    /**
     * Form method
     * @var string
     */
    protected $_method = null;

    /**
     * Form template for HTML formatting.
     * @var string
     */
    protected $_template = null;

    /**
     * Form init values for quick setup
     * @var array
     */
    protected $_initValues = array();

    /**
     * Constructor
     *
     * Instantiate the form object
     *
     * @param  string $action
     * @param  string $method
     * @param  string $indent
     * @return void
     */
    public function __construct($action, $method, $indent = null)
    {

        // Set the form's action and method.
        $this->_action = $action;
        $this->_method = $method;

        // Create the parent DOM element and the form child element.
        parent::__construct(null, 'utf-8', null, $indent);
        $this->_form = new Moc10_Dom_Child('form', null, null, false, $indent);
        $this->_form->setAttributes(array('action' => $this->_action, 'method' => $this->_method));
        $this->addChildren($this->_form);

    }

    /**
     * Set the init values of the form object.
     *
     * @param  array $values
     * @throws Exception
     * @return void
     */
    public function setInitValues($values)
    {

        $lang = new Moc10_Language();

        if (!is_array($values)) {
            throw new Exception($lang->__('The parameter passed must be an array.'));
        } if (isset($values[0]) && !is_array($values[0])) {
            throw new Exception($lang->__('The array parameter passed must contain an array.'));
        } else {
            $this->_initValues = $values;
        }

    }

    /**
     * Process the init values of the form object and create the form elements.
     *
     * @return void
     */
    public function processInitValues()
    {

        if (isset($this->_initValues[0])) {

            foreach ($this->_initValues as $field) {

                if (is_array($field) && isset($field['type']) && isset($field['name'])) {

                    $type = $field['type'];
                    $name = $field['name'];
                    $value = (isset($field['value'])) ? $field['value'] : null;
                    $marked = (isset($field['marked'])) ? $field['marked'] : null;
                    $label = (isset($field['label'])) ? $field['label'] : null;
                    $required = (isset($field['required'])) ? $field['required'] : null;
                    $attributes = (isset($field['attributes'])) ? $field['attributes'] : null;
                    $validators = (isset($field['validators'])) ? $field['validators'] : null;

                    // Initialize the form element.
                    switch ($type) {
                        case 'checkbox':
                            $elem = new Moc10_Form_Element_Checkbox($name, $value, $marked);
                            break;
                        case 'radio':
                            $elem = new Moc10_Form_Element_Radio($name, $value, $marked);
                            break;
                        case 'select':
                            $elem = new Moc10_Form_Element_Select($name, $value, $marked);
                            break;
                        case 'textarea':
                            $elem = new Moc10_Form_Element_Textarea($name, $value, $marked);
                            break;
                        default:
                            $elem = new Moc10_Form_Element($type, $name, $value, $marked);
                    }

                    // Set the label.
                    if (!is_null($label)) {
                        $elem->setLabel($label);
                    }

                    // Set if required.
                    if (!is_null($required)) {
                        $elem->setRequired($required);
                    }

                    // Set any attributes.
                    if (!is_null($attributes)) {
                        if (is_array($attributes)) {
                            if ((count($attributes) == 2) && !is_array($attributes[0]) && !is_array($attributes[1])) {
                                $elem->setAttributes($attributes[0], $attributes[1]);
                            } else {
                                foreach ($attributes as $att) {
                                    if (isset($att[0]) && isset($att[1])) {
                                        $elem->setAttributes($att[0], $att[1]);
                                    }
                                }
                            }
                        }
                    }

                    // Set any validators.
                    if (!is_null($validators)) {
                        if (is_array($validators)) {
                            foreach ($validators as $val) {
                                if (is_array($val)) {
                                    $cond = (isset($val[1])) ? $val[1] : true;
                                    $value = (isset($val[2])) ? $val[2] : null;
                                    $msg = (isset($val[3])) ? $val[3] : null;
                                    $elem->addValidator($val[0], $cond, $value, $msg);
                                } else {
                                    $elem->addValidator($val);
                                }
                            }
                        } else {
                            $elem->addValidator($validators);
                        }
                    }

                    $this->addElements($elem);

                }

            }

        }

    }

    /**
     * Set $_POST values to $initValues.
     *
     * @param  array $post
     * @param  boolean $filter
     * @return void
     */
    public function setPostValues($post, $filter = false)
    {

        // Set $_POST values into the _initValues property.
        if (isset($this->_initValues[0])) {
            foreach ($this->_initValues as $key => $field) {
                if (isset($field['name']) && isset($post[$field['name']])) {
                    if (($field['type'] == 'select') || ($field['type'] == 'checkbox') || ($field['type'] == 'radio')) {
                        $this->_initValues[$key]['marked'] = $post[$field['name']];
                    } else {
                        $this->_initValues[$key]['value'] = ($filter) ? (string)Moc10_String::setString($post[$field['name']])->striptags() : $post[$field['name']];
                    }
                }
            }
        // Else, if elements have already been created, set $_POST values into those elements.
        } else {
            $elements = $this->_form->getChildren();
            if (isset($elements[0])) {
                foreach ($elements as $key => $field) {
                    $attributes = $field->getAttributes();
                    if (isset($attributes['name']) && isset($post[$attributes['name']])) {
                        // If a select element.
                        if ($field instanceof Moc10_Form_Element_Select) {
                            $elements[$key]->setMarked($post[$attributes['name']]);
                            $elements[$key]->removeChildren();
                            foreach ($elements[$key]->value as $k => $v) {
                                $opt = new Moc10_Dom_Child('option');
                                $opt->setAttributes('value', $k);
                                if ($v == $elements[$key]->marked) {
                                    $opt->setAttributes('selected', 'selected');
                                }
                                $opt->setValue($v);
                                $elements[$key]->addChildren($opt);
                            }
                        // If a textarea element.
                        } else if ($field instanceof Moc10_Form_Element_Textarea) {
                            $val = ($filter) ? (string)Moc10_String::setString($post[$attributes['name']])->striptags() : $post[$attributes['name']];
                            $elements[$key]->value = $val;
                            $elements[$key]->setValue($val);
                        // If an input element.
                        } else {
                            $val = ($filter) ? (string)Moc10_String::setString($post[$attributes['name']])->striptags() : $post[$attributes['name']];
                            $elements[$key]->value = $val;
                            $elements[$key]->setAttributes('value', $val);
                        }
                    // If a checkbox element.
                    } else if ($field instanceof Moc10_Form_Element_Checkbox) {
                        $children = $field->getChildren();
                        $atts = $children[0]->getAttributes();
                        $name = str_replace('[]', '', $atts['name']);
                        if (isset($post[$name])) {
                            $elements[$key]->setMarked($post[$name]);
                            $elements[$key]->removeChildren();
                            $i = null;
                            foreach ($elements[$key]->value as $k => $v) {
                                $chk = new Moc10_Dom_Child('input');
                                $chk->setAttributes(array('type' => 'checkbox', 'class' => 'checkBox', 'name' => ($name . '[]'), 'id' => ($name . $i), 'value' => $k));
                                if (in_array($v, $elements[$key]->marked)) {
                                    $chk->setAttributes('checked', 'checked');
                                }
                                $span = new Moc10_Dom_Child('span');
                                $span->setAttributes('class', 'checkPad');
                                $span->setValue($v);
                                $elements[$key]->addChildren(array($chk, $span));
                                $i++;
                            }
                        }
                    // If a radio element.
                    } else if ($field instanceof Moc10_Form_Element_Radio) {
                        $children = $field->getChildren();
                        $atts = $children[0]->getAttributes();
                        $name = $atts['name'];
                        if (isset($post[$name])) {
                            $elements[$key]->setMarked($post[$name]);
                            $elements[$key]->removeChildren();
                            $i = null;
                            foreach ($elements[$key]->value as $k => $v) {
                                $rad = new Moc10_Dom_Child('input');
                                $rad->setAttributes(array('type' => 'radio', 'class' => 'radioBtn', 'name' => $name, 'id' => ($name . $i), 'value' => $k));
                                if ($v == $elements[$key]->marked) {
                                    $rad->setAttributes('checked', 'checked');
                                }
                                $span = new Moc10_Dom_Child('span');
                                $span->setAttributes('class', 'radioPad');
                                $span->setValue($v);
                                $elements[$key]->addChildren(array($rad, $span));
                                $i++;
                            }
                        }
                    }
                }
                $this->_form->removeChildren();
                $this->_form->addChildren($elements);
            }

        }

    }

    /**
     * Set a form template for the render method to utilize.
     *
     * @param  string $tmpl
     * @return void
     */
    public function setTemplate($tmpl)
    {

        $this->_template = $tmpl;

    }

    /**
     * Get the form template for the render method to utilize.
     *
     * @return string
     */
    public function getTemplate()
    {

        return $this->_template;

    }

    /**
     * Set an attribute or attributes for the form object.
     *
     * @param  array|string $a
     * @param  string $v
     * @return void
     */
    public function setAttributes($a, $v = null)
    {

        $this->_form->setAttributes($a, $v);

    }

    /**
     * Get the attributes of the form object.
     *
     * @return array
     */
    public function getAttributes()
    {

        return $this->_form->getAttributes();

    }

    /**
     * Add a form element or elements to the form object.
     *
     * @param  array|string $e
     * @return void
     */
    public function addElements($e)
    {

        $this->_form->addChildren($e);

    }

    /**
     * Get the elements of the form object.
     *
     * @return array
     */
    public function getElements()
    {

        return $this->_form->getChildren();

    }

    /**
     * Determine whether or not the form object is valid and return the result.
     *
     * @return boolean
     */
    public function isValid()
    {

        $noerrors = true;
        $children = $this->_form->getChildren();

        // Check each element for validators, validate them and return the result.
        foreach ($children as $child) {
            if ($child->validate() == false) {
                $noerrors = false;
            }
        }

        return $noerrors;

    }

    /**
     * Render the form object using the defined template. The template should use a simple search and replace
     * format that contains [{element}] and/or [{element_label}] for the placeholders that will be swapped out.
     * Required fields' labels have class="required" and error messages have class="error" for styling purposes.
     *
     * @param  boolean $ret
     * @throws Exception
     * @return void
     */

    public function render($ret = false)
    {

        // Check to make sure form elements exist.
        if (count($this->_form->getChildren()) == 0) {
            $lang = new Moc10_Language();
            throw new Exception($lang->__('Error: There are no form elements declared for this form object.'));
        // Else, if the template is not set, default to the basic output.
        } else if (is_null($this->_template)) {
            if ($ret) {
                return (string)$this;
            } else {
                print($this);
            }
        // Else, start building the form's HTML output based on the template.
        } else {

            // Initialize properties and variabels.
            $this->_output = '';
            $children = $this->_form->getChildren();

            // Loop through the child elements of the form.
            foreach ($children as $child) {

                // Get the element name.
                if ($child->getName() == 'fieldset') {
                    $chdrn = $child->getChildren();
                    $attribs = $chdrn[0]->getAttributes();
                } else {
                    $attribs = $child->getAttributes();
                }
                $name = (isset($attribs['name'])) ? $attribs['name'] : '';
                $name = str_replace('[]', '', $name);

                // Set the element's label, if applicable.
                if (!is_null($child->label)) {

                    // Format the label name.
                    $label = new Moc10_Dom_Child('label', $child->label);

                    if ($child->required) {
                        $label->setAttributes(array('for' => $name, 'class' => 'required'));
                    } else {
                        $label->setAttributes('for', $name);
                    }

                    // Swap the element's label placeholder with the rendered label element.
                    $labelSearch = '[{' . $name . '_label}]';
                    $labelReplace = $label->render(true);
                    $this->_template = str_replace($labelSearch, substr($labelReplace, 0, -1), $this->_template);

                }

                // Calculate the element's indentation.
                $indent = '';
                $indent = substr($this->_template, 0, strpos($this->_template, ('[{' . $name . '}]')));
                $indent = substr($indent, (strrpos($indent, "\n") + 1));

                $matches = array();
                preg_match_all('/[^\s]/', $indent, $matches);
                if (isset($matches[0])) {
                    foreach ($matches[0] as $str) {
                        $indent = str_replace($str, ' ', $indent);
                    }
                }

                // Set each child element's indentation.
                $childChildren = $child->getChildren();
                $child->removeChildren();
                foreach ($childChildren as $cChild) {
                    $cChild->setIndent(($indent . '    '));
                    $child->addChildren($cChild);
                }

                // Swap the element's placeholder with the rendered element.
                $elementSearch = '[{' . $name . '}]';
                $elementReplace = $child->render(true, 0, $indent);
                $elementReplace = substr($elementReplace, 0, -1);
                $elementReplace = str_replace('</select>', $indent . '</select>', $elementReplace);
                $elementReplace = str_replace('</fieldset>', $indent . '</fieldset>', $elementReplace);
                $this->_template = str_replace($elementSearch, $elementReplace, $this->_template);

            }

            // Set the rendered form content and remove the children.
            $this->_form->setValue("\n" . $this->_template . "\n" . $this->_form->getIndent());
            $this->_form->removeChildren();

            // Return or print the form output.
            if ($ret) {
                return $this->_form->render(true);
            } else {
                print($this->_form->render(true));
            }

        }

    }

    /**
     * Output the form object in a basic HTML format. Each form element is formatted to a 1:1 label to element
     * ratio, using <dl>, <dt> and <dd> tags. Required fields' labels have class="required" and error messages
     * have class="error" for styling purposes.
     *
     * @return string
     */

    public function __toString()
    {

        // Initialize propeties.
        $this->_output = '';
        $children = $this->_form->getChildren();
        $this->_form->removeChildren();

        // Create DL element.
        $dl = new Moc10_Dom_Child('dl', null, null, false, ($this->_form->getIndent() . '    '));

        // Loop through the children and create and attach the appropriate DT and DT elements, with labels where applicable.
        foreach ($children as $child) {

            // If the element label is set, render the appropriate DT and DD elements.
            if (!is_null($child->label)) {

                // Create the DT and DD elements.
                $dt = new Moc10_Dom_Child('dt', null, null, false, ($this->_form->getIndent() . '        '));
                $dd = new Moc10_Dom_Child('dd', null, null, false, ($this->_form->getIndent() . '        '));

                // Format the label name.
                $lbl_name = ($child->getName() == 'fieldset') ? '1' : '';
                $label = new Moc10_Dom_Child('label', $child->label, null, false, ($this->_form->getIndent() . '            '));

                if ($child->getName() == 'fieldset') {
                    $chdrn = $child->getChildren();
                    $attribs = $chdrn[0]->getAttributes();
                } else {
                    $attribs = $child->getAttributes();
                }

                $name = (isset($attribs['name'])) ? $attribs['name'] : '';
                $name = str_replace('[]', '', $name);

                if ($child->required) {
                    $label->setAttributes(array('for' => ($name . $lbl_name), 'class' => 'required'));
                } else {
                    $label->setAttributes('for', ($name . $lbl_name));
                }

                // Add the appropriate children to the appropriate elements.
                $dt->addChildren($label);
                $child->setIndent(($this->_form->getIndent() . '            '));
                $childChildren = $child->getChildren();
                $child->removeChildren();

                foreach ($childChildren as $cChild) {
                    $cChild->setIndent(($this->_form->getIndent() . '                '));
                    $child->addChildren($cChild);
                }

                $dd->addChildren($child);
                $dl->addChildren(array($dt, $dd));

            // Else, render only a DD element.
            } else {

                $dd = new Moc10_Dom_Child('dd', null, null, false, ($this->_form->getIndent() . '        '));
                $child->setIndent(($this->_form->getIndent() . '            '));
                $dd->addChildren($child);
                $dl->addChildren($dd);

            }

        }

        // Add the DL element and its children to the form element.
        $this->_form->addChildren($dl);
        $this->_output = $this->_form->render(true);

        // Print the output.
        return $this->_output;

    }

}
Return current item: Moc10 PHP Library