| 
<?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 '';
 }
 }
 |