Passed
Push — master ( 03056a...8132a2 )
by Bruno
05:28
created

Framework::getVueCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
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\Exception\Exception;
9
use Formularium\HTMLNode;
10
use Formularium\Model;
11
12
class Framework extends \Formularium\Framework
13
{
14
    const VUE_MODE_SINGLE_FILE = 'VUE_MODE_SINGLE_FILE';
15
    const VUE_MODE_EMBEDDED = 'VUE_MODE_EMBEDDED';
16
    const VUE_PROP = 'VUE_PROP';
17
    const VUE_VARS = 'VUE_VARS';
18
    const VUE_CODE = 'VUE_CODE';
19
20
    /**
21
     * @var string
22
     */
23
    protected $mode = self::VUE_MODE_EMBEDDED;
24
25
    /**
26
    * The tag used as container for fields in viewable()
27
    *
28
    * @var string
29
    */
30
    protected $viewableContainerTag = 'div';
31
32
    /**
33
     * The tag used as container for fields in editable()
34
     *
35
     * @var string
36
     */
37
    protected $editableContainerTag = 'div';
38
39
    /**
40
     * The viewable template.
41
     *
42
     * The following variables are replaced:
43
     *
44
     * {{form}}
45
     * {{script}}
46
     * {{containerTag}}
47
     *
48
     * @var string|callable|null
49
     */
50
    protected $viewableTemplate = null;
51
52
    /**
53
     *
54
     *
55
     * @var string|callable|null
56
     */
57
    protected $editableTemplate = null;
58
59
    /**
60
     * Appended to the field variable names to handle models stored in an object field.
61
     *
62
     * Allows you to declare the model like this:
63
     *
64
     * data() {
65
     *   return {
66
     *       model: model,
67
     *   };
68
     * },
69
     *
70
     * @var string
71
     */
72
    protected $fieldModelVariable = '';
73
74
    /**
75
     * @var VueCode
76
     */
77
    protected $vueCode = null;
78
79
    public function __construct(string $name = 'Vue')
80
    {
81
        parent::__construct($name);
82
        $this->vueCode = new VueCode();
83
    }
84
85
    /**
86
     * Static counter to generate unique ids.
87
     *
88
     * @return integer
89
     */
90
    public static function counter(): int
91
    {
92
        static $counter = 0;
93
        return $counter++;
94
    }
95
96
    /**
97
     * Get the tag used as container for fields in viewable()
98
     *
99
     * @return  string
100
     */
101
    public function getViewableContainerTag(): string
102
    {
103
        return $this->viewableContainerTag;
104
    }
105
106
    /**
107
     * Set the tag used as container for fields in viewable()
108
     *
109
     * @param  string  $viewableContainerTag  The tag used as container for fields in viewable()
110
     *
111
     * @return  self
112
     */
113
    public function setViewableContainerTag(string $viewableContainerTag): Framework
114
    {
115
        $this->viewableContainerTag = $viewableContainerTag;
116
        return $this;
117
    }
118
119
    public function getEditableContainerTag(): string
120
    {
121
        return $this->editableContainerTag;
122
    }
123
    
124
    /**
125
     * @param string $tag
126
     * @return self
127
     */
128
    public function setEditableContainerTag(string $tag): Framework
129
    {
130
        $this->editableContainerTag = $tag;
131
        return $this;
132
    }
133
134
    /**
135
     * Get the value of editableTemplate
136
     * @return string|callable|null
137
     */
138
    public function getEditableTemplate()
139
    {
140
        return $this->editableTemplate;
141
    }
142
143
    /**
144
     * Set the value of editableTemplate
145
     *
146
     * @param string|callable|null $editableTemplate
147
     * @return self
148
     */
149
    public function setEditableTemplate($editableTemplate): Framework
150
    {
151
        $this->editableTemplate = $editableTemplate;
152
153
        return $this;
154
    }
155
    
156
    /**
157
     * Get viewable template
158
     *
159
     * @return string|callable|null
160
     */
161
    public function getViewableTemplate()
162
    {
163
        return $this->viewableTemplate;
164
    }
165
166
    /**
167
     * Set viewable tempalte
168
     *
169
     * @param string|callable|null  $viewableTemplate
170
     *
171
     * @return  self
172
     */
173
    public function setViewableTemplate($viewableTemplate)
174
    {
175
        $this->viewableTemplate = $viewableTemplate;
176
177
        return $this;
178
    }
179
    
180
    /**
181
     * Sets the vue render mode, single file component or embedded
182
     *
183
     * @param string $mode self::VUE_MODE_EMBEDDED or self::VUE_MODE_SINGLE_FILE
184
     * @return Framework
185
     */
186
    public function setMode(string $mode): Framework
187
    {
188
        $this->mode = $mode;
189
        return $this;
190
    }
191
192
    /**
193
     * Get the value of mode
194
     *
195
     * @return string
196
     */
197
    public function getMode(): string
198
    {
199
        return $this->mode;
200
    }
201
202
    public function htmlHead(HTMLNode &$head)
203
    {
204
        $head->prependContent(
205
            HTMLNode::factory('script', ['src' => "https://cdn.jsdelivr.net/npm/vue/dist/vue.js"])
206
        );
207
    }
208
209
    public function viewableCompose(Model $m, array $elements, string $previousCompose): string
210
    {
211
        $templateData = [
212
            'containerTag' => $this->getViewableContainerTag(),
213
            'form' => join('', $elements),
214
            'script' => $this->vueCode->toScript($m, $elements)
215
        ];
216
217
        if (is_callable($this->viewableTemplate)) {
218
            return call_user_func(
219
                $this->viewableTemplate,
220
                $this,
221
                $templateData,
222
                $m
223
            );
224
        } elseif ($this->mode === self::VUE_MODE_SINGLE_FILE) {
225
            $viewableTemplate = $this->viewableTemplate ? $this->viewableTemplate : <<<EOF
226
<template>
227
<{{containerTag}}>
228
    {{form}}
229
</{{containerTag}}>
230
</template>
231
<script>
232
{{{script}}}
233
</script>
234
<style>
235
</style>
236
EOF;
237
            
238
            return $this->fillTemplate(
239
                $viewableTemplate,
0 ignored issues
show
Bug introduced by
It seems like $viewableTemplate can also be of type callable; however, parameter $template of Formularium\Frontend\Vue\Framework::fillTemplate() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

239
                /** @scrutinizer ignore-type */ $viewableTemplate,
Loading history...
240
                $templateData,
241
                $m
242
            );
243
        } else {
244
            // TODO: this is likely broken
245
            $id = 'vueapp' . static::counter();
246
            $t = new HTMLNode($this->getViewableContainerTag(), ['id' => $id], $templateData['form'], true);
247
            $vars = $this->vueCode->toVariable($m, $elements);
248
            $this->vueCode->appendOther('el', "#$id");
249
            $script = "const app_$id = new Vue({$vars});";
250
            $s = new HTMLNode('script', [], $script, true);
251
            return HTMLNode::factory('div', [], [$t, $s])->getRenderHTML();
252
        }
253
    }
254
255
    public function editableCompose(Model $m, array $elements, string $previousCompose): string
256
    {
257
        $templateData = [
258
            'containerTag' => $this->getEditableContainerTag(),
259
            'form' => join('', $elements),
260
            'script' => $this->vueCode->toScript($m, $elements)
261
        ];
262
        
263
        if (is_callable($this->editableTemplate)) {
264
            return call_user_func(
265
                $this->editableTemplate,
266
                $this,
267
                $templateData,
268
                $m
269
            );
270
        } elseif ($this->editableTemplate) {
271
            return $this->fillTemplate(
272
                $this->editableTemplate,
0 ignored issues
show
Bug introduced by
It seems like $this->editableTemplate can also be of type callable; however, parameter $template of Formularium\Frontend\Vue\Framework::fillTemplate() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

272
                /** @scrutinizer ignore-type */ $this->editableTemplate,
Loading history...
273
                $templateData,
274
                $m
275
            );
276
        } elseif ($this->mode === self::VUE_MODE_SINGLE_FILE) {
277
            $editableTemplate = <<<EOF
278
<template>
279
<{{containerTag}}>
280
    {{form}}
281
</{{containerTag}}>
282
</template>
283
<script>
284
{{{script}}}
285
</script>
286
<style>
287
</style>
288
EOF;
289
            return $this->fillTemplate(
290
                $editableTemplate,
291
                $templateData,
292
                $m
293
            );
294
        } else {
295
            $id = 'vueapp' . static::counter();
296
            $t = new HTMLNode($templateData['containerTag'], ['id' => $id], $templateData['form'], true);
297
            $this->vueCode->appendOther('el', "#$id");
298
            $vars = $this->vueCode->toVariable($m, $elements);
299
            $script = "const app_$id = new Vue({{$vars}});";
300
            $s = new HTMLNode('script', [], $script, true);
301
            return HTMLNode::factory('div', [], [$t, $s])->getRenderHTML();
302
        }
303
    }
304
305
    protected function fillTemplate(string $template, array $data, Model $m): string
306
    {
307
        foreach ($data as $name => $value) {
308
            $template = str_replace(
309
                '{{' . $name . '}}',
310
                $value,
311
                $template
312
            );
313
        }
314
315
        $template = str_replace(
316
            '{{modelName}}',
317
            $m->getName(),
318
            $template
319
        );
320
        $template = str_replace(
321
            '{{modelNameLower}}',
322
            mb_strtolower($m->getName()),
323
            $template
324
        );
325
        return $template;
326
    }
327
328
    /**
329
     * Get appended to the field variable names to handle models stored in an object field.
330
     *
331
     * @return  string
332
     */
333
    public function getFieldModelVariable(): string
334
    {
335
        return $this->fieldModelVariable;
336
    }
337
338
    /**
339
     * Set appended to the field variable names to handle models stored in an object field.
340
     *
341
     * @param  string  $fieldModelVariable  Appended to the field variable names to handle models stored in an object field.
342
     *
343
     * @return  self
344
     */
345
    public function setFieldModelVariable(string $fieldModelVariable): self
346
    {
347
        $this->fieldModelVariable = $fieldModelVariable;
348
349
        return $this;
350
    }
351
352
    /**
353
     * Get the value of vueCode
354
     *
355
     * @return  VueCode
356
     */
357
    public function getVueCode()
358
    {
359
        return $this->vueCode;
360
    }
361
362
    public function resetVueCode(): void
363
    {
364
        $this->vueCode = new VueCode();
365
    }
366
}
367