Passed
Pull Request — master (#1)
by Peter
02:51
created

ContentList::addButtons()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 7
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Website\Form\Factory;
6
7
use AbterPhp\Admin\Form\Factory\Base;
8
use AbterPhp\Framework\Constant\Html5;
9
use AbterPhp\Framework\Constant\Session;
10
use AbterPhp\Framework\Form\Component\Option;
11
use AbterPhp\Framework\Form\Container\CheckboxGroup;
12
use AbterPhp\Framework\Form\Container\FormGroup;
13
use AbterPhp\Framework\Form\Element\Input;
14
use AbterPhp\Framework\Form\Element\Select;
15
use AbterPhp\Framework\Form\Extra\DefaultButtons;
16
use AbterPhp\Framework\Form\Extra\Help;
17
use AbterPhp\Framework\Form\IForm;
18
use AbterPhp\Framework\Form\Label\Label;
19
use AbterPhp\Framework\Html\Component;
20
use AbterPhp\Framework\Html\Component\Button;
21
use AbterPhp\Framework\Html\Tag;
22
use AbterPhp\Framework\I18n\ITranslator;
23
use AbterPhp\Website\Constant\Authorization;
24
use AbterPhp\Website\Domain\Entities\ContentList as Entity;
25
use AbterPhp\Website\Domain\Entities\ContentListItem;
26
use AbterPhp\Website\Domain\Entities\ContentListType;
27
use AbterPhp\Website\Form\Factory\ContentList\Item;
28
use AbterPhp\Website\Orm\ContentListItemRepo as ItemRepo;
29
use AbterPhp\Website\Orm\ContentListTypeRepo as TypeRepo;
30
use Casbin\Enforcer;
31
use Opulence\Orm\IEntity;
32
use Opulence\Sessions\ISession;
33
34
class ContentList extends Base
35
{
36
    private const NEW_ITEM_NAME = 'website:contentListItemNew';
37
38
    private const ITEM_TEMPLATE_CLASS         = 'item-template';
39
    private const NEW_ITEMS_CONTAINER_ID      = 'new-items';
40
    private const EXISTING_ITEMS_CONTAINER_ID = 'existing-items';
41
42
    /** @var TypeRepo */
43
    protected $typeRepo;
44
45
    /** @var ItemRepo */
46
    protected $itemRepo;
47
48
    /** @var Enforcer */
49
    protected $enforcer;
50
51
    /** @var bool */
52
    private $isNew = false;
53
54
    /** @var bool|null */
55
    protected $advancedAllowed;
56
57
    /**
58
     * ContentList constructor.
59
     *
60
     * @param ISession    $session
61
     * @param ITranslator $translator
62
     * @param TypeRepo    $typeRepo
63
     * @param ItemRepo    $itemRepo
64
     * @param Enforcer    $enforcer
65
     */
66
    public function __construct(
67
        ISession $session,
68
        ITranslator $translator,
69
        TypeRepo $typeRepo,
70
        ItemRepo $itemRepo,
71
        Enforcer $enforcer
72
    ) {
73
        parent::__construct($session, $translator);
74
75
        $this->typeRepo = $typeRepo;
76
        $this->itemRepo = $itemRepo;
77
        $this->enforcer = $enforcer;
78
    }
79
80
    /**
81
     * @return bool
82
     * @throws \Casbin\Exceptions\CasbinException
83
     */
84
    protected function isAdvancedAllowed(): bool
85
    {
86
        if ($this->advancedAllowed !== null) {
87
            return $this->advancedAllowed;
88
        }
89
90
        $username              = $this->session->get(Session::USERNAME);
91
        $this->advancedAllowed = $this->enforcer->enforce(
92
            $username,
93
            Authorization::RESOURCE_LISTS,
94
            Authorization::ROLE_ADVANCED_WRITE
95
        );
96
97
        return $this->advancedAllowed;
98
    }
99
100
    /**
101
     * @param string       $action
102
     * @param string       $method
103
     * @param string       $showUrl
104
     * @param IEntity|null $entity
105
     *
106
     * @return IForm
107
     * @throws \Casbin\Exceptions\CasbinException
108
     */
109
    public function create(string $action, string $method, string $showUrl, ?IEntity $entity = null): IForm
110
    {
111
        assert($entity instanceof Entity, new \InvalidArgumentException());
112
113
        $this->isNew = ($entity->getName() == '');
114
115
        $this->createForm($action, $method)
116
            ->addDefaultElements()
117
            ->addTypeId($entity)
118
            ->addName($entity)
119
            ->addIdentifier($entity)
120
            ->addProtected($entity)
121
            ->addWithImage($entity)
122
            ->addWithLinks($entity)
123
            ->addWithHtml($entity)
124
            ->addExistingItems($entity)
125
            ->addNewItems($entity)
126
            ->addAddBtn($entity)
127
            ->addButtons($entity, $showUrl);
128
129
        $form = $this->form;
130
131
        $this->form = null;
132
133
        return $form;
134
    }
135
136
    /**
137
     * @param Entity $entity
138
     *
139
     * @return $this
140
     */
141
    protected function addTypeId(Entity $entity): ContentList
142
    {
143
        // Type of protected lists can only be set by advanced users
144
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
145
            return $this;
146
        }
147
148
        $allTypes = $this->getAllTypes();
149
        $typeId   = $entity->getTypeId();
150
151
        $options = $this->createTypeIdOptions($allTypes, $typeId);
152
153
        $this->form[] = new FormGroup(
154
            $this->createTypeIdSelect($options),
155
            $this->createTypeIdLabel()
156
        );
157
158
        return $this;
159
    }
160
161
    /**
162
     * @return ContentListType[]
163
     */
164
    protected function getAllTypes(): array
165
    {
166
        return $this->typeRepo->getAll();
167
    }
168
169
    /**
170
     * @param ContentListType[] $allTypes
171
     * @param string            $typeId
172
     *
173
     * @return Option[]
174
     */
175
    protected function createTypeIdOptions(array $allTypes, string $typeId): array
176
    {
177
        $options   = [];
178
        $options[] = new Option('', 'framework:none', false);
179
        foreach ($allTypes as $layout) {
180
            $isSelected = $layout->getId() === $typeId;
181
            $options[]  = new Option($layout->getId(), $layout->getLabel(), $isSelected);
182
        }
183
184
        return $options;
185
    }
186
187
    /**
188
     * @param Option[] $options
189
     *
190
     * @return Select
191
     */
192
    protected function createTypeIdSelect(array $options): Select
193
    {
194
        $select = new Select('type_id', 'type_id');
195
196
        foreach ($options as $option) {
197
            $select[] = $option;
198
        }
199
200
        return $select;
201
    }
202
203
    /**
204
     * @return Label
205
     */
206
    protected function createTypeIdLabel(): Label
207
    {
208
        return new Label('type_id', 'website:contentListTypeIdLabel');
209
    }
210
211
    /**
212
     * @param Entity $entity
213
     *
214
     * @return $this
215
     */
216
    protected function addName(Entity $entity): ContentList
217
    {
218
        $input = new Input('name', 'name', $entity->getName());
219
        $label = new Label('name', 'website:contentListName');
220
221
        $this->form[] = new FormGroup($input, $label);
222
223
        return $this;
224
    }
225
226
    /**
227
     * @param Entity $entity
228
     *
229
     * @return $this
230
     */
231
    protected function addIdentifier(Entity $entity): ContentList
232
    {
233
        // Identifier of protected lists can only be set by advanced users
234
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
235
            return $this;
236
        }
237
238
        $input = new Input('identifier', 'identifier', $entity->getIdentifier());
239
        $label = new Label('identifier', 'website:contentListIdentifier');
240
        $help  = new Help('website:contentListIdentifierHelp');
241
242
        $this->form[] = new FormGroup($input, $label, $help);
243
244
        return $this;
245
    }
