FormSidebarWidget::parseAsSidebarActions()   F
last analyzed

Complexity

Conditions 21
Paths 484

Size

Total Lines 55
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 34
nc 484
nop 1
dl 0
loc 55
rs 0.7166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Charcoal\Admin\Widget;
4
5
use Charcoal\Object\RevisionableInterface;
6
use InvalidArgumentException;
7
8
// From Pimple
9
use Pimple\Container;
10
11
// From 'charcoal-ui'
12
use Charcoal\Ui\Form\FormInterface;
13
14
// From 'charcoal-translator'
15
use Charcoal\Translator\Translation;
16
17
// From 'charcoal-admin'
18
use Charcoal\Admin\AdminWidget;
19
use Charcoal\Admin\Ui\ActionContainerTrait;
20
use Charcoal\Admin\Ui\FormSidebarInterface;
21
22
/**
23
 * Form Sidebar Widget
24
 */
25
class FormSidebarWidget extends AdminWidget implements
26
    FormSidebarInterface
27
{
28
    use ActionContainerTrait;
0 ignored issues
show
Bug introduced by
The trait Charcoal\Admin\Ui\ActionContainerTrait requires the property $currentObj which is not provided by Charcoal\Admin\Widget\FormSidebarWidget.
Loading history...
29
30
    /**
31
     * Default sorting priority for an action.
32
     *
33
     * @const integer
34
     */
35
    const DEFAULT_ACTION_PRIORITY = 10;
36
37
    /**
38
     * Store a reference to the parent form widget.
39
     *
40
     * @var FormInterface
41
     */
42
    private $form;
43
44
    /**
45
     * Store the sidebar actions.
46
     *
47
     * @var array|null
48
     */
49
    protected $sidebarActions;
50
51
    /**
52
     * Store the default list actions.
53
     *
54
     * @var array|null
55
     */
56
    protected $defaultSidebarActions;
57
58
    /**
59
     * Keep track if sidebar actions are finalized.
60
     *
61
     * @var boolean
62
     */
63
    protected $parsedSidebarActions = false;
64
65
    /**
66
     * The properties to show.
67
     *
68
     * @var array
69
     */
70
    protected $sidebarProperties = [];
71
72
    /**
73
     * Customize the shown properties.
74
     *
75
     * @var array
76
     */
77
    private $propertiesOptions = [];
78
79
    /**
80
     * The title is displayed by default.
81
     *
82
     * @var boolean
83
     */
84
    private $showTitle = true;
85
86
    /**
87
     * The sidebar's title.
88
     *
89
     * @var Translation|string|null
90
     */
91
    protected $title;
92
93
    /**
94
     * The subtitle is displayed by default.
95
     *
96
     * @var boolean
97
     */
98
    private $showSubtitle = true;
99
100
    /**
101
     * The sidebar's subtitle.
102
     *
103
     * @var Translation|string|null
104
     */
105
    private $subtitle;
106
107
    /**
108
     * The footer is displayed by default.
109
     *
110
     * @var boolean
111
     */
112
    protected $showFooter = true;
113
114
    /**
115
     * Whether the object is viewable.
116
     *
117
     * @var boolean
118
     */
119
    private $isObjViewable;
120
121
    /**
122
     * Whether the object is savable.
123
     *
124
     * @var boolean
125
     */
126
    private $isObjSavable;
127
128
    /**
129
     * Whether the object is resettable.
130
     *
131
     * @var boolean
132
     */
133
    private $isObjResettable;
134
135
    /**
136
     * Whether the object is deletable.
137
     *
138
     * @var boolean
139
     */
140
    private $isObjDeletable;
141
142
    /**
143
     * Whether the object is revisionable.
144
     *
145
     * @var boolean
146
     */
147
    private $isObjRevisionable;
148
149
    /**
150
     * The required Acl permissions for the whole sidebar.
151
     *
152
     * @var string[]
153
     */
154
    private $requiredGlobalAclPermissions = [];
155
156
    /**
157
     * @param array|ArrayInterface $data Class data.
0 ignored issues
show
Bug introduced by
The type Charcoal\Admin\Widget\ArrayInterface 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...
158
     * @return FormSidebarWidget Chainable
159
     */
160
    public function setData(array $data)
161
    {
162
        parent::setData($data);
163
164
        if (isset($data['properties'])) {
165
            $this->setSidebarProperties($data['properties']);
166
        }
167
168
        if (isset($data['actions'])) {
169
            $this->setSidebarActions($data['actions']);
170
        }
171
172
        if (isset($data['permissions'])) {
173
            $permissions = $data['permissions'];
174
            unset($data['permissions']);
175
            $isAssoc = $this->isAssoc($permissions);
176
            if ($isAssoc) {
177
                $this->setRequiredAclPermissions($permissions);
178
            } else {
179
                $this->setRequiredGlobalAclPermissions($permissions);
180
            }
181
        }
182
183
        return $this;
184
    }
185
186
    /**
187
     * Set the form widget the sidebar belongs to.
188
     *
189
     * @param FormInterface $form The related form widget.
190
     * @return FormSidebarWidget Chainable
191
     */
192
    public function setForm(FormInterface $form)
193
    {
194
        $this->form = $form;
195
196
        return $this;
197
    }
198
199
    /**
200
     * Retrieve the form widget the sidebar belongs to.
201
     *
202
     * @return FormInterface
203
     */
204
    public function form()
205
    {
206
        return $this->form;
207
    }
208
209
    /**
210
     * Set the form's object properties to show in the sidebar.
211
     *
212
     * @param  array $properties The form's object properties.
213
     * @return FormSidebarWidget Chainable
214
     */
215
    public function setSidebarProperties(array $properties)
216
    {
217
        $this->sidebarProperties = $properties;
218
219
        return $this;
220
    }
221
222
    /**
223
     * Retrieve the form's object properties to show in the sidebar.
224
     *
225
     * @return mixed
226
     */
227
    public function sidebarProperties()
228
    {
229
        return $this->sidebarProperties;
230
    }
231
232
    /**
233
     * Determine if the sidebar has any object properties.
234
     *
235
     * @return boolean
236
     */
237
    public function hasSidebarProperties()
238
    {
239
        return ($this->numSidebarProperties() > 0);
240
    }
241
242
    /**
243
     * Count the number of object properties in the sidebar.
244
     *
245
     * @return integer
246
     */
247
    public function numSidebarProperties()
248
    {
249
        return count($this->sidebarProperties());
250
    }
251
252
    /**
253
     * Set the map of object property customizations.
254
     *
255
     * @param  array $properties The options to customize the group properties.
256
     * @return FormSidebarWidget Chainable
257
     */
258
    public function setPropertiesOptions(array $properties)
259
    {
260
        $this->propertiesOptions = $properties;
261
262
        return $this;
263
    }
264
265
    /**
266
     * Retrieve the map of object property customizations.
267
     *
268
     * @return array
269
     */
270
    public function propertiesOptions()
271
    {
272
        return $this->propertiesOptions;
273
    }
274
275
    /**
276
     * Retrieve the object's properties from the form.
277
     *
278
     * @return mixed|Generator
0 ignored issues
show
Bug introduced by
The type Charcoal\Admin\Widget\Generator was not found. Did you mean Generator? If so, make sure to prefix the type with \.
Loading history...
279
     */
280
    public function formProperties()
281
    {
282
        $form = $this->form();
283
        $obj  = $form->obj();
0 ignored issues
show
Bug introduced by
The method obj() does not exist on Charcoal\Ui\Form\FormInterface. It seems like you code against a sub-type of Charcoal\Ui\Form\FormInterface such as Charcoal\Admin\Widget\ObjectFormWidget or Charcoal\Admin\Widget\DocWidget. ( Ignorable by Annotation )

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

283
        /** @scrutinizer ignore-call */ 
284
        $obj  = $form->obj();
Loading history...
284
285
        $availableProperties = $obj->properties();
0 ignored issues
show
Unused Code introduced by
The assignment to $availableProperties is dead and can be removed.
Loading history...
286
        $sidebarProperties   = $this->sidebarProperties();
287
        $propertiesOptions   = $this->propertiesOptions();
288
289
        foreach ($sidebarProperties as $propertyIdent) {
290
            if (!$obj->hasProperty($propertyIdent)) {
291
                continue;
292
            }
293
294
            $property = $obj->property($propertyIdent);
295
            $value    = $obj->propertyValue($propertyIdent);
0 ignored issues
show
Unused Code introduced by
The assignment to $value is dead and can be removed.
Loading history...
296
297
            $formProperty = $form->createFormProperty();
0 ignored issues
show
Bug introduced by
The method createFormProperty() does not exist on Charcoal\Ui\Form\FormInterface. It seems like you code against a sub-type of Charcoal\Ui\Form\FormInterface such as Charcoal\Admin\Widget\FormWidget. ( Ignorable by Annotation )

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

297
            /** @scrutinizer ignore-call */ 
298
            $formProperty = $form->createFormProperty();
Loading history...
298
            $formProperty->setOutputType($formProperty::PROPERTY_DISPLAY);
299
            $formProperty->setShowNotes(false);
300
            $formProperty->setViewController($form->viewController());
301
302
            $formProperty->setProperty($property);
303
            $formProperty->setPropertyIdent($property->ident());
304
            $formProperty->setPropertyVal($obj[$propertyIdent]);
305
306
            if (!empty($propertiesOptions[$propertyIdent])) {
307
                $propertyOptions = $propertiesOptions[$propertyIdent];
308
309
                if (is_array($propertyOptions)) {
310
                    $formProperty->setData($propertyOptions);
311
                }
312
            }
313
314
            yield $propertyIdent => $formProperty;
315
        }
316
    }
317
318
    /**
319
     * Determine if the sidebar's actions should be shown.
320
     *
321
     * @return boolean
322
     */
323
    public function showSidebarActions()
324
    {
325
        $actions = $this->sidebarActions();
326
327
        return count($actions);
0 ignored issues
show
Bug Best Practice introduced by
The expression return count($actions) returns the type integer which is incompatible with the documented return type boolean.
Loading history...
328
    }
329
330
    /**
331
     * Retrieve the sidebar's actions.
332
     *
333
     * @return array
334
     */
335
    public function sidebarActions()
336
    {
337
        if ($this->sidebarActions === null) {
338
            $this->setSidebarActions([]);
339
        }
340
341
        if ($this->parsedSidebarActions === false) {
342
            $this->parsedSidebarActions = true;
343
            $this->sidebarActions = $this->createSidebarActions($this->sidebarActions);
344
        }
345
346
        return $this->sidebarActions;
347
    }
348
349
    /**
350
     * Set the sidebar's actions.
351
     *
352
     * @param  array $actions One or more actions.
353
     * @return FormSidebarWidget Chainable.
354
     */
355
    protected function setSidebarActions(array $actions)
356
    {
357
        $this->parsedSidebarActions = false;
358
359
        $this->sidebarActions = $this->mergeActions($this->defaultSidebarActions(), $actions);
360
361
        return $this;
362
    }
363
364
    /**
365
     * Build the sidebar's actions.
366
     *
367
     * Sidebar actions should come from the form settings defined by the "sidebars".
368
     * It is still possible to completly override those externally by setting the "actions"
369
     * with the {@see self::setSidebarActions()} method.
370
     *
371
     * @param  array $actions Actions to resolve.
372
     * @return array Sidebar actions.
373
     */
374
    protected function createSidebarActions(array $actions)
375
    {
376
        $this->actionsPriority = $this->defaultActionPriority();
377
378
        $sidebarActions = $this->parseAsSidebarActions($actions);
379
380
        return $sidebarActions;
381
    }
382
383
    /**
384
     * Parse the given actions as object actions.
385
     *
386
     * @param  array $actions Actions to resolve.
387
     * @return array
388
     */
389
    protected function parseAsSidebarActions(array $actions)
390
    {
391
        $sidebarActions = [];
392
        foreach ($actions as $ident => $action) {
393
            $ident  = $this->parseActionIdent($ident, $action);
394
            $action = $this->parseActionItem($action, $ident, true);
395
396
            if (!isset($action['priority'])) {
397
                $action['priority'] = $this->actionsPriority++;
398
            }
399
400
            if ($action['ident'] === 'view' && !$this->isObjViewable()) {
401
                $action['active'] = false;
402
            } elseif ($action['ident'] === 'save' && !$this->isObjSavable()) {
403
                $action['active'] = false;
404
            } elseif ($action['ident'] === 'reset' && !$this->isObjResettable()) {
405
                $action['active'] = false;
406
            } elseif ($action['ident'] === 'delete' && !$this->isObjDeletable()) {
407
                $action['active'] = false;
408
            }
409
410
            if ($action['isSubmittable'] && !$this->isObjSavable()) {
411
                $action['active'] = false;
412
            }
413
414
            if ($action['actions']) {
415
                $action['actions']    = $this->parseAsSidebarActions($action['actions']);
416
                $action['hasActions'] = !!array_filter($action['actions'], function ($action) {
417
                    return $action['active'];
418
                });
419
            }
420
421
            if (isset($sidebarActions[$ident])) {
422
                $hasPriority = ($action['priority'] > $sidebarActions[$ident]['priority']);
423
                if ($hasPriority || $action['isSubmittable']) {
424
                    $sidebarActions[$ident] = array_replace($sidebarActions[$ident], $action);
425
                } else {
426
                    $sidebarActions[$ident] = array_replace($action, $sidebarActions[$ident]);
427
                }
428
            } else {
429
                $sidebarActions[$ident] = $action;
430
            }
431
        }
432
433
        usort($sidebarActions, [ $this, 'sortActionsByPriority' ]);
434
435
        while (($first = reset($sidebarActions)) && $first['isSeparator']) {
436
            array_shift($sidebarActions);
437
        }
438
439
        while (($last = end($sidebarActions)) && $last['isSeparator']) {
440
            array_pop($sidebarActions);
441
        }
442
443
        return $sidebarActions;
444
    }
445
446
    /**
447
     * Retrieve the sidebar's default actions.
448
     *
449
     * @return array
450
     */
451
    protected function defaultSidebarActions()
452
    {
453
        if ($this->defaultSidebarActions === null) {
454
            $this->defaultSidebarActions = [];
455
456
            if ($this->form()) {
457
                $save = [
458
                    'label'      => $this->form()->submitLabel(),
0 ignored issues
show
Bug introduced by
The method submitLabel() does not exist on Charcoal\Ui\Form\FormInterface. It seems like you code against a sub-type of Charcoal\Ui\Form\FormInterface such as Charcoal\Admin\Widget\FormWidget. ( Ignorable by Annotation )

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

458
                    'label'      => $this->form()->/** @scrutinizer ignore-call */ submitLabel(),
Loading history...
459
                    'ident'      => 'save',
460
                    'buttonType' => 'submit',
461
                    'priority'   => 90
462
                ];
463
                $this->defaultSidebarActions[] = $save;
464
            }
465
        }
466
467
        return $this->defaultSidebarActions;
468
    }
469
470
    /**
471
     * @return string
472
     */
473
    public function jsActionPrefix()
474
    {
475
        return 'js-sidebar';
476
    }
477
478
    /**
479
     * Determine if the object can be deleted.
480
     *
481
     * If TRUE, the "Delete" button is shown. The object can still be
482
     * deleted programmatically or via direct action on the database.
483
     *
484
     * @return boolean
485
     */
486
    public function isObjDeletable()
487
    {
488
        if ($this->isObjDeletable === null) {
489
            // Overridden by permissions
490
            if (!$this->checkPermission('delete') || !$this->form()) {
491
                $this->isObjDeletable = false;
492
            } else {
493
                $obj = $this->form()->obj();
494
                $this->isObjDeletable = !!$obj->id();
495
496
                $method = [ $obj, 'isDeletable' ];
497
                if (is_callable($method)) {
498
                    $this->isObjDeletable = call_user_func($method);
499
                }
500
            }
501
        }
502
503
        return $this->isObjDeletable;
504
    }
505
506
    /**
507
     * Determine if the object has revisions.
508
     *
509
     * If TRUE, the "Delete" button is shown. The object can still be
510
     * deleted programmatically or via direct action on the database.
511
     *
512
     * @return boolean
513
     */
514
    public function isObjRevisionable()
515
    {
516
        if ($this->isObjRevisionable === null) {
517
            // Overridden by permissions
518
            if (!$this->checkPermission('revision') || !$this->form()) {
519
                $this->isObjRevisionable = false;
520
            } else {
521
                $obj = $this->form()->obj();
522
                if (!$obj->id()) {
523
                    $this->isObjRevisionable = false;
524
                    return $this->isObjRevisionable;
525
                }
526
527
                if ($obj instanceof RevisionableInterface && $obj->revisionEnabled()) {
528
                    $this->isObjRevisionable = !!count($obj->allRevisions());
529
                }
530
            }
531
        }
532
533
        return $this->isObjRevisionable;
534
    }
535
536
    /**
537
     * Determine if the object can be reset.
538
     *
539
     * If TRUE, the "Reset" button is shown. The object can still be
540
     * reset to its default values programmatically or emptied via direct
541
     * action on the database.
542
     *
543
     * @return boolean
544
     */
545
    public function isObjResettable()
546
    {
547
        if ($this->isObjResettable === null) {
548
            // Overridden by permissions
549
            if (!$this->checkPermission('reset') || !$this->form()) {
550
                $this->isObjResettable = false;
551
            } else {
552
                $this->isObjResettable = true;
553
554
                $obj    = $this->form()->obj();
555
                $method = [ $obj, 'isResettable' ];
556
                if (is_callable($method)) {
557
                    $this->isObjResettable = call_user_func($method);
558
                }
559
            }
560
        }
561
562
        return $this->isObjResettable;
563
    }
564
565
    /**
566
     * Determine if the object can be saved.
567
     *
568
     * If TRUE, the "Save" button is shown. The object can still be
569
     * saved programmatically.
570
     *
571
     * @return boolean
572
     */
573
    public function isObjSavable()
574
    {
575
        if ($this->isObjSavable === null) {
576
            // Overridden by permissions
577
            if (!$this->checkPermission('save') || !$this->form()) {
578
                $this->isObjSavable = false;
579
            } else {
580
                $this->isObjSavable = true;
581
582
                $obj    = $this->form()->obj();
583
                $method = [ $obj, 'isSavable' ];
584
                if (is_callable($method)) {
585
                    $this->isObjSavable = call_user_func($method);
586
                }
587
            }
588
        }
589
590
        return $this->isObjSavable;
591
    }
592
593
    /**
594
     * Determine if the object can be viewed (on the front-end).
595
     *
596
     * If TRUE, any "View" button is shown. The object can still be
597
     * saved programmatically.
598
     *
599
     * @return boolean
600
     */
601
    public function isObjViewable()
602
    {
603
        if ($this->isObjViewable === null) {
604
            // Overridden by permissions
605
            if (!$this->checkPermission('view') || !$this->form()) {
606
                $this->isObjViewable = false;
607
            } else {
608
                $obj = $this->form()->obj();
609
                $this->isObjViewable = !!$obj->id();
610
611
                $method = [ $obj, 'isViewable' ];
612
                if (is_callable($method)) {
613
                    $this->isObjViewable = call_user_func($method);
614
                }
615
            }
616
        }
617
618
        return $this->isObjViewable;
619
    }
620
621
    /**
622
     * Show/hide the widget's title.
623
     *
624
     * @param boolean $show Show (TRUE) or hide (FALSE) the title.
625
     * @return UiItemInterface Chainable
0 ignored issues
show
Bug introduced by
The type Charcoal\Admin\Widget\UiItemInterface 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...
626
     */
627
    public function setShowTitle($show)
628
    {
629
        $this->showTitle = !!$show;
630
631
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Charcoal\Admin\Widget\FormSidebarWidget which is incompatible with the documented return type Charcoal\Admin\Widget\UiItemInterface.
Loading history...
632
    }
633
634
    /**
635
     * Determine if the title is to be displayed.
636
     *
637
     * @return boolean If TRUE or unset, check if there is a title.
638
     */
639
    public function showTitle()
640
    {
641
        if ($this->showTitle === false) {
642
            return false;
643
        } else {
644
            return !!$this->title();
645
        }
646
    }
647
648
    /**
649
     * @param mixed $title The sidebar title.
650
     * @return FormSidebarWidget Chainable
651
     */
652
    public function setTitle($title)
653
    {
654
        $this->title = $this->translator()->translation($title);
655
656
        return $this;
657
    }
658
659
    /**
660
     * @return Translation|string|null
661
     */
662
    public function title()
663
    {
664
        if ($this->title === null) {
665
            $this->setTitle($this->translator()->translation('Actions'));
666
        }
667
668
        return $this->title;
669
    }
670
671
    /**
672
     * @param boolean $show The show subtitle flag.
673
     * @return FormSidebarWidget Chainable
674
     */
675
    public function setShowSubtitle($show)
676
    {
677
        $this->showSubtitle = !!$show;
678
        return $this;
679
    }
680
681
    /**
682
     * @return boolean
683
     */
684
    public function showSubtitle()
685
    {
686
        if ($this->showSubtitle === false) {
687
            return false;
688
        } else {
689
            return !!$this->subtitle();
690
        }
691
    }
692
693
    /**
694
     * @param mixed $subtitle The sidebar widget subtitle.
695
     * @return FormSidebarWidget Chainable
696
     */
697
    public function setSubtitle($subtitle)
698
    {
699
        $this->subtitle = $this->translator()->translation($subtitle);
700
701
        return $this;
702
    }
703
704
    /**
705
     * @return Translation|string|null
706
     */
707
    public function subtitle()
708
    {
709
        return $this->subtitle;
710
    }
711
712
    /**
713
     * Determine if the sidebar's footer is visible.
714
     *
715
     * @return boolean
716
     */
717
    public function showFooter()
718
    {
719
        // Overridden by permissions
720
        if (!$this->checkPermission('footer')) {
721
            return false;
722
        }
723
724
        // Overridden by conditionals
725
        if (!$this->isObjDeletable() && !$this->isObjResettable() &&!$this->isObjRevisionable()) {
726
            return false;
727
        }
728
729
        return $this->showFooter;
730
    }
731
732
    /**
733
     * Enable / Disable the sidebar's footer.
734
     *
735
     * @param  mixed $show The show footer flag.
736
     * @return FormSidebarWidget
737
     */
738
    public function setShowFooter($show)
739
    {
740
        $this->showFooter = !!$show;
741
742
        return $this;
743
    }
744
745
    /**
746
     * Determine if wrapper containing the subtitle and properties should be displayed.
747
     *
748
     * @return boolean
749
     */
750
    public function showPropertiesWrapper()
751
    {
752
        return $this->showSubtitle() || $this->hasSidebarProperties();
753
    }
754
755
    /**
756
     * Determine if wrapper containing the language switcher and actions should be displayed.
757
     *
758
     * @return boolean
759
     */
760
    public function showActionsWrapper()
761
    {
762
        return $this->showLanguageSwitch() || $this->showSidebarActions();
763
    }
764
765
    /**
766
     * @see    FormPropertyWidget::showActiveLanguage()
767
     * @return boolean
768
     */
769
    public function showLanguageSwitch()
770
    {
771
        if ($this->form()) {
772
            $locales = count($this->translator()->availableLocales());
773
            if ($locales > 1) {
774
                foreach ($this->form()->formProperties() as $formProp) {
0 ignored issues
show
Bug introduced by
The method formProperties() does not exist on Charcoal\Ui\Form\FormInterface. It seems like you code against a sub-type of Charcoal\Ui\Form\FormInterface such as Charcoal\Admin\Widget\FormWidget. ( Ignorable by Annotation )

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

774
                foreach ($this->form()->/** @scrutinizer ignore-call */ formProperties() as $formProp) {
Loading history...
775
                    if ($formProp->property()->l10n()) {
776
                        return true;
777
                    }
778
                }
779
            }
780
        }
781
782
        return false;
783
    }
784
785
    /**
786
     * Retrieve the available languages, formatted for the sidebar language-switcher.
787
     *
788
     * @see    FormGroupWidget::languages()
789
     * @return array
790
     */
791
    public function languages()
792
    {
793
        $currentLocale = $this->translator()->getLocale();
794
        $locales = $this->translator()->locales();
795
        $languages = [];
796
797
        uasort($locales, [ $this, 'sortLanguagesByPriority' ]);
798
799
        foreach ($locales as $locale => $localeStruct) {
800
            /**
801
             * @see \Charcoal\Admin\Widget\FormGroupWidget::languages()
802
             * @see \Charcoal\Property\LangProperty::localeChoices()
803
             */
804
            if (isset($localeStruct['name'])) {
805
                $label = $this->translator()->translation($localeStruct['name']);
806
            } else {
807
                $trans = 'locale.'.$locale;
808
                if ($trans === $this->translator()->translate($trans)) {
809
                    $label = strtoupper($locale);
810
                } else {
811
                    $label = $this->translator()->translation($trans);
812
                }
813
            }
814
815
            $isCurrent = ($locale === $currentLocale);
816
            $languages[] = [
817
                'cssClasses' => ($isCurrent) ? 'btn-primary' : 'btn-outline-primary',
818
                'ident'      => $locale,
819
                'name'       => $label,
820
                'current'    => $isCurrent
821
            ];
822
        }
823
824
        return $languages;
825
    }
826
827
    /**
828
     * To be called with {@see uasort()}.
829
     *
830
     * @param  array $a Sortable action A.
831
     * @param  array $b Sortable action B.
832
     * @return integer
833
     */
834
    protected function sortLanguagesByPriority(array $a, array $b)
835
    {
836
        $a = isset($a['priority']) ? $a['priority'] : 0;
837
        $b = isset($b['priority']) ? $b['priority'] : 0;
838
839
        if ($a === $b) {
840
            return 0;
841
        }
842
        return ($a < $b) ? (-1) : 1;
843
    }
844
845
    /**
846
     * Parse the widget's conditional logic.
847
     *
848
     * @see    AdminWidget::resolveConditionalLogic()
849
     * @param  callable|string $condition The callable or renderable condition.
850
     * @return boolean
851
     */
852
    protected function resolveConditionalLogic($condition)
853
    {
854
        $renderer = $this->getActionRenderer();
855
        if ($renderer && is_callable([ $renderer, $condition ])) {
856
            return !!$renderer->{$condition}();
857
        } elseif (is_callable([ $this, $condition ])) {
858
            return !!$this->{$condition}();
859
        } elseif (is_callable($condition)) {
860
            return !!$condition();
861
        } elseif ($renderer) {
862
            return !!$renderer->renderTemplate($condition);
0 ignored issues
show
Bug introduced by
It seems like $condition can also be of type callable; however, parameter $templateString of Charcoal\View\ViewableInterface::renderTemplate() 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

862
            return !!$renderer->renderTemplate(/** @scrutinizer ignore-type */ $condition);
Loading history...
863
        } elseif ($this->view()) {
864
            return !!$this->renderTemplate($condition);
0 ignored issues
show
Bug introduced by
It seems like $condition can also be of type callable; however, parameter $templateString of Charcoal\App\Template\Ab...idget::renderTemplate() 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

864
            return !!$this->renderTemplate(/** @scrutinizer ignore-type */ $condition);
Loading history...
865
        }
866
867
        return !!$condition;
868
    }
869
870
871
872
    // ACL Permissions
873
    // =========================================================================
874
875
    /**
876
     * Return true if the user as required permissions.
877
     *
878
     * @param string $permissionName The permission name to check against the user's permissions.
879
     * @return boolean
880
     */
881
    protected function checkPermission($permissionName)
882
    {
883
        if (isset($this->requiredGlobalAclPermissions[$permissionName])) {
884
            $permissions = $this->requiredGlobalAclPermissions[$permissionName];
885
        } elseif (isset($this->requiredAclPermissions()[$permissionName])) {
886
            $permissions = $this->requiredAclPermissions()[$permissionName];
887
        } else {
888
            return true;
889
        }
890
891
        // Test sidebar vs. ACL roles
892
        $authUser = $this->authenticator()->authenticate();
893
        if (!$this->authorizer()->userAllowed($authUser, $permissions)) {
0 ignored issues
show
Bug introduced by
It seems like $authUser can also be of type null; however, parameter $user of Charcoal\User\Authorizer::userAllowed() does only seem to accept Charcoal\User\UserInterface, 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

893
        if (!$this->authorizer()->userAllowed(/** @scrutinizer ignore-type */ $authUser, $permissions)) {
Loading history...
Bug introduced by
$permissions of type string is incompatible with the type array expected by parameter $aclPermissions of Charcoal\User\Authorizer::userAllowed(). ( Ignorable by Annotation )

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

893
        if (!$this->authorizer()->userAllowed($authUser, /** @scrutinizer ignore-type */ $permissions)) {
Loading history...
894
            header('HTTP/1.0 403 Forbidden');
895
            header('Location: '.$this->adminUrl().'login');
896
897
            return false;
898
        }
899
900
        return true;
901
    }
902
903
    /**
904
     * @return string[]
905
     */
906
    public function requiredGlobalAclPermissions()
907
    {
908
        return $this->requiredGlobalAclPermissions;
909
    }
910
911
    /**
912
     * @param array $permissions The GlobalAcl permissions required pby the form group.
913
     * @return self
914
     */
915
    public function setRequiredGlobalAclPermissions(array $permissions)
916
    {
917
        $this->requiredGlobalAclPermissions = $permissions;
918
919
        return $this;
920
    }
921
922
923
924
    // Utilities
925
    // =========================================================================
926
927
    /**
928
     * @param array $array Detect if $array is assoc or not.
929
     * @return boolean
930
     */
931
    protected function isAssoc(array $array)
932
    {
933
        if ($array === []) {
934
            return false;
935
        }
936
937
        return !!array_filter($array, 'is_string', ARRAY_FILTER_USE_KEY);
938
    }
939
}
940