Passed
Push — html ( 1dd7b6 )
by Peter
08:14
created

Navigation::resort()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 10
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Navigation;
6
7
use AbterPhp\Framework\Constant\Html5;
8
use AbterPhp\Framework\Html\Attribute;
9
use AbterPhp\Framework\Html\Contentless;
10
use AbterPhp\Framework\Html\Helper\ArrayHelper;
11
use AbterPhp\Framework\Html\INode;
12
use AbterPhp\Framework\Html\ITag;
13
use AbterPhp\Framework\Html\Node;
14
use InvalidArgumentException;
15
16
class Navigation extends Contentless
17
{
18
    public const ROLE_NAVIGATION = 'navigation';
19
20
    public const INTENT_NAVBAR    = 'navbar';
21
    public const INTENT_FOOTER    = 'footer';
22
    public const INTENT_PRIMARY   = 'primary';
23
    public const INTENT_SECONDARY = 'secondary';
24
25
    protected const DEFAULT_TAG = Html5::TAG_UL;
26
    protected const CONTENT_TYPE = Item::class;
27
    protected const SEPARATOR = "\n";
28
29
    protected const ERROR_INVALID_TAG_FOR_ITEM_CREATION = 'item creation is not allowed for navigation type: %s';
30
    protected const ERROR_NAVIGATION_OFFSET_NOT_ALLOWED = 'navigation offsets are not allowed';
31
32
    protected INode $prefix;
33
    protected INode $postfix;
34
35
    protected ?ITag $wrapper = null;
36
37
    /** @var Item[][] */
38
    protected array $itemsByWeight = [];
39
40
    /** @var Item[] */
41
    protected array $content = [];
42
43
    /**
44
     * Navigation constructor.
45
     *
46
     * @param string[]                     $intents
47
     * @param array<string,Attribute>|null $attributes
48
     * @param string|null                  $tag
49
     */
50
    public function __construct(array $intents = [], ?array $attributes = null, ?string $tag = null)
51
    {
52
        parent::__construct($intents, $attributes, $tag);
53
54
        $this->prefix  = new Node();
55
        $this->postfix = new Node();
56
    }
57
58
    /**
59
     * @param int  $weight
60
     * @param Item ...$items
61
     *
62
     * @return $this
63
     */
64
    public function addWithWeight(int $weight = PHP_INT_MAX, Item ...$items): Navigation
65
    {
66
        foreach ($items as $item) {
67
            $this->itemsByWeight[$weight][] = $item;
68
        }
69
70
        return $this;
71
    }
72
73
    protected function resort(): void
74
    {
75
        ksort($this->itemsByWeight);
76
77
        $content = [];
78
        foreach ($this->itemsByWeight as $items) {
79
            $content = array_merge($content, $items);
80
        }
81
82
        $this->content = $content;
83
    }
84
85
    /**
86
     * @return INode
87
     */
88
    public function getPrefix(): INode
89
    {
90
        return $this->prefix;
91
    }
92
93
    /**
94
     * @param INode $prefix
95
     *
96
     * @return $this
97
     */
98
    public function setPrefix(INode $prefix): self
99
    {
100
        $this->prefix = $prefix;
101
102
        return $this;
103
    }
104
105
    /**
106
     * @return INode
107
     */
108
    public function getPostfix(): INode
109
    {
110
        return $this->postfix;
111
    }
112
113
    /**
114
     * @param INode $postfix
115
     *
116
     * @return $this
117
     */
118
    public function setPostfix(INode $postfix): self
119
    {
120
        $this->postfix = $postfix;
121
122
        return $this;
123
    }
124
125
    /**
126
     * @return ITag|null
127
     */
128
    public function getWrapper(): ?ITag
129
    {
130
        return $this->wrapper;
131
    }
132
133
    /**
134
     * @param ITag|null $wrapper
135
     *
136
     * @return $this
137
     */
138
    public function setWrapper(?ITag $wrapper): self
139
    {
140
        $this->wrapper = $wrapper;
141
142
        return $this;
143
    }
144
145
    /**
146
     * @return INode[]
147
     */
148
    public function getNodes(): array
149
    {
150
        $this->resort();
151
152
        return $this->content;
153
    }
154
155
    /**
156
     * @return INode[]
157
     */
158
    public function getExtendedNodes(): array
159
    {
160
        $nodes = array_merge([$this->prefix, $this->postfix], $this->getNodes());
161
162
        if ($this->wrapper) {
163
            $nodes[] = $this->wrapper;
164
        }
165
166
        return $nodes;
167
    }
168
169
    /**
170
     * @return string
171
     */
172
    public function __toString(): string
173
    {
174
        $this->resort();
175
176
        $content = parent::__toString();
177
178
        if ($this->wrapper) {
179
            $content = (string)$this->wrapper->setContent($content);
180
        }
181
182
        $prefix  = $this->prefix ? (string)$this->prefix : '';
183
        $postfix = $this->postfix ? (string)$this->postfix : '';
184
185
        return $prefix . $content . $postfix;
186
    }
187
188
    /**
189
     * @param int|null $offset
190
     * @param INode    $value
191
     */
192
    public function offsetSet($offset, $value): void
193
    {
194
        assert(ArrayHelper::allInstanceOf([$value], static::CONTENT_TYPE));
195
196
        if (is_null($offset) && $value instanceof Item) {
197
            $this->addWithWeight(PHP_INT_MAX, $value);
198
        } elseif (!is_int($offset) || $offset < 0 || $offset > count($this->content)) {
199
            throw new InvalidArgumentException(static::ERROR_INVALID_OFFSET);
200
        } elseif ($value instanceof Item) {
201
            throw new InvalidArgumentException(static::ERROR_NAVIGATION_OFFSET_NOT_ALLOWED);
202
        }
203
    }
204
}
205