246
247
    /**
248
     * @param Entity $entity
249
     *
250
     * @return $this
251
     */
252
    protected function addProtected(Entity $entity): ContentList
253
    {
254
        // Protected can not be set by non-advanced users
255
        if (!$this->isAdvancedAllowed()) {
256
            return $this;
257
        }
258
259
        $attributes = [Html5::ATTR_TYPE => Input::TYPE_CHECKBOX];
260
        if ($entity->isProtected()) {
261
            $attributes[Html5::ATTR_CHECKED] = null;
262
        }
263
        $input = new Input(
264
            'protected',
265
            'protected',
266
            '1',
267
            [],
268
            $attributes
269
        );
270
        $label = new Label('protected', 'website:contentListProtected');
271
        $help  = new Help('website:contentListProtectedHelp');
272
273
        $this->form[] = new CheckboxGroup($input, $label, $help, [], [Html5::ATTR_ID => 'protected-container']);
274
275
        return $this;
276
    }
277
278
    /**
279
     * @param Entity $entity
280
     *
281
     * @return $this
282
     */
283
    protected function addWithImage(Entity $entity): ContentList
284
    {
285
        // With image setting of protected lists can only be modified by advanced users
286
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
287
            return $this;
288
        }
289
290
        $attributes = [Html5::ATTR_TYPE => Input::TYPE_CHECKBOX];
