Passed
Push — main ( 47a406...6037b2 )
by Thierry
02:35
created

Scope::html()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Lagdo\UiBuilder\Html;
4
5
use Lagdo\UiBuilder\Component\Base\HtmlComponent;
6
use Lagdo\UiBuilder\Component\Base\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 array $arguments The arguments passed to the component
77
     *
78
     * @return void
79
     */
80
    public function build(array $arguments): void
81
    {
82
        foreach ($arguments as $argument) {
83
            $this->expand($argument);
84
        }
85
86
        foreach ($this->children as $component) {
87
            if (is_a($component, Element::class)) {
88
                // A children of type Element doesn't need any further processing.
89
                $this->elements[] = $component;
90
                continue;
91
            }
92
93
            // The component is an instance of HtmlComponent.
94
            // Allow the component libraries to react to the parent-child relation.
95
            $component->expanded($this->parent);
96
97
            $scope = new Scope($component);
98
            // Recursively build the component children.
99
            $scope->build($component->children());
100
101
            // Add the child component element to the scope elements.
102
            $this->elements[] = $this->getElement($component, $scope->elements);
103
        }
104
    }
105
106
    /**
107
     * @return string
108
     */
109
    public function html(): string
110
    {
111
        // Merge all the generated elements.
112
        return implode('', $this->elements);
113
    }
114
}
115