Passed
Push — main ( 21e8dc...62d82d )
by Pavel
01:31
created

Includeset::fromString()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 1
dl 0
loc 25
rs 9.7998
c 0
b 0
f 0
1
<?php namespace JSONAPI\Resource;
2
3
/**
4
 * Class helper for working with `include` JSON:API parameter.
5
 *
6
 * @link https://jsonapi.org/format/#fetching-includes
7
 *
8
 * @implements \ArrayAccess<string, Includeset>
9
 * @implements \IteratorAggregate<string, Includeset>
10
 */
11
final class Includeset implements \ArrayAccess, \IteratorAggregate, \Countable
12
{
13
    const ITEM_SEPARATOR = ',';
14
    const RELATION_SEPARATOR = '.';
15
16
    /** @var array<string, Includeset> */
17
    protected array $relations = [];
18
19
    public static function fromString(string $raw): Includeset
20
    {
21
        $include = new Includeset();
22
        $items = array_unique(explode(Includeset::ITEM_SEPARATOR, $raw));
23
24
        foreach ($items as $item) {
25
            $parserInclude = explode(Includeset::RELATION_SEPARATOR, $item, 2);
26
            $relation = array_shift($parserInclude);
27
28
            if (empty($relation)) continue;
29
30
            $rawChildren = array_shift($parserInclude) ?? '';
31
32
            if (isset($include->relations[$relation])) {
33
                $include->relations[$relation] = $include
34
                    ->relations[$relation]
35
                    ->withInclude(Includeset::fromString($rawChildren));
36
37
                continue;
38
            }
39
40
            $include->relations[$relation] = Includeset::fromString($rawChildren);
41
        }
42
43
        return $include;
44
    }
45
46
    public function withRelation(string $relation): self
47
    {
48
        if (isset($this[$relation])) {
49
            return $this;
50
        }
51
52
        $new = clone $this;
53
        $new->relations[$relation] = new Includeset();
54
55
        return $new;
56
    }
57
58
    public function withInclude(self $includeset): self
59
    {
60
        $new = clone $this;
61
62
        foreach ($includeset as $relation => $item) {
63
            if (isset($new->relations[$relation])) {
64
                $new->relations[$relation] = $new
65
                    ->relations[$relation]
66
                    ->withInclude($item);
67
68
                continue;
69
            }
70
71
            $new->relations[$relation] = $item;
72
        }
73
74
        return $new;
75
    }
76
77
    public function count() : int
78
    {
79
        return count($this->relations);
80
    }
81
82
    public function offsetExists($key): bool
83
    {
84
        return isset($this->relations[$key]);
85
    }
86
87
    public function offsetGet($key): ?Includeset
88
    {
89
        return isset($this->relations[$key]) ? $this->relations[$key] : null;
90
    }
91
92
    public function offsetSet($key, $value)
93
    {
94
        throw new \LogicException('Modifying includeset is not permitted');
95
    }
96
97
    public function offsetUnset($key)
98
    {
99
        throw new \LogicException('Modifying includeset is not permitted');
100
    }
101
102
    public function getIterator()
103
    {
104
        return new \ArrayIterator($this->relations);
105
    }
106
}