Completed
Push — master ( 52b2ea...d5cfd4 )
by Jasper
12s queued 10s
created

ItemParser::getItemInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Swis\JsonApi\Client\Parsers;
4
5
use Swis\JsonApi\Client\Collection;
6
use Swis\JsonApi\Client\Exceptions\ValidationException;
7
use Swis\JsonApi\Client\Interfaces\DataInterface;
8
use Swis\JsonApi\Client\Interfaces\ItemInterface;
9
use Swis\JsonApi\Client\Interfaces\TypeMapperInterface;
10
use Swis\JsonApi\Client\Item;
11
12
/**
13
 * @internal
14
 */
15
class ItemParser
16
{
17
    /**
18
     * @var \Swis\JsonApi\Client\Interfaces\TypeMapperInterface
19
     */
20
    private $typeMapper;
21
22
    /**
23
     * @var \Swis\JsonApi\Client\Parsers\LinksParser
24
     */
25
    private $linksParser;
26
27
    /**
28
     * @var \Swis\JsonApi\Client\Parsers\MetaParser
29
     */
30
    private $metaParser;
31
32
    /**
33
     * @param \Swis\JsonApi\Client\Interfaces\TypeMapperInterface $typeMapper
34
     * @param \Swis\JsonApi\Client\Parsers\LinksParser            $linksParser
35
     * @param \Swis\JsonApi\Client\Parsers\MetaParser             $metaParser
36
     */
37 576
    public function __construct(TypeMapperInterface $typeMapper, LinksParser $linksParser, MetaParser $metaParser)
38
    {
39 576
        $this->typeMapper = $typeMapper;
40 576
        $this->linksParser = $linksParser;
41 576
        $this->metaParser = $metaParser;
42 576
    }
43
44
    /**
45
     * @param mixed $data
46
     *
47
     * @return \Swis\JsonApi\Client\Interfaces\ItemInterface
48
     */
49 450
    public function parse($data): ItemInterface
50
    {
51 450
        if (!is_object($data)) {
52 36
            throw new ValidationException(sprintf('Resource has to be an object, "%s" given.', gettype($data)));
53
        }
54 414
        if (!property_exists($data, 'type')) {
55 6
            throw new ValidationException('Resource object MUST contain a type.');
56
        }
57 408
        if (!property_exists($data, 'id')) {
58 6
            throw new ValidationException('Resource object MUST contain an id.');
59
        }
60 402
        if (!is_string($data->type)) {
61 36
            throw new ValidationException(sprintf('Resource property "type" has to be a string, "%s" given.', gettype($data->type)));
62
        }
63 366
        if (!is_string($data->id) && !is_numeric($data->id)) {
64 24
            throw new ValidationException(sprintf('Resource property "id" has to be a string, "%s" given.', gettype($data->id)));
65
        }
66 342
        if (property_exists($data, 'attributes')) {
67 156
            if (!is_object($data->attributes)) {
68 36
                throw new ValidationException(sprintf('Resource property "attributes" has to be an object, "%s" given.', gettype($data->attributes)));
69
            }
70 120
            if (property_exists($data->attributes, 'type') || property_exists($data->attributes, 'id') || property_exists($data->attributes, 'relationships') || property_exists($data->attributes, 'links')) {
71 24
                throw new ValidationException('These properties are not allowed in attributes: `type`, `id`, `relationships`, `links`');
72
            }
73
        }
74
75 282
        $item = $this->getItemInstance($data->type);
76
77 282
        if (property_exists($data, 'id')) {
78 282
            $item->setId($data->id);
79
        }
80
81 282
        if (property_exists($data, 'attributes')) {
82 96
            $item->fill((array)$data->attributes);
83
        }
84
85 282
        if (property_exists($data, 'relationships')) {
86 264
            $this->setRelations($item, $data->relationships);
87
        }
88
89 90
        if (property_exists($data, 'links')) {
90 60
            $item->setLinks($this->linksParser->parse($data->links));
91
        }
92
93 90
        if (property_exists($data, 'meta')) {
94 60
            $item->setMeta($this->metaParser->parse($data->meta));
95
        }
96
97 90
        return $item;
98
    }
99
100
    /**
101
     * @param string $type
102
     *
103
     * @return \Swis\JsonApi\Client\Interfaces\ItemInterface
104
     */
105 282
    private function getItemInstance(string $type): ItemInterface
106
    {
107 282
        if ($this->typeMapper->hasMapping($type)) {
108 252
            return $this->typeMapper->getMapping($type);
109
        }
110
111 30
        return (new Item())->setType($type);
112
    }
113
114
    /**
115
     * @param \Swis\JsonApi\Client\Interfaces\ItemInterface $item
116
     * @param mixed                                         $data
117
     */
118 264
    private function setRelations(ItemInterface $item, $data): void
119
    {
120 264
        if (!is_object($data)) {
121 36
            throw new ValidationException(sprintf('Relationships has to be an object, "%s" given.', gettype($data)));
122
        }
123 228
        if (property_exists($data, 'type') || property_exists($data, 'id')) {
124 12
            throw new ValidationException('These properties are not allowed in relationships: `type`, `id`.');
125
        }
126
127 216
        foreach ($data as $name => $relationship) {
128 216
            if ($item->hasAttribute($name)) {
129 6
                throw new ValidationException(sprintf('Relationship "%s" cannot be set because it already exists in Resource object.', $name));
130
            }
131 210
            if (!is_object($relationship)) {
132 36
                throw new ValidationException(sprintf('Relationship has to be an object, "%s" given.', gettype($relationship)));
133
            }
134 174
            if (!property_exists($relationship, 'links') && !property_exists($relationship, 'data') && !property_exists($relationship, 'meta')) {
135 6
                throw new ValidationException('Relationship object MUST contain at least one of the following properties: `links`, `data`, `meta`.');
136
            }
137
138 168
            $value = new Collection();
139 168
            if (property_exists($relationship, 'data') && $relationship->data !== null) {
140 168
                $value = $this->parseRelationshipData($relationship->data);
141
            }
142
143 72
            $links = null;
144 72
            if (property_exists($relationship, 'links')) {
145 60
                $links = $this->linksParser->parse($relationship->links);
146
            }
147
148 72
            $meta = null;
149 72
            if (property_exists($relationship, 'meta')) {
150 60
                $meta = $this->metaParser->parse($relationship->meta);
151
            }
152
153 72
            $item->setRelation($name, $value, $links, $meta);
154
        }
155 72
    }
156
157
    /**
158
     * @param mixed $data
159
     *
160
     * @throws \InvalidArgumentException
161
     *
162
     * @return \Swis\JsonApi\Client\Interfaces\DataInterface
163
     */
164 168
    private function parseRelationshipData($data): DataInterface
165
    {
166 168
        if (is_array($data)) {
167 66
            return Collection::make($data)
168 66
                ->map(
169 22
                    function ($identifier) {
170 66
                        return $this->parseRelationshipData($identifier);
171 66
                    }
172
                );
173
        }
174
175 168
        if (!is_object($data)) {
176 24
            throw new ValidationException(sprintf('ResourceIdentifier has to be an object, "%s" given.', gettype($data)));
177
        }
178 144
        if (!property_exists($data, 'type')) {
179 6
            throw new ValidationException('ResourceIdentifier object MUST contain a type.');
180
        }
181 138
        if (!property_exists($data, 'id')) {
182 6
            throw new ValidationException('ResourceIdentifier object MUST contain an id.');
183
        }
184 132
        if (!is_string($data->type)) {
185 36
            throw new ValidationException(sprintf('ResourceIdentifier property "type" has to be a string, "%s" given.', gettype($data->type)));
186
        }
187 96
        if (!is_string($data->id) && !is_numeric($data->id)) {
188 24
            throw new ValidationException(sprintf('ResourceIdentifier property "id" has to be a string, "%s" given.', gettype($data->type)));
189
        }
190
191 72
        return $this->getItemInstance($data->type)->setId($data->id);
192
    }
193
}
194