Passed
Push — master ( 26f223...98f436 )
by Peter
03:08
created

ContentList::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 15
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 22
rs 9.7666
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\FormGroup;
12
use AbterPhp\Framework\Form\Container\Hideable;
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\Advanced as AdvancedFactory;
28
use AbterPhp\Website\Form\Factory\ContentList\Item as ItemFactory;
29
use AbterPhp\Website\Orm\ContentListItemRepo as ItemRepo;
30
use AbterPhp\Website\Orm\ContentListTypeRepo as TypeRepo;
31
use Casbin\Enforcer;
32
use Opulence\Orm\IEntity;
33
use Opulence\Sessions\ISession;
34
35
// @phan-suppress-current-line PhanUnreferencedUseNormal
36
37
class ContentList extends Base
38
{
39
    private const NEW_ITEM_NAME = 'website:contentListItemNew';
40
41
    private const ITEM_TEMPLATE_CLASS         = 'item-template';
42
    private const NEW_ITEMS_CONTAINER_ID      = 'new-items';
43
    private const EXISTING_ITEMS_CONTAINER_ID = 'existing-items';
44
45
    /** @var TypeRepo */
46
    protected $typeRepo;
47
48
    /** @var ItemRepo */
49
    protected $itemRepo;
50
51
    /** @var AdvancedFactory */
52
    protected $advancedFactory;
53
54
    /** @var ItemFactory */
55
    protected $itemFactory;
56
57
    /** @var Enforcer */
58
    protected $enforcer;
59
60
    /** @var bool */
61
    private $isNew = false;
62
63
    /** @var bool|null */
64
    protected $advancedAllowed;
65
66
    /**
67
     * ContentList constructor.
68
     *
69
     * @param ISession        $session
70
     * @param ITranslator     $translator
71
     * @param TypeRepo        $typeRepo
72
     * @param ItemRepo        $itemRepo
73
     * @param AdvancedFactory $advancedFactory
74
     * @param ItemFactory     $itemFactory
75
     * @param Enforcer        $enforcer
76
     */
77
    public function __construct(
78
        ISession $session,
79
        ITranslator $translator,
80
        TypeRepo $typeRepo,
81
        ItemRepo $itemRepo,
82
        AdvancedFactory $advancedFactory,
83
        ItemFactory $itemFactory,
84
        Enforcer $enforcer
85
    ) {
86
        parent::__construct($session, $translator);
87
88
        $this->typeRepo        = $typeRepo;
89
        $this->itemRepo        = $itemRepo;
90
        $this->advancedFactory = $advancedFactory;
91
        $this->itemFactory     = $itemFactory;
92
        $this->enforcer        = $enforcer;
93
    }
94
95
    /**
96
     * @return bool
97
     * @throws \Casbin\Exceptions\CasbinException
98
     */
99
    protected function isAdvancedAllowed(): bool
100
    {
101
        if ($this->advancedAllowed !== null) {
102
            return $this->advancedAllowed;
103
        }
104
105
        $username              = $this->session->get(Session::USERNAME);
106
        $this->advancedAllowed = $this->enforcer->enforce(
107
            $username,
108
            Authorization::RESOURCE_LISTS,
109
            Authorization::ROLE_ADVANCED_WRITE
110
        );
111
112
        return $this->advancedAllowed;
113
    }
114
115
    /**
116
     * @param string       $action
117
     * @param string       $method
118
     * @param string       $showUrl
119
     * @param IEntity|null $entity
120
     *
121
     * @return IForm
122
     * @throws \Casbin\Exceptions\CasbinException
123
     */
124
    public function create(string $action, string $method, string $showUrl, ?IEntity $entity = null): IForm
125
    {
126
        assert($entity instanceof Entity, new \InvalidArgumentException());
127
128
        $this->isNew = ($entity->getName() == '');
129
130
        $this->createForm($action, $method)
131
            ->addDefaultElements()
132
            ->addTypeId($entity)
133
            ->addName($entity)
134
            ->addIdentifier($entity)
135
            ->addAdvanced($entity)
136
            ->addExistingItems($entity)
137
            ->addNewItems($entity)
138
            ->addAddBtn($entity)
139
            ->addButtons($entity, $showUrl);
140
141
        $form = $this->form;
142
143
        $this->form = null;
144
145
        return $form;
146
    }
147
148
    /**
149
     * @param Entity $entity
150
     *
151
     * @return $this
152
     */
153
    protected function addTypeId(Entity $entity): ContentList
154
    {
155
        // Type of protected lists can only be set by advanced users
156
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
157
            return $this;
158
        }
159
160
        $allTypes = $this->getAllTypes();
161
        $typeId   = $entity->getTypeId();
162
163
        $options = $this->createTypeIdOptions($allTypes, $typeId);
164
165
        $this->form[] = new FormGroup(
166
            $this->createTypeIdSelect($options),
167
            $this->createTypeIdLabel()
168
        );
169
170
        return $this;
171
    }
