Completed
Push — master ( 312f5c...551479 )
by Derek Stephen
02:59
created

AbstractFormRenderer::getMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * User: delboy1978uk
4
 * Date: 07/12/2016
5
 * Time: 01:54
6
 */
7
8
namespace Del\Form\Renderer;
9
10
use Del\Form\Collection\FieldCollection;
11
use Del\Form\AbstractForm;
12
use Del\Form\Field\FieldInterface;
13
use Del\Form\FormInterface;
14
use Del\Form\Renderer\Error\DefaultErrorRender;
15
use Del\Form\Renderer\Error\ErrorRendererInterface;
16
use Del\Form\Traits\HasDomTrait;
17
use DOMDocument;
18
use DomElement;
19
20
abstract class AbstractFormRenderer implements FormRendererInterface
21
{
22
    use HasDomTrait;
23
24
    /** @var DomElement $form */
25
    protected $form;
26
27
    /** @var bool $displayErrors */
28
    protected $displayErrors;
29
30
    /** @var ErrorRendererInterface $errorRenderer */
31
    protected $errorRenderer;
32
33
    /** @var DomElement $label The label element */
34
    protected $label;
35
36
    /** @var DomElement $element the field element */
37
    protected $element;
38
39
    /** @var DomElement $errors The error block html */
40
    protected $errors;
41
42
    /** @var DomElement $block The containing html block */
43
    protected $block;
44
45
    /** @var DomElement $dynamicContainerBlock */
46
    protected $dynamicContainerBlock;
47
48
    /** @var FieldInterface $field The current field being processed */
49
    protected $field;
50
51
    /** @var bool $includeDynamicFormJavascript */
52
    private $includeDynamicFormJavascript = false;
53
54
    /** @var string $dynamicFormParentName */
55
    private $dynamicFormParentName = '';
56
57
    /** @var bool $dynamicFormVisible */
58
    private $dynamicFormVisible = false;
59
60 50
    public function __construct()
61
    {
62 50
        $this->resetDom();
63 50
    }
64
65
    /**
66
     *  resets dom
67
     */
68 50
    private function resetDom()
69
    {
70 50
        $this->setDom(new DOMDocument());
71 50
        $this->form = $this->getDom()->createElement('form');
72 50
        $this->errorRenderer = new DefaultErrorRender($this->dom);
73 50
    }
74
75
    /**
76
     * @param FormInterface $form
77
     * @param bool $displayErrors
78
     * @return string
79
     */
80 29
    public function render(FormInterface $form, $displayErrors = true)
81
    {
82 29
        $this->displayErrors = $displayErrors;
83 29
        $this->setFormAttributes($form);
84
85 29
        $fields = $form->getFields();
86 29
        $this->processFields($fields);
87
88 23
        $this->getDom()->appendChild($this->form);
89 23
        $html = $this->getDom()->saveHTML();
90 23
        $this->resetDom();
91
92 23
        $html .= $this->addDynamicFormJavascript();
93 23
        return $html;
94
    }
95
96
    /**
97
     * @param FormInterface $form
98
     */
99 29
    private function setFormAttributes(FormInterface $form)
100
    {
101 29
        $attributes = $form->getAttributes();
102 29
        foreach ($attributes as $key => $value) {
103 29
            $this->form->setAttribute($key, $value);
104
        }
105
106
        // set Id as name or method as post if not set
107 29
        $method = $this->getMethod($form);
108 29
        $id = $this->getId($form);
109
110 29
        $this->form->setAttribute('id', $id);
111 29
        $this->form->setAttribute('method', $method);
112 29
    }
113
114
    /**
115
     * @param FormInterface $form
116
     * @return string
117
     */
118 29
    private function getMethod(FormInterface $form)
119
    {
120 29
        return $form->getMethod() ?: AbstractForm::METHOD_POST;
121
    }
122
123
    /**
124
     * @param FormInterface $form
125
     * @return string
126
     */
127 29
    private function getId(FormInterface $form)
128
    {
129 29
        return $form->getId() ?: $this->form->getAttribute('name');
130
    }
131
132
    /**
133
     * @param FieldCollection $fields
134
     * @param string $dynamicTriggerValue
135
     */
136 29
    private function processFields(FieldCollection $fields, $dynamicTriggerValue = null)
137
    {
138 29
        $count = $fields->count();
139 29
        $x = 1;
140 29
        $fields->rewind();
141 29
        while ($fields->valid()) {
142 27
            $this->field = $fields->current();
143 27
            $finaliseDynamicBlock = ($x == $count) ? true : false;
144 27
            $this->renderField($dynamicTriggerValue, $finaliseDynamicBlock);
0 ignored issues
show
Bug introduced by
It seems like $dynamicTriggerValue defined by parameter $dynamicTriggerValue on line 136 can also be of type string; however, Del\Form\Renderer\Abstra...Renderer::renderField() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
145 21
            $x++;
146 21
            $fields->next();
147
        }
148 23
        $fields->rewind();
149 23
    }
150
151
    /**
152
     * @param null $dynamicTriggerValue
153
     * @param bool $finaliseDynamicBlock
154
     */
155 27
    public function renderField($dynamicTriggerValue = null, $finaliseDynamicBlock = false)
156
    {
157 27
        $this->createNewDynamicContainerBlockIfNeeded($dynamicTriggerValue);
158
159 27
        $this->block = $this->createElement('div');
160 27
        $this->label = $this->renderFieldLabel();
161 27
        $this->element = $this->field->getRenderer()->render($this->dom, $this->field);
162 21
        $this->errors = $this->field->isValid() ? null : $this->renderError();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->field->isValid() ... : $this->renderError() can also be of type object<Del\Form\Renderer\DOMElement>. However, the property $errors is declared as type object<DOMElement>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
163 21
        $this->block = $this->renderFieldBlock();
164
165 21
        is_null($dynamicTriggerValue)
166 21
            ? $this->form->appendChild($this->block)
167 1
            : $this->dynamicContainerBlock->appendChild($this->block);
168
169 21
        $this->dynamicFormCheck();
170 21
        $this->finaliseDynamicBlockIfNeeded($finaliseDynamicBlock);
171 21
    }
172
173
    /**
174
     * This creates a containing div for dynamic fields which appear only on another fields value
175
     * @param null $dynamicTriggerValue
176
     */
177 27
    private function createNewDynamicContainerBlockIfNeeded($dynamicTriggerValue)
178
    {
179 27
        if (!isset($this->dynamicContainerBlock) && $dynamicTriggerValue !== null) {
180 1
            $this->dynamicContainerBlock = $this->createElement('div');
181 1
            $this->dynamicContainerBlock->setAttribute('data-dynamic-form', $this->dynamicFormParentName);
182 1
            $this->dynamicContainerBlock->setAttribute('data-dynamic-form-trigger-value', $dynamicTriggerValue);
183 1
            $this->dynamicContainerBlock->setAttribute('class', 'dynamic-form-block trigger'.$this->dynamicFormParentName);
184 1
            $this->dynamicContainerBlock->setAttribute('id', $this->dynamicFormParentName.$dynamicTriggerValue);
185 1
            $this->dynamicFormVisible === false ? $this->dynamicContainerBlock->setAttribute('style', 'display: none;') : null;
186
        }
187 27
    }
188
189
    /**
190
     *  Checks current field being processed for dynamic sub forms
191
     */
192 21
    private function dynamicFormCheck()
193
    {
194 21
        if ($this->field->hasDynamicForms()) {
195 1
            $this->dynamicFormParentName = $this->field->getName();
196 1
            $value = $this->field->getValue();
197 1
            $forms = $this->field->getDynamicForms();
198 1
            $this->includeDynamicFormJavascript = true;
199 1
            foreach ($forms as $dynamicTriggerValue => $form) {
200 1
                $this->dynamicFormVisible = ($value == $dynamicTriggerValue);
201 1
                $dynamicFields = $form->getFields();
202 1
                $this->processFields($dynamicFields, $dynamicTriggerValue);
203
            }
204 1
            unset($this->dynamicFormParentName);
205
        }
206 21
    }
207
208
    /**
209
     * @param bool $finaliseDynamicBlock
210
     */
211 21
    private function finaliseDynamicBlockIfNeeded($finaliseDynamicBlock)
212
    {
213 21
        if (isset($this->dynamicContainerBlock) && $finaliseDynamicBlock === true) {
214 1
            $this->form->appendChild($this->dynamicContainerBlock);
215 1
            unset($this->dynamicContainerBlock);
216
        }
217 21
    }
218
219
220
    /**
221
     * @return DOMElement|null
222
     */
223 6
    public function renderError()
224
    {
225 6
        $errorBlock = null;
226 6
        if ($this->errorRenderer->shouldRender($this->field) && $this->displayErrors === true) {
227 4
            $this->block->setAttribute('class', 'has-error ');
228 4
            $errorBlock = $this->errorRenderer->render($this->field);
229
        }
230 6
        return $errorBlock;
231
    }
232
233
    /**
234
     * @return \DOMElement
235
     */
236 27
    protected function createLabelElement()
237
    {
238 27
        $label = $this->createElement('label');
239 27
        $label->setAttribute('for', $this->field->getId());
240 27
        if ($this->field->isRequired()) {
241 6
            $label = $this->addRequiredAsterisk($label);
242
        }
243 27
        return $label;
244
    }
245
246
    /**
247
     * @param DomElement $label
248
     * @return DomElement
249
     */
250 6
    public function addRequiredAsterisk(DomElement $label)
251
    {
252 6
        $span = $this->createElement('span');
253 6
        $span->setAttribute('class', 'text-danger');
254 6
        $text = $this->createText('* ');
255 6
        $span->appendChild($text);
256 6
        $label->appendChild($span);
257 6
        return $label;
258
    }
259
260
    /**
261
     * @return string
262
     */
263 23
    private function addDynamicFormJavascript()
264
    {
265 23
        if ($this->includeDynamicFormJavascript === true) {
266
            return "<script type=\"text/javascript\">
267
                $(document).ready(function(){
268
                    $('.dynamic-form-block').each(function(){
269
                        var Id = $(this).prop('id');
270
                        var parentField = $(this).attr('data-dynamic-form');
271
                        var parentValue = $(this).attr('data-dynamic-form-trigger-value');
272
            
273
                        $('input[name=\"'+parentField+'\"]').change(function(){
274
                            var val = $(this).val();
275
                            if (val == parentValue) {
276
                                $('.trigger'+parentField).each(function(){
277
                                    $(this).attr('style', 'display: none;');
278
                                });
279
                                $('#'+Id).attr('style', 'display: block;');
280
                            }
281
                        });
282
                    });
283
                });
284
            </script>
285 1
            ";
286
        }
287 22
        return '';
288
    }
289
}