Passed
Branch 4.9 (cb955a)
by Mikhail
01:30
created

AddonXmlGenerator::toXml()   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
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace generators\AddonXml;
4
5
use exceptions\InvalidAddonXmlException;
0 ignored issues
show
Bug introduced by
The type exceptions\InvalidAddonXmlException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use generators\AddonXml\exceptions\InvalidContentException;
7
use generators\AddonXml\exceptions\DuplicateIdException;
8
use generators\Xml;
9
use mediators\AbstractMediator;
10
use mediators\ICanNotify;
11
use Config;
12
13
/**
14
 * @todo make functions like setSettings curry of one general function
15
 */
16
final class AddonXmlGenerator extends \generators\AbstractGenerator implements ICanNotify
17
{
18
    // readonly
19
    private $pathTemplate = '/app/addons/${addon}/addon.xml';
20
    private $templatePath = '';
21
    private $content;
22
    private $config;
23
    private $mediator;
24
25
    function __construct(
26
        Config $config
27
    )
28
    {
29
        $this->config = $config;
30
    }
31
32
    public function setMediator(AbstractMediator $mediator): void
33
    {
34
        $this->mediator = $mediator;
35
    }
36
37
    public function trigger(string $name, $data = [], $sender = null): void
38
    {
39
        $this->mediator && $this->mediator->trigger($name, $data, $this);
40
    }
41
42
    /**
43
     * @inheritdoc
44
     */
45
    public function getTemplateFilename(): string
46
    {
47
        return $this->templatePath;
48
    }
49
50
    /**
51
     * returns full path for addon.xml file
52
     * @return string
53
     */
54
    public function getPath(): string
55
    {
56
        $addon_id = $this->config->getOr('addon', 'addon.id');
57
58
        if (!$addon_id) {
59
            throw new \InvalidArgumentException('Addon id (name) not specified');
60
        }
61
62
        $path = $this->config->get('path')
63
            . $this->config->get('filesystem.output_path_relative')
64
            . str_replace('${addon}', $addon_id, $this->pathTemplate);
65
66
        return get_absolute_path($path);
67
    }
68
69
    /**
70
     * Set initial content for generator to work with
71
     * @param string $content - content of input xml file
72
     * @throws InvalidContentException if the $content is not valid xml content
73
     * @return AddonXmlGenerator
74
     */
75
    public function setContent(string $content)
76
    {
77
        try {
78
            $simpleXmlElement = new \SimpleXMLElement($content);
79
            $this->content = new XML($simpleXmlElement);
80
        } catch (\Exception $error) {
81
            throw new  InvalidContentException('Can\'t create xml from content');
82
        }
83
84
        return $this;
85
    }
86
87
    /**
88
     * Creates addon.xml content
89
     *
90
     * @return AddonXmlGenerator
91
     */
92
    public function create()
93
    {
94
        $this->createAddon();
95
        $this->setScheme();
96
        $this->setEditionType($this->config->get('addon.edition_type'));
97
        $this->setId($this->config->getOr('addon', 'addon.id'));
0 ignored issues
show
Bug introduced by
It seems like $this->config->getOr('addon', 'addon.id') can also be of type null; however, parameter $value of generators\AddonXml\AddonXmlGenerator::setId() 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

97
        $this->setId(/** @scrutinizer ignore-type */ $this->config->getOr('addon', 'addon.id'));
Loading history...
98
        $this->setVersion($this->config->get('addon.version'));
99
        $this->setPriority($this->config->get('addon.priority'));
100
        $this->setStatus($this->config->get('addon.status'));
101
        $this->setAutoInstall($this->config->get('addon.auto_install'));
102
        $this->setSettings();
103
        // $this->setSettingsLayout();
104
105
        return $this;
106
    }
107
108
    /**
109
     * Creates root element for xml - addon
110
     * @return AddonXmlGenerator
111
     */
112
    public function createAddon()
113
    {
114
        $simpleXmlElement = new \SimpleXMLElement('<addon></addon>');
115
        $this->content = new XML($simpleXmlElement);
116
        $this->trigger(
117
            'addonxml.created',
118
            [
119
                'addon.id' => $this->config->getOr('addon', 'addon.id')
120
            ]
121
        );
122
123
        return $this;
124
    }
125
126
    /**
127
     * Retrieves addon xml element
128
     * @throws InvalidAddonXmlException if no addon node found
129
     * @return Xml - addon node
130
     */
131
    public function getAddon()
132
    {
133
        $addonElemenent = $this->content;
134
135
        if ('addon' !== $addonElemenent->getName()) {
136
            throw new InvalidAddonXmlException('No addon node found');
137
        }
138
139
        return $addonElemenent;
140
    }
141
142
    /**
143
     * <addon ... scheme="3.0">
144
     * @param string $scheme - scheme
145
     * @return AddonXmlGenerator
146
     */
147
    public function setScheme(string $scheme = '3.0')
148
    {
149
        $this->getAddon()->setAttribute('scheme', $scheme);
150
151
        return $this;
152
    }
153
154
    /**
155
     * <addon ... edition_type="ROOT,ULT:VENDOR">
156
     * @param string $type - edition_type
157
     * @return AddonXmlGenerator
158
     */
159
    public function setEditionType($type = 'ROOT,ULT:VENDOR')
160
    {
161
        $this->getAddon()->setAttribute('edition_type', $type);
162
163
        return $this;
164
    }
165
166
    /**
167
     * <id>sample_addon</id>
168
     * @param string $value - content of id node
169
     * @return AddonXmlGenerator
170
     */
171
    public function setId(string $value = 'sample_addon')
172
    {
173
        $this->getAddon()->setUniqueChild('id', $value);
174
175
        return $this;
176
    }
177
178
    /**
179
     * <version>1.0</version>
180
     * @param string $value - content of version node
181
     * @return AddonXmlGenerator
182
     */
183
    public function setVersion(string $value = '4.9')
184
    {
185
        $this->getAddon()->setUniqueChild('version', $value);
186
187
        return $this;
188
    }
189
190
    /**
191
     * <priority>100</priority>
192
     * @param string $value - content of priority node
193
     * @return AddonXmlGenerator
194
     */
195
    public function setPriority(string $value = '1000')
196
    {
197
        $this->getAddon()->setUniqueChild('priority', $value);
198
199
        return $this;
200
    }
201
202
    /**
203
     * <status>active</status>
204
     * @param string $value - content of status node
205
     * @return AddonXmlGenerator
206
     */
207
    public function setStatus(string $value = 'active')
208
    {
209
        $this->getAddon()->setUniqueChild('status', $value);
210
211
        return $this;
212
    }
213
214
    /**
215
     * <auto_install>MULTIVENDOR,ULTIMATE</auto_install>
216
     * @param string $value - content of auto_install node
217
     * @return AddonXmlGenerator
218
     */
219
    public function setAutoInstall(string $value = 'MULTIVENDOR,ULTIMATE')
220
    {
221
        $this->getAddon()->setUniqueChild('auto_install', $value);
222
223
        return $this;
224
    }
225
226
    /**
227
     * <settings...>
228
     * @return AddonXmlGenerator
229
     */
230
    public function setSettings()
231
    {
232
        $this->getAddon()->setUniqueChild('settings', '');
233
234
        return $this;
235
    }
236
237
    /**
238
     * Retrieve settings node
239
     * @return Xml|null - settings node
240
     */
241
    public function getSettings()
242
    {
243
        return $this->getAddon()->getSingleElement('settings');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAddon()...ngleElement('settings') also could return the type generators\XML[] which is incompatible with the documented return type generators\Xml|null.
Loading history...
244
    }
245
246
    /**
247
     * <settings ... layout="separate">
248
     * @param string layout - 'popup' or 'separate'
0 ignored issues
show
Bug introduced by
The type generators\AddonXml\layout was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
249
     * @return AddonXmlGenerator
250
     */
251
    public function setSettingsLayout(string $value = 'popup')
252
    {
253
        $this->getSettings()->setAttribute('layout', $value);
254
255
        return $this;
256
    }
257
258
    /**
259
     * Adds section to settings element
260
     * @throws DuplicateIdException if section with same id already exists
261
     * @return AddonXmlGenerator
262
     */
263
    public function addSection(string $id)
264
    {
265
        if ($this->getSection($id)) {
266
            throw new DuplicateIdException('section with same id already exists: ' . $id);
267
        }
268
269
        $sections = $this->getSections();
270
271
        if (null === $sections) {
272
            $sections =
273
                $this
274
                    ->getAddon()
275
                    ->getSingleElement('settings')
276
                    ->addChild('sections');
277
        }
278
279
        $sections
280
            ->addChild('section')
281
            ->addAttribute('id', $id);
282
283
        $this->trigger(
284
            'addonxml.settingSection.added',
285
            [
286
                'addon.id'  => $this->config->getOr('addon', 'addon.id'),
287
                'id'        => $id
288
            ]
289
        );
290
291
        return $this;
292
    }
293
294
    /**
295
     * Retrieves section with the specified id
296
     * @param string $id - by this id function will find section
297
     * @return Xml|null
298
     */
299
    public function getSection(string $id)
300
    {
301
        return $this->getAddon()->getSingleElement('section', $id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAddon()...Element('section', $id) also could return the type generators\XML[] which is incompatible with the documented return type generators\Xml|null.
Loading history...
302
    }
303
304
    /**
305
     * Retrieves sections node
306
     * @return Xml|null
307
     */
308
    public function getSections()
309
    {
310
        return $this->getAddon()->getSingleElement('sections');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAddon()...ngleElement('sections') also could return the type generators\XML[] which is incompatible with the documented return type generators\Xml|null.
Loading history...
311
    }
312
313
    /**
314
     * Set setting with replace if exists
315
     * @param string $section_id - to which section (id) setting will belong
316
     * @param string type
0 ignored issues
show
Bug introduced by
The type generators\AddonXml\type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
317
     * @param string $id
318
     * @param string $default_value
319
     * @param array $variants - list of possible values
320
     * Full information about params [https://docs.cs-cart.com/4.9.x/developer_guide/addons/scheme/scheme3.0_structure.html]
321
     * @throws DuplicateIdException if setting with same id already exists
322
     *
323
     * @return AddonXmlGenerator
324
     */
325
    private function _setSetting(
326
        string $section_id = 'section1',
327
        string $type,
328
        string $id,
329
        string $default_value = '',
330
        array  $variants = []
331
    )
332
    {
333
        $itemElement = $this->content->getSingleElement('item', $id);
334
        if (null !== $itemElement) {
335
            $itemElement->remove();
336
        }
337
338
        $sectionElement = $this->getSection($section_id);
339
340
        if (null === $sectionElement) {
341
            $sectionElement = $this->addSection($section_id)->getSection($section_id);
342
        }
343
344
        $itemsElement = $sectionElement->getSingleElement('items');
345
346
        if (null === $itemsElement) {
347
            $itemsElement = $sectionElement->addChild('items');
0 ignored issues
show
Bug introduced by
The method addChild() does not exist on generators\XML. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

347
            /** @scrutinizer ignore-call */ 
348
            $itemsElement = $sectionElement->addChild('items');
Loading history...
348
        }
349
350
        $settingItem = $itemsElement->addChild('item');
351
        $settingItem->addAttribute('id', $id);
352
            $settingItem->addChild('type', $type);
353
            if ($variants) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $variants of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
354
                $variantsElement = $settingItem->addChild('variants');
355
                    foreach($variants as $variant)
356
                    {
357
                        $variantElement = $variantsElement->addChild('item');
358
                            $variantElement->addAttribute('id', $variant);
359
                    }
360
                    unset($variantElement);
361
            }
362
            $settingItem->addChild('default_value', $default_value);
363
364
        return $this;
365
    }
366
367
    /**
368
     * Set setting with replace if exists
369
     * @param string $section_id - to which section (id) setting will belong
370
     * @param string type
371
     * @param string $id
372
     * @param string $default_value
373
     * @param array $variants - list of possible values
374
     * Full information about params [https://docs.cs-cart.com/4.9.x/developer_guide/addons/scheme/scheme3.0_structure.html]
375
     *
376
     * @return AddonXmlGenerator
377
     */
378
    public function setSetting(
379
        string $section_id = 'section1',
380
        string $type,
381
        string $id,
382
        string $default_value = '',
383
        array  $variants = []
384
    )
385
    {
386
        $this->_setSetting(
387
            $section_id,
388
            $type,
389
            $id,
390
            $default_value,
391
            $variants
392
        );
393
394
        $this->trigger(
395
            'addonxml.setting.updated',
396
            [
397
                'addon.id'      => $this->config->getOr('addon', 'addon.id'),
398
                'section_id'    => $section_id,
399
                'type'          => $type,
400
                'id'            => $id,
401
                'variants'      => $variants
402
            ]
403
        );
404
405
        return $this;
406
    }
407
408
    /**
409
     * Set setting without replace if exists
410
     * @param string $section_id - to which section (id) setting will belong
411
     * @param string type
412
     * @param string $id
413
     * @param string $default_value
414
     * @param array $variants - list of possible values
415
     * Full information about params [https://docs.cs-cart.com/4.9.x/developer_guide/addons/scheme/scheme3.0_structure.html]
416
     * @throws DuplicateIdException if setting with same id already exists
417
     *
418
     * @return AddonXmlGenerator
419
     */
420
    public function addSetting(
421
        string $section_id = 'section1',
422
        string $type,
423
        string $id,
424
        string $default_value = '',
425
        array  $variants = []
426
    )
427
    {
428
        $itemElement = $this->content->getSingleElement('item', $id);
429
430
        if (null !== $itemElement) {
431
            throw new DuplicateIdException('Item with same id already exists: ' . $id);
432
        }
433
434
        $this->_setSetting(
435
            $section_id,
436
            $type,
437
            $id,
438
            $default_value,
439
            $variants
440
        );
441
442
        $this->trigger(
443
            'addonxml.setting.added',
444
            [
445
                'addon.id'      => $this->config->getOr('addon', 'addon.id'),
446
                'section_id'    => $section_id,
447
                'type'          => $type,
448
                'id'            => $id,
449
                'variants'      => $variants
450
            ]
451
        );
452
453
        return $this;
454
    }
455
456
    /**
457
     * @todo test
458
     * Remove settings item
459
     * 
460
     * @param string $id
461
     * 
462
     * @return AddonXmlGenerator
463
     */
464
    public function removeSetting(string $id)
465
    {
466
        $itemElement = $this->content->getSingleElement('item', $id);
467
        if (null !== $itemElement) {
468
            $itemElement->remove();
469
        }
470
471
        $this->trigger(
472
            'addonxml.setting.removed',
473
            [
474
                'addon.id'      => $this->config->getOr('addon', 'addon.id'),
475
                'id'            => $id
476
            ]
477
        );
478
479
        return $this;
480
    }
481
482
    /**
483
     * @deprecated - Use toString instead
484
     */
485
    public function toXml(): string
486
    {
487
        return $this->toString();
488
    }
489
490
    /**
491
     * Converts generator result to string
492
     * @return string
493
     */
494
    public function toString(): string
495
    {
496
        $Dom = new \DOMDocument('1.0');
497
        $Dom->preserveWhiteSpace    = false;
498
        $Dom->formatOutput          = true;
499
        $Dom->loadXML($this->content->asXML());
500
501
        return $Dom->saveXML();
502
    }
503
}
504