291
        if ($entity->isWithImage()) {
292
            $attributes[Html5::ATTR_CHECKED] = null;
293
        }
294
        $input = new Input(
295
            'with_image',
296
            'with_image',
297
            '1',
298
            [],
299
            $attributes
300
        );
301
        $label = new Label('with_image', 'website:contentListWithImage');
302
        $help  = new Help('website:contentListWithImageHelp');
303
304
        $this->form[] = new CheckboxGroup($input, $label, $help, [], [Html5::ATTR_ID => 'withImage-container']);
305
306
        return $this;
307
    }
308
309
    /**
310
     * @param Entity $entity
311
     *
312
     * @return $this
313
     */
314
    protected function addWithLinks(Entity $entity): ContentList
315
    {
316
        // With links setting of protected lists can only be modified by advanced users
317
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
318
            return $this;
319
        }
320
321
        $attributes = [Html5::ATTR_TYPE => Input::TYPE_CHECKBOX];
322
        if ($entity->isWithLinks()) {
323
            $attributes[Html5::ATTR_CHECKED] = null;
324
        }
325
        $input = new Input(
326
            'with_links',
327
            'with_links',
328
            '1',
329
            [],
330
            $attributes
331
        );
332
        $label = new Label('with_links', 'website:contentListWithLinks');
333
        $help  = new Help('website:contentListWithLinksHelp');
334
335
        $this->form[] = new CheckboxGroup($input, $label, $help, [], [Html5::ATTR_ID => 'withLinks-container']);
336
337
        return $this;
338
    }
339
340
    /**
341
     * @param Entity $entity
342
     *
343
     * @return $this
344
     */
345
    protected function addWithHtml(Entity $entity): ContentList
346
    {
347
        // With HTML setting of protected lists can only be modified by advanced users
348
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
349
            return $this;
350
        }
351
352
        $attributes = [Html5::ATTR_TYPE => Input::TYPE_CHECKBOX];
353
        if ($entity->isWithHtml()) {
354
            $attributes[Html5::ATTR_CHECKED] = null;
355
        }
356
        $input = new Input(
357
            'with_html',
358
            'with_html',
359
            '1',
360
            [],
361
            $attributes
362
        );
363
        $label = new Label('with_html', 'website:contentListWithHtml');
364
        $help  = new Help('website:contentListWithHtmlHelp');
365
366
        $this->form[] = new CheckboxGroup($input, $label, $help, [], [Html5::ATTR_ID => 'withHtml-container']);
367
368
        return $this;
369
    }
370
371
    /**
372
     * @param Entity $entity
373
     *
374
     * @return ContentList
375
     */
376
    protected function addExistingItems(Entity $entity): ContentList
377
    {
378
        // There's no reason to check existing items during creation
379
        if (!$entity->getId()) {
380
            return $this;
381
        }
382
383
        $containerAttribs = [Html5::ATTR_ID => static::EXISTING_ITEMS_CONTAINER_ID];
384
        $container        = new Component(null, [], $containerAttribs, Html5::TAG_SECTION);
385
386
        $itemFormFactory = new Item($entity->isProtected(), $entity->isWithImage(), $entity->isWithLinks());
387
388
        /** @var ContentListItem[] $items */
389
        $items = $this->itemRepo->getByListId($entity->getId());
390
        foreach ($items as $item) {
391
            $fieldset   = new Component(null, [], [], Html5::TAG_FIELDSET);
392
            $fieldset[] = new Tag($item->getName(), [], [], Html5::TAG_LEGEND);
393
            foreach ($itemFormFactory->create($item) as $node) {
394
                $fieldset[] = $node;
395
            }
396
            $container[] = $fieldset;
397
        }
398
399
        $this->form[] = $container;
400
401
        return $this;
402
    }
