AddonXmlGenerator::setContent()   A
last analyzed

Complexity

Conditions 2
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 10
c 0
b 0
f 0
rs 10
cc 2
nc 3
nop 1
1
<?php
2
3
namespace generators\AddonXml;
4
5
use generators\AddonXml\exceptions\InvalidAddonXmlException;
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
    const FILENAME = 'app/addons/${addon}/addon.xml';
19
    private $templatePath = '';
20
    private $content;
21
    private $config;
22
    private $mediator;
23
24
    protected $variants = [
25
        'scheme' => [
26
            '3.0',
27
            '4.0'
28
        ],
29
        'status' => [
30
            'active',
31
            'disabled'
32
        ],
33
        'item' => [
34
            'input',
35
            'textarea',
36
            'password',
37
            'checkbox',
38
            'selectbox',
39
            'multiple select',
40
            'multiple checkboxes',
41
            'countries list',
42
            'states list',
43
            'file',
44
            'info',
45
            'header',
46
            'template'
47
        ]
48
    ];
49
50
    function __construct(
51
        Config $config
52
    )
53
    {
54
        $this->config = $config;
55
    }
56
57
    public function setMediator(AbstractMediator $mediator): void
58
    {
59
        $this->mediator = $mediator;
60
    }
61
62
    public function trigger(string $name, $data = [], $sender = null): void
63
    {
64
        $this->mediator && $this->mediator->trigger($name, $data, $this);
65
    }
66
67
    /**
68
     * @inheritdoc
69
     */
70
    public function getTemplateFilename(): string
71
    {
72
        return $this->templatePath;
73
    }
74
75
    /**
76
     * returns full path for addon.xml file
77
     * @return string
78
     */
79
    public function getPath(): string
80
    {
81
        $addon_id = $this->config->get('addon.id');
82
83
        if (!$addon_id) {
84
            throw new \InvalidArgumentException('Addon id (name) not specified');
85
        }
86
87
        $path = $this->config->get('filesystem.output_path')
88
            . str_replace('${addon}', $addon_id, static::FILENAME);
89
90
        return sanitize_filename($path);
91
    }
92
    
93
    /**
94
     * Set initial content for generator to work with
95
     * @param string $content - content of input xml file
96
     * @throws InvalidContentException if the $content is not valid xml content
97
     * @return AddonXmlGenerator
98
     */
99
    public function setContent(string $content)
100
    {
101
        try {
102
            $simpleXmlElement = new \SimpleXMLElement($content);
103
            $this->content = new XML($simpleXmlElement);
104
        } catch (\Exception $error) {
105
            throw new InvalidContentException('Can\'t create xml from content');
106
        }
107
108
        return $this;
109
    }
110
111
    /**
112
     * Creates addon.xml content
113
     *
114
     * @return AddonXmlGenerator
115
     */
116
    public function create()
117
    {
118
        $this->createAddon();
119
        $this->setScheme($this->config->get('addon.scheme'));
120
        $this->setEditionType($this->config->get('addon.edition_type'));
121
        $this->setId($this->config->get('addon.id'));
122
        $this->setVersion($this->config->get('addon.version'));
123
        $this->setPriority($this->config->get('addon.priority'));
124
        $this->setStatus($this->config->get('addon.status'));
125
        $this->setAutoInstall($this->config->get('addon.auto_install'));
126
        $this->setSettings();
127
        // $this->setSettingsLayout();
128
129
        return $this;
130
    }
131
132
    /**
133
     * Creates root element for xml - addon
134
     * @return AddonXmlGenerator
135
     */
136
    public function createAddon()
137
    {
138
        $simpleXmlElement = new \SimpleXMLElement('<addon></addon>');
139
        $this->content = new XML($simpleXmlElement);
140
        $this->trigger(
141
            'addonxml.created',
142
            [
143
                'addon.id' => $this->config->get('addon.id')
144
            ]
145
        );
146
147
        return $this;
148
    }
149
150
    /**
151
     * Retrieves addon xml element
152
     * @throws InvalidAddonXmlException if no addon node found
153
     * @return Xml - addon node
154
     */
155
    public function getAddon()
156
    {
157
        $addonElemenent = $this->content;
158
159
        if ('addon' !== $addonElemenent->getName()) {
160
            throw new InvalidAddonXmlException('No addon node found');
161
        }
162
163
        return $addonElemenent;
164
    }
165
166
    /**
167
     * <addon ... scheme="3.0">
168
     * @param string $scheme - scheme
169
     * @return AddonXmlGenerator
170
     */
171
    public function setScheme(string $scheme = '3.0')
172
    {
173
        $this->getAddon()->setAttribute('scheme', $scheme);
174
175
        return $this;
176
    }
177
178
    /**
179
     * <addon ... edition_type="ROOT,ULT:VENDOR">
180
     * @param string $type - edition_type
181
     * @return AddonXmlGenerator
182
     */
183
    public function setEditionType(string $type = 'ROOT,ULT:VENDOR')
184
    {
185
        $this->getAddon()->setAttribute('edition_type', $type);
186
187
        return $this;
188
    }
