Completed
Push — v2 ( ad2ba8...88b419 )
by Joschi
04:59
created

Item::validatePropertyStructure()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6.972

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 2
nop 1
dl 0
loc 15
ccs 7
cts 10
cp 0.7
crap 6.972
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category Jkphl
7
 * @package Jkphl\Micrometa
8
 * @subpackage Jkphl\Micrometa\Domain\Miom
9
 * @author Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Jkphl\Micrometa\Domain\Item;
38
39
use Jkphl\Micrometa\Domain\Exceptions\InvalidArgumentException;
40
use Jkphl\Micrometa\Domain\Exceptions\OutOfBoundsException;
41
use Jkphl\Micrometa\Domain\Factory\IriFactory;
42
use Jkphl\Micrometa\Domain\Value\ValueInterface;
43
44
/**
45
 * Micro information item
46
 *
47
 * @package Jkphl\Micrometa
48
 * @subpackage Jkphl\Micrometa\Domain
49
 */
50
class Item implements ItemInterface
51
{
52
    /**
53
     * Item type(s)
54
     *
55
     * @var string[]
56
     */
57
    protected $type;
58
59
    /**
60
     * Item properties
61
     *
62
     * @var PropertyList
63
     */
64
    protected $properties;
65
66
    /**
67
     * Item ID
68
     *
69
     * @var string
70
     */
71
    protected $itemId;
72
73
    /**
74
     * Item constructor
75
     *
76
     * @param string|\stdClass|\stdClass[] $type Item type(s)
77
     * @param array[] $properties Item properties
78
     * @param string|null $itemId Item id
79
     */
80 25
    public function __construct($type, array $properties = [], $itemId = null)
81
    {
82 25
        $this->type = $this->validateTypes(is_array($type) ? $type : [$type]);
83 24
        $this->properties = $this->validateProperties($properties);
84 22
        $this->itemId = trim($itemId) ?: null;
85 22
    }
86
87
    /**
88
     * Validate and sanitize the item types
89
     *
90
     * @param \stdClass[] $types Item types
91
     * @return array Validated item types
92
     * @throws InvalidArgumentException If there are no valid types
93
     */
94 25
    protected function validateTypes(array $types)
95
    {
96 25
        $nonEmptyTypes = array_filter(array_map([$this, 'validateType'], $types));
97
98
        // If there are no valid types
99 24
        if (!count($nonEmptyTypes)) {
100
            throw new InvalidArgumentException(
101
                InvalidArgumentException::EMPTY_TYPES_STR,
102
                InvalidArgumentException::EMPTY_TYPES
103
            );
104
        }
105
106 24
        return array_values($nonEmptyTypes);
107
    }
108
109
    /**
110
     * Validate the item properties
111
     *
112
     * @param array $properties Item properties
113
     * @return PropertyList Validated item properties
114
     * @throws InvalidArgumentException If the property name is empty
115
     */
116 24
    protected function validateProperties(array $properties)
117
    {
118 24
        $validatedProperties = new PropertyList();
119
120
        // Run through all validated properties
121 24
        foreach (array_filter(array_map([$this, 'validateProperty'], $properties)) as $property) {
122 13
            $validatedProperties->add($property);
123
        }
124
125 22
        return $validatedProperties;
126
    }
127
128
    /**
129
     * Return the item types
130
     *
131
     * @return string[] Item types
132
     */
133 13
    public function getType()
134
    {
135 13
        return $this->type;
136
    }
137
138
    /**
139
     * Return the item ID (if any)
140
     *
141
     * @return string|null Item id
142
     */
143 12
    public function getId()
144
    {
145 12
        return $this->itemId;
146
    }
147
148
    /**
149
     * Return all item properties
150
     *
151
     * @return PropertyList Item properties list
152
     */
153 13
    public function getProperties()
154
    {
155 13
        return $this->properties;
156
    }
157
158
    /**
159
     * Return the values of a particular property
160
     *
161
     * @param string $name Property name
162
     * @param string|null $profile Property profile
163
     * @return array Item property values
164
     * @throws OutOfBoundsException If the property is unknown
165
     */
166 2
    public function getProperty($name, $profile = null)
167
    {
168 2
        $iri = IriFactory::create(($profile === null) ? $name : (object)['profile' => $profile, 'name' => $name]);
169 2
        return $this->properties->offsetGet($iri);
170
    }
171
172
    /**
173
     * Return whether the value should be considered empty
174
     *
175
     * @return boolean Value is empty
176
     */
177 7
    public function isEmpty()
178
    {
179 7
        return false;
180
    }
181
182
    /**
183
     * Validate a single property
184
     *
185
     * @param \stdClass $property Property
186
     * @return \stdClass Validated property
187
     */
188 15
    protected function validateProperty($property)
189
    {
190
        // Validate the property structure
191 15
        $this->validatePropertyStructure($property);
192
193
        // If the property has values
194 15
        if (count($property->values)) {
195
            // Validate the property name
196 15
            $property->name = $this->validatePropertyName($property);
197
198
            // Validate the property values
199 14
            $property->values = $this->validatePropertyValues($property->values);
200
201
            // If the property has significant values
202 13
            if (count($property->values)) {
203 13
                return $property;
204
            }
205
        }
206
207
        return null;
208
    }
209
210
    /**
211
     * Validate the structure of a property object
212
     *
213
     * @param \stdClass $property Property object
214
     * @throws InvalidArgumentException If the property object is invalid
215
     */
216 15
    protected function validatePropertyStructure($property)
217
    {
218
        // If the property object is invalid
219 15
        if (!is_object($property)
220 15
            || !isset($property->profile)
221 15
            || !isset($property->name)
222 15
            || !isset($property->values)
223 15
            || !is_array($property->values)
224
        ) {
225
            throw new InvalidArgumentException(
226
                InvalidArgumentException::INVALID_PROPERTY_STR,
227
                InvalidArgumentException::INVALID_PROPERTY
228
            );
229
        }
230 15
    }
231
232
    /**
233
     * Validate a property name
234
     *
235
     * @param \stdClass $property Property
236
     * @return string Property name
237
     */
238 15
    protected function validatePropertyName($property)
239
    {
240 15
        $propertyName = trim($property->name);
241
242
        // If the property name is empty
243 15
        if (!strlen($propertyName)) {
244 1
            throw new InvalidArgumentException(
245 1
                InvalidArgumentException::EMPTY_PROPERTY_NAME_STR,
246 1
                InvalidArgumentException::EMPTY_PROPERTY_NAME
247
            );
248
        }
249
250 14
        return $propertyName;
251
    }
252
253
    /**
254
     * Validate a list of property values
255
     *
256
     * @param array $values Property values
257
     * @return array Validated property values
258
     * @throws InvalidArgumentException If the value is not a nested item
259
     */
260 14
    protected function validatePropertyValues(array $values)
261
    {
262 14
        $nonEmptyPropertyValues = [];
263
264
        // Run through all property values
265
        /** @var ValueInterface $value */
266 14
        foreach ($values as $value) {
267
            // If the value is not a nested item
268 14
            if (!($value instanceof ValueInterface)) {
269 1
                throw new InvalidArgumentException(
270 1
                    sprintf(InvalidArgumentException::INVALID_PROPERTY_VALUE_STR, gettype($value)),
271 1
                    InvalidArgumentException::INVALID_PROPERTY_VALUE
272
                );
273
            }
274
275 13
            if (!$value->isEmpty()) {
276 13
                $nonEmptyPropertyValues[] = $value;
277
            }
278
        }
279
280 13
        return $nonEmptyPropertyValues;
281
    }
282
283
    /**
284
     * Validate a single item type
285
     *
286
     * @param \stdClass|string $type Item type
287
     * @return \stdClass|null Validated item type
288
     * @throws InvalidArgumentException If the item type object is invalid
289
     */
290 25
    protected function validateType($type)
291
    {
292 25
        $type = IriFactory::create($type);
293 24
        return strlen($type->name) ? $type : null;
294
    }
295
}
296