403
404
    /**
405
     * @param Entity $entity
406
     *
407
     * @return ContentList
408
     */
409
    protected function addNewItems(Entity $entity): ContentList
410
    {
411
        // New items can not be added during creation
412
        if (!$entity->getId()) {
413
            return $this;
414
        }
415
        // New items can only be added to protected lists by advanced users
416
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
417
            return $this;
418
        }
419
420
        $containerAttribs = [Html5::ATTR_ID => static::NEW_ITEMS_CONTAINER_ID];
421
        $container        = new Component(null, [], $containerAttribs, Html5::TAG_SECTION);
422
423
        $itemAttribs     = [Html5::ATTR_CLASS => static::ITEM_TEMPLATE_CLASS];
424
        $item            = new Component(null, [], $itemAttribs, Html5::TAG_FIELDSET);
425
        $item[]          = new Tag(static::NEW_ITEM_NAME, [], [], Html5::TAG_LEGEND);
426
        $itemFormFactory = new Item($entity->isProtected(), $entity->isWithImage(), $entity->isWithLinks());
427
        foreach ($itemFormFactory->create() as $component) {
428
            $item[] = $component;
429
        }
430
431
        $container[] = $item;
432
433
        $this->form[] = $container;
434
435
        return $this;
436
    }
437
438
    /**
439
     * @param Entity $entity
440
     *
441
     * @return ContentList
442
     */
443
    protected function addAddBtn(Entity $entity): ContentList
444
    {
445
        // New items can not be added during creation
446
        if (!$entity->getId()) {
447
            return $this;
448
        }
449
        // New items can only be added to protected lists by advanced users
450
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
451
            return $this;
452
        }
453
454
        $i   = new Component('add', [Component::INTENT_SMALL, Component::INTENT_ICON], [], Html5::TAG_I);
0 ignored issues
show
Bug introduced by
The constant AbterPhp\Framework\Html\Component::INTENT_SMALL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant AbterPhp\Framework\Html\Component::INTENT_ICON was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
455
        $btn = new Button($i, [Button::INTENT_FAB, Button::INTENT_PRIMARY], [Html5::ATTR_TYPE => Button::TYPE_BUTTON]);
0 ignored issues
show
Bug introduced by
The constant AbterPhp\Framework\Html\...nent\Button::INTENT_FAB was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
456
457
        $this->form[] = new Component($btn, [], [Html5::ATTR_ID => 'add-item-container'], Html5::TAG_DIV);
458
459
        return $this;
460
    }
461
462
    /**
463
     * @param string $showUrl
464
     *
465
     * @return Base
466
     */
467
    protected function addButtons(Entity $entity, string $showUrl): Base
468
    {
469
        if ($entity->getName()) {
470
            return parent::addDefaultButtons($showUrl);
471
        }
472
473
        return $this->addNewButtons($showUrl);
474
    }
475
476
    /**
477
     * @param string $showUrl
478
     *
479
     * @return Base
480
     */
481
    protected function addNewButtons(string $showUrl): Base
482
    {
483
        $buttons = new DefaultButtons();
484
485
        $buttons
486
            ->addSaveAndEdit(Button::INTENT_PRIMARY, Button::INTENT_FORM)
0 ignored issues
show
Unused Code introduced by
The call to AbterPhp\Framework\Form\...ttons::addSaveAndEdit() has too many arguments starting with AbterPhp\Framework\Html\...\Button::INTENT_PRIMARY. ( Ignorable by Annotation )

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

486
            ->/** @scrutinizer ignore-call */ 
487
              addSaveAndEdit(Button::INTENT_PRIMARY, Button::INTENT_FORM)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
487
            ->addBackToGrid($showUrl)
488
            ->addSaveAndBack(Button::INTENT_WARNING, Button::INTENT_FORM)
0 ignored issues
show
Unused Code introduced by
The call to AbterPhp\Framework\Form\...ttons::addSaveAndBack() has too many arguments starting with AbterPhp\Framework\Html\...\Button::INTENT_WARNING. ( Ignorable by Annotation )

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

488
            ->/** @scrutinizer ignore-call */ addSaveAndBack(Button::INTENT_WARNING, Button::INTENT_FORM)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
489
            ->addSaveAndCreate();
490
491
        $this->form[] = $buttons;
492
493
        return $this;
494
    }
495
}
496