189
190
    /**
191
     * <id>sample_addon</id>
192
     * @param string $value - content of id node
193
     * @return AddonXmlGenerator
194
     */
195
    public function setId(string $value = 'sample_addon')
196
    {
197
        $this->getAddon()->setUniqueChild('id', $value);
198
199
        return $this;
200
    }
201
202
    /**
203
     * <version>1.0</version>
204
     * @param string $value - content of version node
205
     * @return AddonXmlGenerator
206
     */
207
    public function setVersion(string $value = '4.9')
208
    {
209
        $this->getAddon()->setUniqueChild('version', $value);
210
211
        return $this;
212
    }
213
214
    /**
215
     * <priority>100</priority>
216
     * @param string $value - content of priority node
217
     * @return AddonXmlGenerator
218
     */
219
    public function setPriority(string $value = '1000')
220
    {
221
        $this->getAddon()->setUniqueChild('priority', $value);
222
223
        return $this;
224
    }
225
226
    /**
227
     * <status>active</status>
228
     * @param string $value - content of status node
229
     * @return AddonXmlGenerator
230
     */
231
    public function setStatus(string $value = 'active')
232
    {
233
        $this->getAddon()->setUniqueChild('status', $value);
234
235
        return $this;
236
    }
237
238
    /**
239
     * <auto_install>MULTIVENDOR,ULTIMATE</auto_install>
240
     * @param string $value - content of auto_install node
241
     * @return AddonXmlGenerator
242
     */
243
    public function setAutoInstall(string $value = 'MULTIVENDOR,ULTIMATE')
244
    {
245
        $this->getAddon()->setUniqueChild('auto_install', $value);
246
247
        return $this;
248
    }
249
250
    /**
251
     * <settings...>
252
     * @return AddonXmlGenerator
253
     */
254
    public function setSettings()
255
    {
256
        $this->getAddon()->setUniqueChild('settings', '');
257
258
        return $this;
259
    }
260
261
    /**
262
     * Retrieve settings node
263
     * @return Xml|null - settings node
264
     */
265
    public function getSettings()
266
    {
267
        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...
268
    }
269
270
    /**
271
     * <settings ... layout="separate">
272
     * @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...
273
     * @return AddonXmlGenerator
274
     */
275
    public function setSettingsLayout(string $value = 'popup')
276
    {
277
        $this->getSettings()->setAttribute('layout', $value);
278
279
        return $this;
280
    }
281
282
    /**
283
     * Adds section to settings element
284
     * @throws DuplicateIdException if section with same id already exists
285
     * @return AddonXmlGenerator
286
     */
287
    public function addSection(string $id)
288
    {
289
        if ($this->getSection($id)) {
290
            throw new DuplicateIdException('section with same id already exists: ' . $id);
291
        }
292
293
        $sections = $this->getSections();
294
295
        if (null === $sections) {
296
            $sections =
297
                $this
298
                    ->getAddon()
299
                    ->getSingleElement('settings')
300
                    ->addChild('sections');
301
        }
302
303
        $sections
304
            ->addChild('section')
305
            ->addAttribute('id', $id);
306
307
        $this->trigger(
308
            'addonxml.settingSection.added',
309
            [
310
                'addon.id'  => $this->config->getOr('addon', 'addon.id'),
311
                'id'        => $id
312
            ]
313
        );
314
315
        return $this;
316
    }
317
318
    /**
319
     * Retrieves section with the specified id
320
     * @param string $id - by this id function will find section
321
     * @return Xml|null
322
     */
323
    public function getSection(string $id)
324
    {
325
        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...
326
    }
327
328
    /**
329
     * Retrieves sections node
330
     * @return Xml|null
331
     */
332
    public function getSections()
333
    {
334
        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...
335
    }
336
337
    /**
338
     * Set setting with replace if exists
339
     * @param string $section_id - to which section (id) setting will belong
340
     * @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...
341
     * @param string $id
342
     * @param string $default_value
343
     * @param array $variants - list of possible values
344
     * Full information about params [https://docs.cs-cart.com/4.9.x/developer_guide/addons/scheme/scheme3.0_structure.html]
345
     * @throws DuplicateIdException if setting with same id already exists
346
     *
347
     * @return AddonXmlGenerator
348
     * @todo setting item and variant item can be the same
349
     * write test and solve this problem
350
     */
351
    private function _setSetting(
352
        string $section_id = 'section1',
353
        string $type,
354
        string $id,
355
        string $default_value = '',
356
        array  $variants = []
357
    )
358
    {
359
        $itemElement = $this->content->getSingleElement('item', $id);
360
        if (null !== $itemElement) {
361
            $itemElement->remove();
362
        }
363
364
        $sectionElement = $this->getSection($section_id);
365
366
        if (null === $sectionElement) {
367
            $sectionElement = $this->addSection($section_id)->getSection($section_id);
368
        }
369
370
        $itemsElement = $sectionElement->getSingleElement('items');
371
372
        if (null === $itemsElement) {
373
            $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

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