172
173
    /**
174
     * @return ContentListType[]
175
     */
176
    protected function getAllTypes(): array
177
    {
178
        return $this->typeRepo->getAll();
179
    }
180
181
    /**
182
     * @param ContentListType[] $allTypes
183
     * @param string            $typeId
184
     *
185
     * @return Option[]
186
     */
187
    protected function createTypeIdOptions(array $allTypes, string $typeId): array
188
    {
189
        $options   = [];
190
        $options[] = new Option('', 'framework:none', false);
191
        foreach ($allTypes as $layout) {
192
            $isSelected = $layout->getId() === $typeId;
193
            $options[]  = new Option($layout->getId(), $layout->getLabel(), $isSelected);
194
        }
195
196
        return $options;
197
    }
198
199
    /**
200
     * @param Option[] $options
201
     *
202
     * @return Select
203
     */
204
    protected function createTypeIdSelect(array $options): Select
205
    {
206
        $select = new Select('type_id', 'type_id');
207
208
        foreach ($options as $option) {
209
            $select[] = $option;
210
        }
211
212
        return $select;
213
    }
214
215
    /**
216
     * @return Label
217
     */
218
    protected function createTypeIdLabel(): Label
219
    {
220
        return new Label('type_id', 'website:contentListTypeIdLabel');
221
    }
222
223
    /**
224
     * @param Entity $entity
225
     *
226
     * @return $this
227
     */
228
    protected function addName(Entity $entity): ContentList
229
    {
230
        $input = new Input('name', 'name', $entity->getName());
231
        $label = new Label('name', 'website:contentListName');
232
233
        $this->form[] = new FormGroup($input, $label);
234
235
        return $this;
236
    }
237
238
    /**
239
     * @param Entity $entity
240
     *
241
     * @return $this
242
     */
243
    protected function addIdentifier(Entity $entity): ContentList
244
    {
245
        // Identifier of protected lists can only be set by advanced users
246
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
247
            return $this;
248
        }
249
250
        $input = new Input('identifier', 'identifier', $entity->getIdentifier());
251
        $label = new Label('identifier', 'website:contentListIdentifier');
252
        $help  = new Help('website:contentListIdentifierHelp');
253
254
        $this->form[] = new FormGroup($input, $label, $help);
255
256
        return $this;
257
    }
258
259
    /**
260
     * @param Entity $entity
261
     *
262
     * @return $this
263
     */
264
    protected function addAdvanced(Entity $entity): ContentList
265
    {
266
        // Protected can not be set by non-advanced users
267
        if (!$this->isAdvancedAllowed() && $entity->getId()) {
268
            return $this;
269
        }
270
271
        $hideable   = new Hideable($this->translator->translate('website:contentListAdvanced'));
272
        $components = $this->advancedFactory->create($entity);
273
        foreach ($components as $component) {
274
            $hideable[] = $component;
275
        }
276
277
        $this->form[] = $hideable;
278
279
        return $this;
280
    }
281
282
    /**
283
     * @param Entity $entity
284
     *
285
     * @return ContentList
286
     */
287
    protected function addExistingItems(Entity $entity): ContentList
