Passed
Push — master ( b5507b...28d9c0 )
by Dispositif
02:37
created

AbstractWikiTemplate::paramsByRenderOrder()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 13
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 28
rs 8.8333
1
<?php
2
/**
3
 * This file is part of dispositif/wikibot application
4
 * 2019 : Philippe M. <[email protected]>
5
 * For the full copyright and MIT license information, please view the LICENSE file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Domain\Models\Wiki;
11
12
use App\Domain\Utils\ArrayProcessTrait;
13
use App\Domain\Utils\TemplateParser;
14
use App\Domain\Utils\WikiTextUtil;
15
use DomainException;
16
use Exception;
17
use Throwable;
18
19
/**
20
 * TODO detect userPreferences (inlineStyle, spaceStyle...)
21
 * Class AbstractWikiTemplate.
22
 */
23
abstract class AbstractWikiTemplate extends AbstractParametersObject
24
{
25
    use ArrayProcessTrait;
26
27
    const MODEL_NAME = '';
28
29
    // commented to allow inherit from Interface in OuvrageTemplate
30
    //const PARAM_ALIAS = [];
31
32
    /**
33
     * todo : modify to [a,b,c] ?
34
     */
35
    const REQUIRED_PARAMETERS = [];
36
37
    public $log = [];
38
39
    public $parametersErrorFromHydrate;
40
41
    public $userSeparator; // todo move to WikiRef
42
43
    /**
44
     * optional
45
     * Not a constant so it can be modified in constructor.
46
     * Commented so it can be inherit from trait in OuvrageTemplate
47
     */
48
    //protected $parametersByOrder = [];
49
50
    protected $paramOrderByUser = [];
51
52
    /**
53
     * AbstractWikiTemplate constructor.
54
     *
55
     * @throws Exception
56
     */
57
    public function __construct()
58
    {
59
        if (empty(static::REQUIRED_PARAMETERS)) {
1 ignored issue
show
introduced by
The condition empty(static::REQUIRED_PARAMETERS) is always true.
Loading history...
60
            throw new Exception(sprintf('REQUIRED_PARAMETERS not configured in "%s"', get_called_class()));
61
        }
62
        $this->parametersValues = static::REQUIRED_PARAMETERS;
63
64
        if (empty($this->parametersByOrder)) {
65
            $this->parametersByOrder = static::REQUIRED_PARAMETERS;
66
        }
67
    }
68
69
    /**
70
     * Get data from wiki-template. Also invalid param/values.
71
     *
72
     * @return array
73
     */
74
    public function toArray(): array
75
    {
76
        $allValue = array_merge($this->parametersValues, $this->parametersErrorFromHydrate ?? []);
77
78
        return $this->deleteEmptyValueArray($allValue);
79
    }
80
81
    public function getParamsAndAlias(): array
82
    {
83
        return array_merge($this->parametersByOrder, array_keys($this::PARAM_ALIAS));
1 ignored issue
show
Bug introduced by
The constant App\Domain\Models\Wiki\A...kiTemplate::PARAM_ALIAS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
84
    }
85
86
    /**
87
     * Is the parameter's name valid ?
88
     *
89
     * @param string $paramName
90
     *
91
     * @return bool
92
     */
93
    public function isParamOrAlias(string $paramName): bool
94
    {
95
        return in_array($paramName, $this->getParamsAndAlias());
96
    }
97
98
    /**
99
     * @param string $name
100
     *
101
     * @return string|null
102
     * @throws Exception
103
     */
104
    public function getParam(string $name): ?string
105
    {
106
        try {
107
            $this->checkParamName($name);
108
        } catch (Exception $e) {
109
            return null;
110
        }
111
        $name = $this->getAliasParam($name);
112
113
        return ($this->parametersValues[$name]) ?? null;
114
    }
115
116
    /**
117
     * TODO return bool + log() ?
118
     * todo check keyNum <= count($parametersByOrder).
119
     *
120
     * @param $name string|int
121
     *
122
     * @throws Exception
123
     */
124
    protected function checkParamName($name): void
125
    {
126
        // todo verify/useless ?
127
        if (is_int($name)) {
128
            $name = (string)$name;
129
        }
130
131
        // that parameter exists in template ?
132
        if (in_array($name, $this->parametersByOrder)
133
            || array_key_exists($name, static::PARAM_ALIAS)
1 ignored issue
show
Bug introduced by
The constant App\Domain\Models\Wiki\A...kiTemplate::PARAM_ALIAS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
134
        ) {
135
            return;
136
        }
137
138
        // keyNum parameter ?
139
        //        if (!in_array($name, ['1', '2', '3', '4'])) {
140
        throw new Exception(sprintf('no parameter "%s" in template "%s"', $name, get_called_class()));
141
    }
142
143
    /**
144
     * @param string $name
145
     *
146
     * @return string
147
     */
148
    public function getAliasParam(string $name): string
149
    {
150
        if (array_key_exists($name, static::PARAM_ALIAS)) {
1 ignored issue
show
Bug introduced by
The constant App\Domain\Models\Wiki\A...kiTemplate::PARAM_ALIAS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
151
            $name = static::PARAM_ALIAS[$name];
152
        }
153
154
        return $name;
155
    }
156
157
    /**
158
     * TODO check if method set{ParamName} exists.
159
     *
160
     * @param string $name
161
     * @param string $value
162
     *
163
     * @return AbstractParametersObject
164
     * @throws Exception
165
     */
166
    public function setParam(string $name, string $value): AbstractParametersObject
167
    {
168
        try {
169
            $this->checkParamName($name);
170
        } catch (Throwable $e) {
171
            $this->log[] = sprintf('no parameter "%s" in AbstractParametersObject "%s"', $name, get_called_class());
172
173
            return $this;
174
        }
175
176
        $name = $this->getAliasParam($name);
177
        $value = trim($value);
178
        if (!empty($value) || $this->parametersValues[$name]) {
179
            $this->parametersValues[$name] = $value;
180
        }
181
182
        return $this;
183
    }
184
185
    /**
186
     * @param $param
187
     *
188
     * @return string|null
189
     * @throws Exception
190
     */
191
    public function __get($param): ?string
192
    {
193
        $this->checkParamName($param);
194
195
        if (!empty($this->parametersValues[$param])) {
196
            return $this->parametersValues[$param];
197
        }
198
199
        // todo param_alias ?
200
        return null;
201
    }
202
203
    public function unsetParam(string $name): void
204
    {
205
        $this->checkParamName($name);
206
        $name = $this->getAliasParam($name);
207
        unset($this->parametersValues[$name]);
208
    }
209
210
    /**
211
     * TODO move/refac.
212
     *
213
     * @param string $tplText
214
     *
215
     * @throws Exception
216
     */
217
    public function hydrateFromText(string $tplText)
218
    {
219
        if (WikiTextUtil::isCommented($tplText)) {
220
            throw new DomainException('HTML comment tag detected');
221
        }
222
        $data = TemplateParser::parseDataFromTemplate($this::MODEL_NAME, $tplText);
223
        $this->detectUserSeparator($tplText);
224
        $this->hydrate($data);
225
    }
226
227
    public function detectUserSeparator($text): void
228
    {
229
        $this->userSeparator = TemplateParser::findUserStyleSeparator($text);
230
    }
231
232
    /**
233
     * @param array $data
234
     *
235
     * @return AbstractWikiTemplate
236
     * @throws Exception
237
     */
238
    public function hydrate(array $data): self
239
    {
240
        foreach ($data as $name => $value) {
241
            if (is_string($value)) {
242
                $this->hydrateTemplateParameter($name, $value);
243
            }
244
        }
245
246
        $this->setParamOrderByUser($data);
247
248
        return $this;
249
    }
250
251
    /**
252
     * @param        $name  string|int
253
     * @param string $value
254
     *
255
     * @throws Exception
256
     */
257
    protected function hydrateTemplateParameter($name, string $value): void
258
    {
259
        // Gestion alias
260
        try {
261
            $this->checkParamName($name);
262
            $name = $this->getAliasParam($name); // main parameter name
263
264
            // Gestion des doublons de paramètres
265
            if (!empty($this->getParam($name))) {
266
                if (!empty($value)) {
267
                    $this->log[] = "parameter $name en doublon";
268
                    $this->parametersErrorFromHydrate[$name.'-doublon'] = $value;
269
                }
270
271
                return;
272
            }
273
        } catch (Throwable $e) {
274
            unset($e);
275
            // hack : 1 => "ouvrage collectif"
276
            $name = (string)$name;
277
            $this->log[] = "parameter $name not found";
278
            $this->parametersErrorFromHydrate[$name] = $value;
279
280
            return;
281
        }
282
283
284
        if (empty($value)) {
285
            // optional parameter
286
            if (!isset(static::REQUIRED_PARAMETERS[$name])) {
287
                unset($this->parametersValues[$name]);
288
289
                return;
290
            }
291
            // required parameter
292
            $this->parametersValues[$name] = '';
293
        }
294
295
        $method = $this->setterMethodName($name);
296
        if (method_exists($this, $method)) {
297
            $this->$method($value);
298
299
            return;
300
        }
301
302
        $this->parametersValues[$name] = $value;
303
    }
304
305
    /**
306
     * Define the serialize order of parameters (from user initial choice).
307
     * default : $params = ['param1'=>'', 'param2' => '', ...]
308
     * OK with $params = ['a','b','c'].
309
     *
310
     * @param array
311
     *
312
     * @throws Exception
313
     */
314
    public function setParamOrderByUser(array $params = []): void
315
    {
316
        $validParams = [];
317
        foreach ($params as $key => $value) {
318
            $name = (is_int($key)) ? $value : $key;
319
320
            try {
321
                $this->checkParamName($name);
322
                $name = $this->getAliasParam($name);
323
                $validParams[] = $name;
324
            } catch (Throwable $e) {
325
                unset($e);
326
                $this->log[] = "Parameter $name do not exists";
327
328
                continue;
329
            }
330
        }
331
        $this->paramOrderByUser = $validParams;
332
    }
333
334
    /**
335
     * TODO : data transfer object (DTO) to mix userErrorParam data ?
336
     * TODO : refac $inlineStyle as $userPreferences[] and bool flag on serialize().
337
     *
338
     * @param bool|null $cleanOrder
339
     *
340
     * @return string
341
     */
342
    public function serialize(?bool $cleanOrder = false): string
343
    {
344
        $paramsByRenderOrder = $this->paramsByRenderOrder($cleanOrder);
345
        $paramsByRenderOrder = $this->filterEmptyNotRequired($paramsByRenderOrder);
346
347
        // TODO : $option to add or not the wrong parameters ?
348
        // Using the wrong parameters+value from user input ?
349
        $paramsByRenderOrder = $this->mergeWrongParametersFromUser($paramsByRenderOrder);
350
351
        $string = '{{'.static::MODEL_NAME;
352
        foreach ($paramsByRenderOrder as $paramName => $paramValue) {
353
            $string .= ($this->userSeparator) ?? '|';
354
355
            if (!in_array($paramName, ['0', '1', '2', '3', '4', '5'])) {
356
                $string .= $paramName.'=';
357
                // {{template|1=blabla}} -> {{template|blabla}}
358
            }
359
            $string .= $paramValue;
360
        }
361
        // expanded model -> "\n}}"
362
        if ($this->userSeparator && false !== strpos($this->userSeparator, "\n")) {
363
            $string .= "\n";
364
        }
365
        $string .= '}}';
366
367
        return $string;
368
    }
369
370
    /**
371
     * @param bool|null $cleanOrder
372
     *
373
     * @return array
374
     */
375
    protected function paramsByRenderOrder(?bool $cleanOrder = false): array
376
    {
377
        $renderParams = [];
378
379
        // By user order
380
        if (!empty($this->paramOrderByUser) && !$cleanOrder) {
381
            $completeFantasyOrder = $this->completeFantasyOrder(
382
                $this->paramOrderByUser,
383
                $this->parametersByOrder
384
            );
385
386
            foreach ($completeFantasyOrder as $paramName) {
387
                if (isset($this->parametersValues[$paramName])) {
388
                    $renderParams[$paramName] = $this->parametersValues[$paramName];
389
                }
390
            }
391
392
            return $renderParams;
393
        }
394
395
        // default order
396
        foreach ($this->parametersByOrder as $order => $paramName) {
397
            if (isset($this->parametersValues[$paramName])) {
398
                $renderParams[$paramName] = $this->parametersValues[$paramName];
399
            }
400
        }
401
402
        return $renderParams;
403
    }
404
405
    /**
406
     * Delete key if empty value and the key not required.
407
     *
408
     * @param array $params
409
     *
410
     * @return array
411
     */
412
    protected function filterEmptyNotRequired(array $params): array
413
    {
414
        $render = [];
415
        foreach ($params as $name => $value) {
416
            if (empty($value) && !isset(static::REQUIRED_PARAMETERS[$name])) {
417
                continue;
418
            }
419
            $render[$name] = $params[$name];
420
        }
421
422
        return $render;
423
    }
424
425
    /**
426
     * Merge Render data with wrong parameters+value from user input.
427
     * The wrong ones already corrected are not added.
428
     *
429
     * @param array $paramsByRenderOrder
430
     *
431
     * @return array
432
     */
433
    protected function mergeWrongParametersFromUser(array $paramsByRenderOrder): array
434
    {
435
        if (!empty($this->parametersErrorFromHydrate)) {
436
            // FIXED? : si y'a de l'info dans un paramètre erreur et sans value...
437
            //$errorUserData = $this->deleteEmptyValueArray($this->parametersErrorFromHydrate);
438
            $errorUserData = $this->parametersErrorFromHydrate;
439
440
            // Add a note in HTML commentary
441
            foreach ($errorUserData as $param => $value) {
442
                if ('string' === gettype($param) && empty(trim($param))) {
443
                    continue;
444
                }
445
                if (is_int($param)) {
446
                    // erreur "|lire en ligne|"
447
                    if (in_array($value, $this->getParamsAndAlias())) {
448
                        unset($errorUserData[$param]);
449
450
                        continue;
451
                    }
452
453
                    // ou 1= 2= 3=
454
                    $errorUserData[$param] = $value.' <!--VALEUR SANS NOM DE PARAMETRE -->';
455
456
                    continue;
457
                }
458
                $errorUserData[$param] = $value." <!--PARAMETRE '$param' N'EXISTE PAS -->";
459
            }
460
            $paramsByRenderOrder = array_merge($paramsByRenderOrder, $errorUserData);
461
        }
462
463
        return $paramsByRenderOrder;
464
    }
465
}
466