Issues (49)

src/Builder/Engine/Scope.php (1 issue)

1
<?php
2
3
namespace Lagdo\UiBuilder\Builder\Engine;
4
5
use Lagdo\UiBuilder\Component\HtmlComponent;
6
use Lagdo\UiBuilder\Component\HtmlElement;
7
use Lagdo\UiBuilder\Component\Html\Element;
8
use Lagdo\UiBuilder\Component\Virtual\VirtualComponent;
9
10
use function is_a;
11
use function implode;
12
13
class Scope
14
{
15
    /**
16
     * @var array<Element>
17
     */
18
    protected $elements = [];
19
20
    /**
21
     * @var array<Element|HtmlComponent>
22
     */
23
    protected $children = [];
24
25
    /**
26
     * The constructor
27
     *
28
     * @param HtmlComponent $parent
29
     */
30
    public function __construct(protected HtmlComponent $parent)
31
    {}
32
33
    /**
34
     * Create the corresponding components
35
     *
36
     * @param mixed $component
37
     *
38
     * @return void
39
     */
40
    private function expand(mixed $component): void
41
    {
42
        if (is_a($component, Element::class) ||
43
            is_a($component, HtmlComponent::class)) {
44
            $this->children[] = $component;
45
            return;
46
        }
47
48
        if (is_a($component, VirtualComponent::class)) {
49
            // Recursively expand the children of the virtual components.
50
            foreach ($component->children() as $childElement) {
51
                $this->expand($childElement);
52
            }
53
        }
54
    }
55
56
    /**
57
     * @param HtmlComponent $component
58
     * @param array<Element> $children
59
     *
60
     * @return HtmlElement
61
     */
62
    private function getElement(HtmlComponent $component, array $children): HtmlElement
63
    {
64
        $element = $component->element();
65
        $element->addChildren($children);
66
        // Nest the component element into its wrappers elements.
67
        foreach ($component->wrappers() as $wrapper) {
68
            $wrapper->addChild($element);
69
            $element = $wrapper;
70
        }
71
72
        return $element;
73
    }
74
75
    /**
76
     * @param Engine $engine
77
     * @param array $arguments The arguments passed to the component
78
     *
79
     * @return void
80
     */
81
    public function build(Engine $engine, array $arguments): void
82
    {
83
        foreach ($arguments as $argument) {
84
            $this->expand($argument);
85
        }
86
87
        foreach ($this->children as $component) {
88
            if (is_a($component, Element::class)) {
89
                // A children of type Element doesn't need any further processing.
90
                $this->elements[] = $component;
91
                continue;
92
            }
93
94
            // The component is an instance of HtmlComponent.
95
            $isForm = $component->element()->tag() === 'form';
96
            if ($isForm) {
97
                $engine->formStarted();
98
            }
99
100
            // Allow the component libraries to react to the parent-child relation.
101
            $component->expanded($this->parent);
102
103
            $scope = new Scope($component);
104
            // Recursively build the component children.
105
            $scope->build($engine, $component->children());
106
107
            if ($isForm) {
108
                $engine->formEnded();
109
            }
110
111
            // Add the child component element and its siblings to the scope elements.
112
            $this->elements = [
0 ignored issues
show
Documentation Bug introduced by
array($this->elements, $...nent->siblings('next')) is of type array<integer,Lagdo\UiBu...t\Html\Element[]|array>, but the property $elements was declared to be of type Lagdo\UiBuilder\Component\Html\Element[]. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
113
                ...$this->elements,
114
                ...$component->siblings('prev'),
115
                $this->getElement($component, $scope->elements),
116
                ...$component->siblings('next'),
117
            ];
118
        }
119
    }
120
121
    /**
122
     * @return string
123
     */
124
    public function html(): string
125
    {
126
        // Merge all the generated elements.
127
        return implode('', $this->elements);
128
    }
129
}
130