PHP Classes

File: src/Renderer/AbstractFormRenderer.php

Recommend this page to a friend!
  Classes of Derek McLean   HTML Forms   src/Renderer/AbstractFormRenderer.php   Download  
File: src/Renderer/AbstractFormRenderer.php
Role: Class source
Content type: text/plain
Description: Class source
Class: HTML Forms
Generate and validate submitted HTML forms
Author: By
Last change:
Date: 6 years ago
Size: 9,134 bytes
 

Contents

Class file image Download
<?php
/**
 * User: delboy1978uk
 * Date: 07/12/2016
 * Time: 01:54
 */

namespace Del\Form\Renderer;

use
Del\Form\Collection\FieldCollection;
use
Del\Form\AbstractForm;
use
Del\Form\Field\FieldInterface;
use
Del\Form\FormInterface;
use
Del\Form\Renderer\Error\DefaultErrorRender;
use
Del\Form\Renderer\Error\ErrorRendererInterface;
use
Del\Form\Traits\HasDomTrait;
use
DOMDocument;
use
DOMElement;

abstract class
AbstractFormRenderer implements FormRendererInterface
{
    use
HasDomTrait;

   
/** @var DOMElement $form */
   
protected $form;

   
/** @var bool $displayErrors */
   
protected $displayErrors;

   
/** @var ErrorRendererInterface $errorRenderer */
   
protected $errorRenderer;

   
/** @var DOMElement $label The label element */
   
protected $label;

   
/** @var DOMElement $element the field element */
   
protected $element;

   
/** @var null|\DOMElement $errors The error block html */
   
protected $errors;

   
/** @var DOMElement $block The containing html block */
   
protected $block;

   
/** @var DOMElement $dynamicContainerBlock */
   
protected $dynamicContainerBlock;

   
/** @var FieldInterface $field The current field being processed */
   
protected $field;

   
/** @var bool $includeDynamicFormJavascript */
   
private $includeDynamicFormJavascript = false;

   
/** @var string $dynamicFormParentName */
   
private $dynamicFormParentName = '';

   
/** @var bool $dynamicFormVisible */
   
private $dynamicFormVisible = false;

    public function
__construct()
    {
       
$this->resetDom();
    }

   
/**
     * resets dom
     */
   
private function resetDom()
    {
       
$this->setDom(new DOMDocument());
       
$this->form = $this->getDom()->createElement('form');
       
$this->errorRenderer = new DefaultErrorRender($this->dom);
    }

   
/**
     * @param FormInterface $form
     * @param bool $displayErrors
     * @return string
     */
   
public function render(FormInterface $form, $displayErrors = true)
    {
       
$this->displayErrors = $displayErrors;
       
$this->setFormAttributes($form);

       
$fields = $form->getFields();
       
$this->processFields($fields);

       
$this->getDom()->appendChild($this->form);
       
$html = $this->getDom()->saveHTML();
       
$this->resetDom();

       
$html .= $this->addDynamicFormJavascript();
        return
$html;
    }

   
/**
     * @param FormInterface $form
     */
   
private function setFormAttributes(FormInterface $form)
    {
       
$attributes = $form->getAttributes();
        foreach (
$attributes as $key => $value) {
           
$this->form->setAttribute($key, $value);
        }

       
// set Id as name or method as post if not set
       
$method = $this->getMethod($form);
       
$id = $this->getId($form);

       
$this->form->setAttribute('id', $id);
       
$this->form->setAttribute('method', $method);
    }

   
/**
     * @param FormInterface $form
     * @return string
     */
   
private function getMethod(FormInterface $form)
    {
        return
$form->getMethod() ?: AbstractForm::METHOD_POST;
    }

   
/**
     * @param FormInterface $form
     * @return string
     */
   
private function getId(FormInterface $form)
    {
        return
$form->getId() ?: $this->form->getAttribute('name');
    }

   
/**
     * @param FieldCollection $fields
     * @param string $dynamicTriggerValue
     */
   
private function processFields(FieldCollection $fields, $dynamicTriggerValue = null)
    {
       
$count = $fields->count();
       
$x = 1;
       
$fields->rewind();
        while (
$fields->valid()) {
           
$this->field = $fields->current();
           
$finaliseDynamicBlock = ($x == $count) ? true : false;
           
$this->renderField($dynamicTriggerValue, $finaliseDynamicBlock);
           
$x++;
           
$fields->next();
        }
       
$fields->rewind();
    }

   
/**
     * @param string $dynamicTriggerValue
     * @param bool $finaliseDynamicBlock
     */
   
public function renderField($dynamicTriggerValue = null, $finaliseDynamicBlock = false)
    {
       
$this->createNewDynamicContainerBlockIfNeeded($dynamicTriggerValue);

       
$this->block = $this->createElement('div');
       
$this->label = $this->renderFieldLabel();
       
$this->element = $this->field->getRenderer()->render($this->dom, $this->field);
       
$this->errors = $this->field->isValid() ? null : $this->renderError();
       
$this->block = $this->renderFieldBlock();

       
is_null($dynamicTriggerValue)
            ?
$this->form->appendChild($this->block)
            :
$this->dynamicContainerBlock->appendChild($this->block);

       
$this->dynamicFormCheck();
       
$this->finaliseDynamicBlockIfNeeded($finaliseDynamicBlock);
    }

   
/**
     * This creates a containing div for dynamic fields which appear only on another fields value
     * @param null|string $dynamicTriggerValue
     */
   
private function createNewDynamicContainerBlockIfNeeded($dynamicTriggerValue)
    {
        if (!isset(
$this->dynamicContainerBlock) && $dynamicTriggerValue !== null) {
           
$this->dynamicContainerBlock = $this->createElement('div');
           
$this->dynamicContainerBlock->setAttribute('data-dynamic-form', $this->dynamicFormParentName);
           
$this->dynamicContainerBlock->setAttribute('data-dynamic-form-trigger-value', $dynamicTriggerValue);
           
$this->dynamicContainerBlock->setAttribute('class', 'dynamic-form-block trigger'.$this->dynamicFormParentName);
           
$this->dynamicContainerBlock->setAttribute('id', $this->dynamicFormParentName.$dynamicTriggerValue);
           
$this->dynamicFormVisible === false ? $this->dynamicContainerBlock->setAttribute('style', 'display: none;') : null;
        }
    }

   
/**
     * Checks current field being processed for dynamic sub forms
     */
   
private function dynamicFormCheck()
    {
        if (
$this->field->hasDynamicForms()) {
           
$this->dynamicFormParentName = $this->field->getName();
           
$value = $this->field->getValue();
           
$forms = $this->field->getDynamicForms();
           
$this->includeDynamicFormJavascript = true;
            foreach (
$forms as $dynamicTriggerValue => $form) {
               
$this->dynamicFormVisible = ($value == $dynamicTriggerValue);
               
$dynamicFields = $form->getFields();
               
$this->processFields($dynamicFields, $dynamicTriggerValue);
            }
            unset(
$this->dynamicFormParentName);
        }
    }

   
/**
     * @param bool $finaliseDynamicBlock
     */
   
private function finaliseDynamicBlockIfNeeded($finaliseDynamicBlock)
    {
        if (isset(
$this->dynamicContainerBlock) && $finaliseDynamicBlock === true) {
           
$this->form->appendChild($this->dynamicContainerBlock);
            unset(
$this->dynamicContainerBlock);
        }
    }


   
/**
     * @return DOMElement|null
     */
   
public function renderError()
    {
       
$errorBlock = null;
        if (
$this->errorRenderer->shouldRender($this->field) && $this->displayErrors === true) {
           
$this->block->setAttribute('class', 'has-error ');
           
$errorBlock = $this->errorRenderer->render($this->field);
        }
        return
$errorBlock;
    }

   
/**
     * @return \DOMElement
     */
   
protected function createLabelElement()
    {
       
$label = $this->createElement('label');
       
$label->setAttribute('for', $this->field->getId());
        if (
$this->field->isRequired()) {
           
$label = $this->addRequiredAsterisk($label);
        }
        return
$label;
    }

   
/**
     * @param DomElement $label
     * @return DomElement
     */
   
public function addRequiredAsterisk(DomElement $label)
    {
       
$span = $this->createElement('span');
       
$span->setAttribute('class', 'text-danger');
       
$text = $this->createText('* ');
       
$span->appendChild($text);
       
$label->appendChild($span);
        return
$label;
    }

   
/**
     * @return string
     */
   
private function addDynamicFormJavascript()
    {
        if (
$this->includeDynamicFormJavascript === true) {
            return
"<script type=\"text/javascript\">
                $(document).ready(function(){
                    $('.dynamic-form-block').each(function(){
                        var Id = $(this).prop('id');
                        var parentField = $(this).attr('data-dynamic-form');
                        var parentValue = $(this).attr('data-dynamic-form-trigger-value');
           
                        $('input[name=\"'+parentField+'\"]').change(function(){
                            var val = $(this).val();
                            if (val == parentValue) {
                                $('.trigger'+parentField).each(function(){
                                    $(this).attr('style', 'display: none;');
                                });
                                $('#'+Id).attr('style', 'display: block;');
                            }
                        });
                    });
                });
            </script>
            "
;
        }
        return
'';
    }
}