Passed
Push — master ( 089a6d...7b13b9 )
by Bruno
06:38
created

Framework   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 328
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 6
Bugs 1 Features 0
Metric Value
eloc 151
c 6
b 1
f 0
dl 0
loc 328
ccs 0
cts 213
cp 0
rs 10
wmc 26

17 Methods

Rating   Name   Duplication   Size   Complexity  
A setViewableContainerTag() 0 4 1
A setMode() 0 4 1
A fillTemplate() 0 28 1
A mapType() 0 8 3
A __construct() 0 3 1
A setEditableContainerTag() 0 4 1
A htmlHead() 0 4 1
A getViewableTemplate() 0 3 1
A editableCompose() 0 52 3
A getEditableContainerTag() 0 3 1
A props() 0 15 4
A getEditableTemplate() 0 3 1
A getMode() 0 3 1
A getViewableContainerTag() 0 3 1
A setEditableTemplate() 0 5 1
A viewableCompose() 0 52 3
A setViewableTemplate() 0 5 1
1
<?php declare(strict_types=1);
2
3
namespace Formularium\Frontend\Vue;
4
5
use Formularium\Datatype;
6
use Formularium\Datatype\Datatype_bool;
7
use Formularium\Datatype\Datatype_number;
8
use Formularium\HTMLElement;
9
use Formularium\Model;
10
11
class Framework extends \Formularium\Framework
12
{
13
    const VUE_MODE_SINGLE_FILE = 'VUE_MODE_SINGLE_FILE';
14
    const VUE_MODE_EMBEDDED = 'VUE_MODE_EMBEDDED';
15
16
    const VUE_PROP = 'VUE_PROP';
17
18
19
    /**
20
     * @var string
21
     */
22
    protected $mode = self::VUE_MODE_EMBEDDED;
23
24
    /**
25
    * The tag used as container for fields in viewable()
26
    *
27
    * @var string
28
    */
29
    protected $viewableContainerTag = 'div';
30
31
    /**
32
     * The tag used as container for fields in editable()
33
     *
34
     * @var string
35
     */
36
    protected $editableContainerTag = 'div';
37
38
    /**
39
     * The viewable template.
40
     *
41
     * The following variables are replaced:
42
     *
43
     * {{form}}
44
     * {{jsonData}}
45
     * {{containerTag}}
46
     *
47
     * @var string
48
     */
49
    protected $viewableTemplate = '';
50
51
    /**
52
     *
53
     *
54
     * @var string
55
     */
56
    protected $editableTemplate = '';
57
58
    public function __construct(string $name = 'Vue')
59
    {
60
        parent::__construct($name);
61
    }
62
63
    /**
64
     * Get the tag used as container for fields in viewable()
65
     *
66
     * @return  string
67
     */
68
    public function getViewableContainerTag(): string
69
    {
70
        return $this->viewableContainerTag;
71
    }
72
73
    /**
74
     * Set the tag used as container for fields in viewable()
75
     *
76
     * @param  string  $viewableContainerTag  The tag used as container for fields in viewable()
77
     *
78
     * @return  self
79
     */
80
    public function setViewableContainerTag(string $viewableContainerTag): Framework
81
    {
82
        $this->viewableContainerTag = $viewableContainerTag;
83
        return $this;
84
    }
85
86
    public function getEditableContainerTag(): string
87
    {
88
        return $this->editableContainerTag;
89
    }
90
    
91
    /**
92
     * @param string $tag
93
     * @return self
94
     */
95
    public function setEditableContainerTag(string $tag): Framework
96
    {
97
        $this->editableContainerTag = $tag;
98
        return $this;
99
    }
100
101
    /**
102
     * Get the value of editableTemplate
103
     */
104
    public function getEditableTemplate(): string
105
    {
106
        return $this->editableTemplate;
107
    }
108
109
    /**
110
     * Set the value of editableTemplate
111
     *
112
     * @return self
113
     */
114
    public function setEditableTemplate(string $editableTemplate): Framework
115
    {
116
        $this->editableTemplate = $editableTemplate;
117
118
        return $this;
119
    }
120
    
121
    /**
122
     * Get {{containerTag}}
123
     *
124
     * @return  string
125
     */
126
    public function getViewableTemplate()
127
    {
128
        return $this->viewableTemplate;
129
    }
130
131
    /**
132
     * Set {{containerTag}}
133
     *
134
     * @param  string  $viewableTemplate  {{containerTag}}
135
     *
136
     * @return  self
137
     */
138
    public function setViewableTemplate(string $viewableTemplate)
139
    {
140
        $this->viewableTemplate = $viewableTemplate;
141
142
        return $this;
143
    }
144
    
145
    /**
146
     * Sets the vue render mode, single file component or embedded
147
     *
148
     * @param string $mode self::VUE_MODE_EMBEDDED or self::VUE_MODE_SINGLE_FILE
149
     * @return Framework
150
     */
151
    public function setMode(string $mode): Framework
152
    {
153
        $this->mode = $mode;
154
        return $this;
155
    }
156
157
    /**
158
     * Get the value of mode
159
     *
160
     * @return string
161
     */
162
    public function getMode(): string
163
    {
164
        return $this->mode;
165
    }
166
167
    public function htmlHead(HTMLElement &$head)
168
    {
169
        $head->prependContent(
170
            HTMLElement::factory('script', ['src' => "https://cdn.jsdelivr.net/npm/vue/dist/vue.js"])
171
        );
172
    }
173
174
    protected function mapType(Datatype $type): string
175
    {
176
        if ($type instanceof Datatype_number) {
177
            return 'Number';
178
        } elseif ($type instanceof Datatype_bool) {
179
            return 'Boolean';
180
        }
181
        return 'String';
182
    }
183
184
    protected function props(Model $m): array
185
    {
186
        $props = [];
187
        foreach ($m->getFields() as $field) {
188
            if ($field->getExtension(self::VUE_PROP, false)) { // TODO
189
                $p = [
190
                    'type' => $this->mapType($field->getDatatype()),
191
                ];
192
                if ($field->getExtension(Datatype::REQUIRED)) {
0 ignored issues
show
Bug introduced by
The call to Formularium\Field::getExtension() has too few arguments starting with default. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

192
                if ($field->/** @scrutinizer ignore-call */ getExtension(Datatype::REQUIRED)) {

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
193
                    $p['required'] = true;
194
                }
195
                $props[$field->getName()] = $p;
196
            }
197
        }
198
        return $props;
199
    }
200
201
    public function viewableCompose(Model $m, array $elements, string $previousCompose): string
202
    {
203
        $data = $m->getDefault(); // TODO: load data
204
        
205
        $viewableForm = join('', $elements);
206
        $jsonData = json_encode($data);
207
        $templateData = [
208
            'containerTag' => $this->getViewableContainerTag(),
209
            'form' => $viewableForm,
210
            'jsonData' => $jsonData,
211
            'props' => $this->props($m)
212
        ];
213
214
        if ($this->viewableTemplate) {
215
            return $this->fillTemplate(
216
                $this->viewableTemplate,
217
                $templateData,
218
                $m
219
            );
220
        } elseif ($this->mode === self::VUE_MODE_SINGLE_FILE) {
221
            $viewableTemplate = <<<EOF
0 ignored issues
show
Unused Code introduced by
The assignment to $viewableTemplate is dead and can be removed.
Loading history...
222
<template>
223
<{{containerTag}}>
224
    {{form}}
225
</{{containerTag}}>
226
</template>
227
<script>
228
module.exports = {
229
    data: function () {
230
        return {{jsonData}};
231
    }
232
};
233
</script>
234
<style>
235
</style>
236
EOF;
237
            return $this->fillTemplate(
238
                $this->viewableTemplate,
239
                $templateData,
240
                $m
241
            );
242
        } else {
243
            $id = 'vueapp';
244
            $t = new HTMLElement(self::getViewableContainerTag(), ['id' => $id], $viewableForm, true);
0 ignored issues
show
Bug Best Practice introduced by
The method Formularium\Frontend\Vue...tViewableContainerTag() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

244
            $t = new HTMLElement(self::/** @scrutinizer ignore-call */ getViewableContainerTag(), ['id' => $id], $viewableForm, true);
Loading history...
245
            $script = <<<EOF
246
var app = new Vue({
247
    el: '#$id',
248
    data: $jsonData
249
});
250
EOF;
251
            $s = new HTMLElement('script', [], $script, true);
252
            return HTMLElement::factory('div', [], [$t, $s])->getRenderHTML();
253
        }
254
    }
255
256
    public function editableCompose(Model $m, array $elements, string $previousCompose): string
257
    {
258
        $data = $m->getDefault(); // TODO: load data
259
        $editableContainerTag = $this->getEditableContainerTag();
260
        $editableForm = join('', $elements);
261
        $jsonData = json_encode($data);
262
        $templateData = [
263
            'containerTag' => $this->getViewableContainerTag(),
264
            'form' => $editableForm,
265
            'jsonData' => $jsonData,
266
            'props' => $this->props($m)
267
        ];
268
269
        if ($this->viewableTemplate) {
270
            return $this->fillTemplate(
271
                $this->editableTemplate,
272
                $templateData,
273
                $m
274
            );
275
        } elseif ($this->mode === self::VUE_MODE_SINGLE_FILE) {
276
            $editableTemplate = <<<EOF
277
<template>
278
<{{containerTag}}>
279
    {{form}}
280
</{{containerTag}}>
281
</template>
282
<script>
283
module.exports = {
284
    data: function () {
285
        return {{jsonData}};
286
    }
287
};
288
</script>
289
<style>
290
</style>
291
EOF;
292
            return $this->fillTemplate(
293
                $editableTemplate,
294
                $templateData,
295
                $m
296
            );
297
        } else {
298
            $id = 'vueapp';
299
            $t = new HTMLElement($editableContainerTag, ['id' => $id], $editableForm, true);
300
            $script = <<<EOF
301
var app = new Vue({
302
    el: '#$id',
303
    data: $jsonData
304
});
305
EOF;
306
            $s = new HTMLElement('script', [], $script, true);
307
            return HTMLElement::factory('div', [], [$t, $s])->getRenderHTML();
308
        }
309
    }
310
311
    protected function fillTemplate(string $template, array $data, Model $m): string
312
    {
313
        $template = str_replace(
314
            '{{form}}',
315
            $data['form'],
316
            $template
317
        );
318
        $template = str_replace(
319
            '{{modelName}}',
320
            $m->getName(),
321
            $template
322
        );
323
        $template = str_replace(
324
            '{{modelNameLower}}',
325
            mb_strtolower($m->getName()),
326
            $template
327
        );
328
        $template = str_replace(
329
            '{{jsonData}}',
330
            $data['jsonData'],
331
            $template
332
        );
333
        $template = str_replace(
334
            '{{containerTag}}',
335
            $data['containerTag'],
336
            $template
337
        );
338
        return $template;
339
    }
340
}
341