288
    {
289
        // There's no reason to check existing items during creation
290
        if (!$entity->getId()) {
291
            return $this;
292
        }
293
294
        $isWithLinks = $entity->isWithLinks();
295
        $isWithImage = $entity->isWithImage();
296
        $isWithHtml  = $entity->isWithHtml();
297
298
        $containerAttribs = [Html5::ATTR_ID => static::EXISTING_ITEMS_CONTAINER_ID];
299
        $container        = new Component(null, [], $containerAttribs, Html5::TAG_SECTION);
300
301
        /** @var ContentListItem[] $items */
302
        $items = $this->itemRepo->getByListId($entity->getId());
303
        foreach ($items as $item) {
304
            $fieldset   = new Component(null, [], [], Html5::TAG_FIELDSET);
305
            $fieldset[] = new Tag($item->getName(), [], [], Html5::TAG_LEGEND);
306
307
            $components = $this->itemFactory->create($item, $isWithLinks, $isWithImage, $isWithHtml);
308
            foreach ($components as $component) {
309
                $fieldset[] = $component;
310
            }
311
            $container[] = $fieldset;
312
        }
313
314
        $this->form[] = $container;
315
316
        return $this;
317
    }
318
319
    /**
320
     * @param Entity $entity
321
     *
322
     * @return ContentList
323
     */
324
    protected function addNewItems(Entity $entity): ContentList
325
    {
326
        // New items can not be added during creation
327
        if (!$entity->getId()) {
328
            return $this;
329
        }
330
        // New items can only be added to protected lists by advanced users
331
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
332
            return $this;
333
        }
334
335
        $isWithLinks = $entity->isWithLinks();
336
        $isWithImage = $entity->isWithImage();
337
        $isWithHtml  = $entity->isWithHtml();
338
339
        $containerAttribs = [Html5::ATTR_ID => static::NEW_ITEMS_CONTAINER_ID];
340
        $container        = new Component(null, [], $containerAttribs, Html5::TAG_SECTION);
341
342
        $itemAttribs = [Html5::ATTR_CLASS => static::ITEM_TEMPLATE_CLASS];
343
        $item        = new Component(null, [], $itemAttribs, Html5::TAG_FIELDSET);
344
        $item[]      = new Tag(static::NEW_ITEM_NAME, [], [], Html5::TAG_LEGEND);
345
346
        $components = $this->itemFactory->create(null, $isWithLinks, $isWithImage, $isWithHtml);
347
        foreach ($components as $component) {
348
            $item[] = $component;
349
        }
350
351
        $container[] = $item;
352
353
        $this->form[] = $container;
354
355
        return $this;
356
    }
357
358
    /**
359
     * @param Entity $entity
360
     *
361
     * @return ContentList
362
     */
363
    protected function addAddBtn(Entity $entity): ContentList
364
    {
365
        // New items can not be added during creation
366
        if (!$entity->getId()) {
367
            return $this;
368
        }
369
        // New items can only be added to protected lists by advanced users
370
        if ($entity->isProtected() && !$this->isAdvancedAllowed()) {
371
            return $this;
372
        }
373
374
        $i   = new Component('add', [Component::INTENT_SMALL, Component::INTENT_ICON], [], Html5::TAG_I);
375
        $btn = new Button($i, [Button::INTENT_FAB, Button::INTENT_PRIMARY], [Html5::ATTR_TYPE => Button::TYPE_BUTTON]);
376
377
        $this->form[] = new Component($btn, [], [Html5::ATTR_ID => 'add-item-container'], Html5::TAG_DIV);
378
379
        return $this;
380
    }
381
382
    /**
383
     * @param string $showUrl
384
     *
385
     * @return Base
386
     */
387
    protected function addButtons(Entity $entity, string $showUrl): Base
388
    {
389
        if ($entity->getName()) {
390
            return parent::addDefaultButtons($showUrl);
391
        }
392
393
        return $this->addNewButtons($showUrl);
394
    }
395
396
    /**
397
     * @param string $showUrl
398
     *
399
     * @return Base
400
     */
401
    protected function addNewButtons(string $showUrl): Base
402
    {
403
        $buttons = new DefaultButtons();
404
405
        $buttons
406
            ->addSaveAndEdit(Button::INTENT_PRIMARY, Button::INTENT_FORM)
407
            ->addBackToGrid($showUrl)
408
            ->addSaveAndBack(Button::INTENT_WARNING, Button::INTENT_FORM)
409
            ->addSaveAndCreate();
410
411
        $this->form[] = $buttons;
412
413
        return $this;
414
    }
415
}
416