Passed
Push — master ( 20bf7d...03056a )
by Bruno
08:25
created

VueCode::appendOther()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 2
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\Field;
10
use Formularium\HTMLNode;
11
use Formularium\Model;
12
13
class VueCode
14
{
15
    /**
16
     * Extra props.
17
     *
18
     * @var array
19
     */
20
    protected $extraProps = [];
21
22
    /**
23
     * extra data fields
24
     *
25
     * @var string[]
26
     */
27
    protected $extraData = [];
28
29
    /**
30
     * The list of imports to add: import 'key' from 'value'
31
     *
32
     * @var string[]
33
     */
34
    protected $imports = [];
35
    
36
    /**
37
     * @var string[]
38
     */
39
    protected $methods = [];
40
41
    /**
42
     * @var string[]
43
     */
44
    protected $other = [];
45
46
    /**
47
     * @param string $name
48
     * @param string $code
49
     * @return self
50
     */
51
    public function appendMethod($name, $code): self
52
    {
53
        $this->methods[$name] = $code;
54
        return $this;
55
    }
56
57
    /**
58
     * @param string $name
59
     * @param string $code
60
     * @return self
61
     */
62
    public function appendOther($name, $code): self
63
    {
64
        $this->other[$name] = $code;
65
        return $this;
66
    }
67
68
    /**
69
     * @return array
70
     */
71
    public function getExtraProps(): array
72
    {
73
        return $this->extraProps;
74
    }
75
76
    /**
77
     *
78
     * @param array $extraProps
79
     *
80
     * @return  self
81
     */
82
    public function setExtraProps(array $extraProps): self
83
    {
84
        $this->extraProps = $extraProps;
85
86
        return $this;
87
    }
88
89
    /**
90
     *
91
     * @param array $extra Array of props. 'name' and 'type' keys are required for each element.
92
     *
93
     * @return  self
94
     */
95
    public function appendExtraProp(array $extra): self
96
    {
97
        $this->extraProps[] = $extra;
98
99
        return $this;
100
    }
101
102
    /**
103
     * Appends to the `data` field.
104
     *
105
     * @param string $name
106
     * @param string $value
107
     * @return self
108
     */
109
    public function appendExtraData(string $name, string $value): self
110
    {
111
        $this->extraData[$name] = $value;
112
        return $this;
113
    }
114
115
    /**
116
     * The list of imports to add: import 'key' from 'value'
117
     *
118
     * @param string $key
119
     * @param string $value
120
     * @return self
121
     */
122
    public function appendImport(string $key, string $value): self
123
    {
124
        $this->imports[$key] = $value;
125
126
        return $this;
127
    }
128
129
    /**
130
     * Converts a Datatype to a JS type
131
     *
132
     * @param Datatype $type
133
     * @return string
134
     */
135
    public function mapType(Datatype $type): string
136
    {
137
        if ($type instanceof Datatype_number) {
138
            return 'Number';
139
        } elseif ($type instanceof Datatype_bool) {
140
            return 'Boolean';
141
        }
142
        return 'String';
143
    }
144
145
    public function props(Model $m): array
146
    {
147
        $props = [];
148
        foreach ($m->getFields() as $field) {
149
            /**
150
             * @var Field $field
151
             */
152
            if ($field->getRenderable(Framework::VUE_PROP, false)) {
153
                $p = [
154
                    'name' => $field->getName(),
155
                    'type' => $this->mapType($field->getDatatype()),
156
                ];
157
                if ($field->getRenderable(Datatype::REQUIRED, false)) {
158
                    $p['required'] = true;
159
                }
160
                $props[] = $p;
161
            }
162
        }
163
        foreach ($this->extraProps as $p) {
164
            if (!array_key_exists('name', $p)) {
165
                throw new Exception('Missing prop name');
166
            }
167
            $props[] = $p;
168
        }
169
        
170
        return $props;
171
    }
172
173
    /**
174
     * Generates valid JS code for the props.
175
     *
176
     * @param array $props
177
     * @return string
178
     */
179
    protected function serializeProps(array $props): string
180
    {
181
        $s = array_map(function ($p) {
182
            return "'{$p['name']}': { 'type': {$p['type']}" . ($p['required'] ?? false ? ", 'required': true" : '') . " } ";
183
        }, $props);
184
        return "{\n        " . implode(",\n        ", $s) . "\n    }\n";
185
    }
186
187
    /**
188
     * Generates template data for rendering
189
     *
190
     * @param Model $m
191
     * @param HTMLNode[] $elements $elements
192
     * @return array
193
     */
194
    protected function getTemplateData(Model $m, array $elements): array
0 ignored issues
show
Unused Code introduced by
The parameter $elements is not used and could be removed. ( Ignorable by Annotation )

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

194
    protected function getTemplateData(Model $m, /** @scrutinizer ignore-unused */ array $elements): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
195
    {
196
        $data = array_merge($m->getDefault(), $m->getData());
197
        $jsonData = json_encode($data);
198
        $props = $this->props($m);
199
        $propsBind = array_map(
200
            function ($p) {
201
                return 'v-bind:' . $p . '="model.' . $p . '"';
202
            },
203
            array_keys($props)
204
        );
205
        $templateData = [
206
            'jsonData' => $jsonData,
207
            'propsCode' => $this->serializeProps($props),
208
            'propsBind' => implode(' ', $propsBind),
209
            'imports' => implode(
210
                "\n",
211
                array_map(function ($key, $value) {
212
                    // TODO: array
213
                    return "import $key from \"$value\";";
214
                }, array_keys($this->imports), $this->imports)
215
            ),
216
            'otherData' => implode(
217
                "\n",
218
                array_map(function ($key, $value) {
219
                    return "$key: " . json_encode($value) . ",\n";
220
                }, array_keys($this->other), $this->other)
221
            ),
222
            'methodsCode' => '{}', // TODO
223
            'extraData' => implode(
224
                "\n",
225
                array_map(function ($key, $value) {
226
                    return "  $key: $value,";
227
                }, array_keys($this->extraData), $this->extraData)
228
            )
229
        ];
230
        var_dump($templateData);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($templateData) looks like debug code. Are you sure you do not want to remove it?
Loading history...
231
232
        return $templateData;
233
    }
234
235
    protected function fillTemplate(string $template, array $data, Model $m): string
236
    {
237
        foreach ($data as $name => $value) {
238
            $template = str_replace(
239
                '{{' . $name . '}}',
240
                $value,
241
                $template
242
            );
243
        }
244
245
        $template = str_replace(
246
            '{{modelName}}',
247
            $m->getName(),
248
            $template
249
        );
250
        $template = str_replace(
251
            '{{modelNameLower}}',
252
            mb_strtolower($m->getName()),
253
            $template
254
        );
255
        return $template;
256
    }
257
258
    /**
259
     * Generates the javascript code.
260
     *
261
     * @param Model $m
262
     * @param HTMLNode[] $elements
263
     * @return string
264
     */
265
    public function toScript(Model $m, array $elements)
266
    {
267
        $templateData = $this->getTemplateData($m, $elements);
268
269
        $viewableTemplate = <<<EOF
270
{{imports}}
271
272
module.exports = {
273
    {{otherData}}
274
    data: function () {
275
        return {{jsonData}};
276
    },
277
    props: {{propsCode}},
278
    methods: {{methodsCode}}
279
};
280
EOF;
281
            
282
        return $this->fillTemplate(
283
            $viewableTemplate,
284
            $templateData,
285
            $m
286
        );
287
    }
288
289
    /**
290
     * Generates the javascript code.
291
     *
292
     * @param Model $m
293
     * @param HTMLNode[] $elements
294
     * @return string
295
     */
296
    public function toVariable(Model $m, array $elements)
297
    {
298
        $templateData = $this->getTemplateData($m, $elements);
299
300
        $viewableTemplate = <<<EOF
301
    {{otherData}}
302
    data() {
303
        return {{jsonData}};
304
    },
305
    props: {{propsCode}},
306
    methods: {{methodsCode}}
307
EOF;
308
            
309
        return $this->fillTemplate(
310
            $viewableTemplate,
311
            $templateData,
312
            $m
313
        );
314
    }
315
316
    /**
317
     * Get the value of other
318
     * @return array
319
     */
320
    public function &getOther(): array
321
    {
322
        return $this->other;
323
    }
324
}
325