Passed
Branch dev (b7aeac)
by Dispositif
03:10
created

AbstractWikiTemplate   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 98
c 0
b 0
f 0
dl 0
loc 287
rs 9.44
wmc 37

9 Methods

Rating   Name   Duplication   Size   Complexity  
B serialize() 0 45 9
A setParamOrderByUser() 0 13 4
A toArray() 0 5 1
A detectUserSeparator() 0 4 1
B mergeWrongParametersFromUser() 0 31 7
A paramsByRenderOrder() 0 22 5
A hydrateFromText() 0 13 2
A hydrate() 0 6 1
B hydrateTemplateParameter() 0 46 7
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
18
/**
19
 * todo correct text bellow
20
 * The mother of all the wiki-template classes.
21
 * Methods for the wiki-parameters data, hydratation, personnal wiki-style conservation, required params,
22
 * handling error/alias of wiki-parameters, complex serialization into wikicode (minimum params), etc.
23
 * No abstract method.
24
 * Minimum setup for child class : set 'const MODEL_NAME' and it's done !
25
 * Class AbstractWikiTemplate.
26
 */
27
abstract class AbstractWikiTemplate extends AbstractStrictWikiTemplate implements WikiTemplateInterface
28
{
29
    use ArrayProcessTrait, InfoTrait;
30
31
    public $parametersErrorFromHydrate;
32
33
    public $userSeparator;
34
35
    public $userMultiSpaced = false;
36
37
    /**
38
     * optional
39
     * Not a constant so it can be modified in constructor.
40
     * Commented so it can be inherit from trait in OuvrageTemplate (bad design)
41
     */
42
    //protected $parametersByOrder = [];
43
44
    protected $paramOrderByUser = [];
45
46
    /**
47
     * TODO : DONE
48
     * TODO : refac $inlineStyle as $userPreferences[].
49
     *
50
     * @param bool|null $cleanOrder
51
     *
52
     * @return string
53
     */
54
    public function serialize(?bool $cleanOrder = false): string
55
    {
56
        $paramsByRenderOrder = $this->paramsByRenderOrder($cleanOrder);
57
        $paramsByRenderOrder = $this->keepMinimumOrNotEmpty($paramsByRenderOrder);
58
59
        // max caractères des paramètres (valides)
60
        $maxChars = 0;
61
        foreach (array_keys($paramsByRenderOrder) as $paramName) {
62
            $maxChars = max($maxChars, mb_strlen($paramName));
63
        }
64
65
        // TODO old : $option 'strict' to keep/delete the wrong parameters ?
66
        // Using the wrong parameters+value from user input ?
67
        $paramsByRenderOrder = $this->mergeWrongParametersFromUser($paramsByRenderOrder);
68
69
        $string = '{{'.static::WIKITEMPLATE_NAME;
70
        foreach ($paramsByRenderOrder as $paramName => $paramValue) {
71
            $string .= ($this->userSeparator) ?? '|';
72
73
            if (!in_array($paramName, ['0', '1', '2', '3', '4', '5'])) {
74
                $string .= $paramName;
75
76
                // MultiSpaced : espacements multiples pour style étendu : "auteur    = Bla"
77
                if ($this->userSeparator
78
                    && false !== strpos($this->userSeparator, "\n")
79
                    && $this->userMultiSpaced
80
                ) {
81
                    $spaceNb = max(0, $maxChars - mb_strlen($paramName));
82
                    $string .= str_repeat(' ', $spaceNb);
83
                    $string .= ' = ';
84
                } else {
85
                    // style condensé "auteur=Bla" ou non multiSpaced
86
                    $string .= '=';
87
                }
88
            }
89
            // {{template|1=blabla}} -> {{template|blabla}}
90
            $string .= $paramValue;
91
        }
92
        // expanded model -> "\n}}"
93
        if ($this->userSeparator && false !== strpos($this->userSeparator, "\n")) {
94
            $string .= "\n";
95
        }
96
        $string .= '}}';
97
98
        return $string;
99
    }
100
101
    /**
102
     *  TODO DONE
103
     *
104
     * @param bool|null $cleanOrder
105
     *
106
     * @return array
107
     */
108
    protected function paramsByRenderOrder(?bool $cleanOrder = false): array
109
    {
110
        $renderParams = [];
111
112
        // By user order
113
        if (!empty($this->paramOrderByUser) && !$cleanOrder) {
114
            $completeFantasyOrder = $this->completeFantasyOrder(
115
                $this->paramOrderByUser,
116
                $this->parametersByOrder
117
            );
118
119
            foreach ($completeFantasyOrder as $paramName) {
120
                if (isset($this->parametersValues[$paramName])) {
121
                    $renderParams[$paramName] = $this->parametersValues[$paramName];
122
                }
123
            }
124
125
            return $renderParams;
126
        }
127
128
        // default order
129
        return parent::paramsByRenderOrder();
130
    }
131
132
    /**
133
     * Merge Render data with wrong parameters+value from user input.
134
     * The wrong ones already corrected are not added.
135
     *
136
     * @param array $paramsByRenderOrder
137
     *
138
     * @return array
139
     */
140
    protected function mergeWrongParametersFromUser(array $paramsByRenderOrder): array
141
    {
142
        if (!empty($this->parametersErrorFromHydrate)) {
143
            // FIXED? : si y'a de l'info dans un paramètre erreur et sans value...
144
            //$errorUserData = $this->deleteEmptyValueArray($this->parametersErrorFromHydrate);
145
            $errorUserData = $this->parametersErrorFromHydrate;
146
147
            // Add a note in HTML commentary
148
            foreach ($errorUserData as $param => $value) {
149
                if ('string' === gettype($param) && empty(trim($param))) {
150
                    continue;
151
                }
152
                if (is_int($param)) {
153
                    // erreur "|lire en ligne|"
154
                    if (in_array($value, $this->getParamsAndAlias())) {
155
                        unset($errorUserData[$param]);
156
157
                        continue;
158
                    }
159
160
                    // ou 1= 2= 3=
161
                    $errorUserData[$param] = $value.' <!--VALEUR SANS NOM DE PARAMETRE -->';
162
163
                    continue;
164
                }
165
                $errorUserData[$param] = $value." <!--PARAMETRE '$param' N'EXISTE PAS -->";
166
            }
167
            $paramsByRenderOrder = array_merge($paramsByRenderOrder, $errorUserData);
168
        }
169
170
        return $paramsByRenderOrder;
171
    }
172
173
    /**
174
     * KEEP THERE
175
     * Get data from wiki-template. Also invalid param/values.
176
     *
177
     * @return array
178
     */
179
    public function toArray(): array
180
    {
181
        $allValue = array_merge($this->parametersValues, $this->parametersErrorFromHydrate ?? []);
182
183
        return $this->deleteEmptyValueArray($allValue);
184
    }
185
186
    /**
187
     * TODO move ? trait ? to TemplateFactory ? /refac.
188
     *
189
     * @param string $tplText
190
     *
191
     * @return AbstractWikiTemplate
192
     * @throws Exception
193
     */
194
    public function hydrateFromText(string $tplText): AbstractWikiTemplate
195
    {
196
        $tplText = str_ireplace(static::COMMENT_STRIPPED, '', $tplText);
197
198
        if (WikiTextUtil::isCommented($tplText)) {
199
            throw new DomainException('HTML comment tag detected');
200
        }
201
        $data = TemplateParser::parseDataFromTemplate($this::WIKITEMPLATE_NAME, $tplText);
202
        $this->hydrate($data);
203
204
        $this->detectUserSeparator($tplText);
205
206
        return $this;
207
    }
208
209
    /**
210
     * keep there
211
     *
212
     * @param $text
213
     */
214
    public function detectUserSeparator($text): void
215
    {
216
        $this->userSeparator = TemplateParser::findUserStyleSeparator($text);
217
        $this->userMultiSpaced = TemplateParser::isMultispacedTemplate($text);
218
    }
219
220
    /**
221
     * @param array $data
222
     *
223
     * @return AbstractStrictWikiTemplate
224
     * @throws Exception
225
     */
226
    public function hydrate(array $data): AbstractStrictWikiTemplate
227
    {
228
        parent::hydrate($data);
229
        $this->setParamOrderByUser($data);
230
231
        return $this;
232
    }
233
234
    /**
235
     * TODO : KEEP
236
     * Define the serialize order of parameters (from user initial choice).
237
     * default : $params = ['param1'=>'', 'param2' => '', ...]
238
     * OK with $params = ['a','b','c'].
239
     *
240
     * @param array
241
     *
242
     * @throws Exception
243
     */
244
    private function setParamOrderByUser(array $params = []): void
245
    {
246
        $validParams = [];
247
        foreach ($params as $key => $value) {
248
            $name = (is_int($key)) ? $value : $key;
249
            if (!$this->isValidParamName($name)) {
250
                $this->log[] = "Parameter $name do not exists";
251
                continue;
252
            }
253
            $name = $this->getAliasParam($name);
254
            $validParams[] = $name;
255
        }
256
        $this->paramOrderByUser = $validParams;
257
    }
258
259
    /**
260
     * TODO refac extract
261
     * todo : why not using setParam() ?????
262
     *
263
     * @param           $name    string|int
264
     * @param string    $value
265
     *
266
     * @throws Exception
267
     */
268
    protected function hydrateTemplateParameter($name, string $value): void
269
    {
270
        // Gestion alias
271
        if (!$this->isValidParamName($name)) {
272
            // hack : 1 => "ouvrage collectif"
273
            $name = (string)$name;
274
            $this->log[] = "parameter $name not found";
275
276
            // todo keep there
277
            $this->parametersErrorFromHydrate[$name] = $value;
278
279
            return;
280
        }
281
282
        $name = $this->getAliasParam($name); // main parameter name
283
284
        // todo keep that
285
        // Gestion des doublons de paramètres
286
        if ($this->hasParamValue($name)) {
287
            if (!empty($value)) {
288
                $this->log[] = "parameter $name en doublon";
289
                $this->parametersErrorFromHydrate[$name.'-doublon'] = $value;
290
            }
291
292
            return;
293
        }
294
295
        if (empty($value)) {
296
            // optional parameter
297
            if (!isset(static::MINIMUM_PARAMETERS[$name])) {
298
                unset($this->parametersValues[$name]);
299
300
                return;
301
            }
302
            // required parameter
303
            $this->parametersValues[$name] = '';
304
        }
305
306
        $method = $this->setterMethodName($name);
307
        if (method_exists($this, $method)) {
308
            $this->$method($value);
309
310
            return;
311
        }
312
313
        $this->parametersValues[$name] = $value;
314
    }
315
}
316