Completed
Push — v2 ( a3e6f8...094005 )
by Joschi
07:34
created

Item   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 285
c 0
b 0
f 0
wmc 34
lcom 3
cbo 7
ccs 74
cts 74
cp 1
rs 9.2

14 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 13 5
A validateTypes() 0 14 2
A validateProperties() 0 11 2
A getType() 0 4 1
A getId() 0 4 1
A getLanguage() 0 4 1
A getProperties() 0 4 1
A getProperty() 0 12 3
A isEmpty() 0 4 1
A validateProperty() 0 21 3
B validatePropertyStructure() 0 15 6
A validatePropertyName() 0 14 2
B validatePropertyValues() 0 22 4
A validateType() 0 5 2
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\Factory\IriFactory;
41
use Jkphl\Micrometa\Domain\Factory\PropertyListFactory;
42
use Jkphl\Micrometa\Domain\Factory\PropertyListFactoryInterface;
43
use Jkphl\Micrometa\Domain\Value\ValueInterface;
44
45
/**
46
 * Micro information item
47
 *
48
 * @package Jkphl\Micrometa
49
 * @subpackage Jkphl\Micrometa\Domain
50
 */
51
class Item implements ItemInterface
52
{
53
    /**
54
     * Item type(s)
55
     *
56
     * @var \stdClass[]
57
     */
58
    protected $type;
59
60
    /**
61
     * Item properties
62
     *
63
     * @var PropertyListInterface
64
     */
65
    protected $properties;
66
67
    /**
68
     * Item ID
69
     *
70
     * @var string
71
     */
72
    protected $itemId;
73
74
    /**
75
     * Item language
76
     *
77
     * @var string
78
     */
79
    protected $itemLanguage;
80
81
    /**
82
     * Property list factory
83
     *
84
     * @var PropertyListFactoryInterface
85
     */
86
    protected $propertyListFactory;
87
88
    /**
89
     * Item constructor
90
     *
91
     * @param string|\stdClass|\stdClass[] $type Item type(s)
92
     * @param \stdClass[] $properties Item properties
93
     * @param string|null $itemId Item id
94
     * @param string|null $itemLanguage Item language
95
     * @param PropertyListFactoryInterface|null $propertyListFactory Property list factory
96
     */
97 46
    public function __construct(
98
        $type,
99
        array $properties = [],
100
        $itemId = null,
101
        $itemLanguage = null,
102
        PropertyListFactoryInterface $propertyListFactory = null
103
    ) {
104 46
        $this->propertyListFactory = $propertyListFactory ?: new PropertyListFactory();
105 46
        $this->type = $this->validateTypes(is_array($type) ? $type : [$type]);
106 44
        $this->properties = $this->validateProperties($properties);
107 41
        $this->itemId = trim($itemId) ?: null;
108 41
        $this->itemLanguage = trim($itemLanguage) ?: null;
109 41
    }
110
111
    /**
112
     * Validate and sanitize the item types
113
     *
114
     * @param \stdClass[] $types Item types
115
     * @return array Validated item types
116
     * @throws InvalidArgumentException If there are no valid types
117
     */
118 46
    protected function validateTypes(array $types)
119
    {
120 46
        $nonEmptyTypes = array_filter(array_map([$this, 'validateType'], $types));
121
122
        // If there are no valid types
123 45
        if (!count($nonEmptyTypes)) {
124 1
            throw new InvalidArgumentException(
125 1
                InvalidArgumentException::EMPTY_TYPES_STR,
126 1
                InvalidArgumentException::EMPTY_TYPES
127
            );
128
        }
129
130 44
        return array_values($nonEmptyTypes);
131
    }
132
133
    /**
134
     * Validate the item properties
135
     *
136
     * @param array $properties Item properties
137
     * @return PropertyListInterface Validated item properties
138
     * @throws InvalidArgumentException If the property name is empty
139
     */
140 44
    protected function validateProperties(array $properties)
141
    {
142 44
        $validatedProperties = $this->propertyListFactory->create();
143
144
        // Run through all validated properties
145 44
        foreach (array_filter(array_map([$this, 'validateProperty'], $properties)) as $property) {
146 28
            $validatedProperties->add($property);
147
        }
148
149 41
        return $validatedProperties;
150
    }
151
152
    /**
153
     * Return the item types
154
     *
155
     * @return \stdClass[] Item types
156
     */
157 23
    public function getType()
158
    {
159 23
        return $this->type;
160
    }
161
162
    /**
163
     * Return the item ID (if any)
164
     *
165
     * @return string|null Item id
166
     */
167 19
    public function getId()
168
    {
169 19
        return $this->itemId;
170
    }
171
172
    /**
173
     * Return the item language (if any)
174
     *
175
     * @return string|null Item language
176
     */
177 18
    public function getLanguage()
178
    {
179 18
        return $this->itemLanguage;
180
    }
181
182
    /**
183
     * Return all item properties
184
     *
185
     * @return PropertyListInterface Item properties list
186
     */
187 21
    public function getProperties()
188
    {
189 21
        return $this->properties;
190
    }
191
192
    /**
193
     * Return the values of a particular property
194
     *
195
     * @param string|\stdClass|Iri $name Property name
196
     * @param string|null $profile Property profile
197
     * @return array Item property values
198
     */
199 10
    public function getProperty($name, $profile = null)
200
    {
201 10
        $iri = IriFactory::create(
202 10
            (($profile === null) || is_object($name)) ?
203 8
                $name :
204
                (object)[
205 4
                    'profile' => $profile,
206 10
                    'name' => $name
207
                ]
208
        );
209 10
        return $this->properties->offsetGet($iri);
210
    }
211
212
    /**
213
     * Return whether the value should be considered empty
214
     *
215
     * @return boolean Value is empty
216
     */
217 17
    public function isEmpty()
218
    {
219 17
        return false;
220
    }
221
222
    /**
223
     * Validate a single property
224
     *
225
     * @param \stdClass $property Property
226
     * @return \stdClass Validated property
227
     */
228 33
    protected function validateProperty($property)
229
    {
230
        // Validate the property structure
231 33
        $this->validatePropertyStructure($property);
232
233
        // If the property has values
234 32
        if (count($property->values)) {
235
            // Validate the property name
236 31
            $property->name = $this->validatePropertyName($property);
237
238
            // Validate the property values
239 30
            $property->values = $this->validatePropertyValues($property->values);
240
241
            // If the property has significant values
242 29
            if (count($property->values)) {
243 28
                return $property;
244
            }
245
        }
246
247 2
        return null;
248
    }
249
250
    /**
251
     * Validate the structure of a property object
252
     *
253
     * @param \stdClass $property Property object
254
     * @throws InvalidArgumentException If the property object is invalid
255
     */
256 33
    protected function validatePropertyStructure($property)
257
    {
258
        // If the property object is invalid
259 33
        if (!is_object($property)
260 33
            || !isset($property->profile)
261 32
            || !isset($property->name)
262 32
            || !isset($property->values)
263 33
            || !is_array($property->values)
264
        ) {
265 1
            throw new InvalidArgumentException(
266 1
                InvalidArgumentException::INVALID_PROPERTY_STR,
267 1
                InvalidArgumentException::INVALID_PROPERTY
268
            );
269
        }
270 32
    }
271
272
    /**
273
     * Validate a property name
274
     *
275
     * @param \stdClass $property Property
276
     * @return string Property name
277
     */
278 31
    protected function validatePropertyName($property)
279
    {
280 31
        $propertyName = trim($property->name);
281
282
        // If the property name is empty
283 31
        if (!strlen($propertyName)) {
284 1
            throw new InvalidArgumentException(
285 1
                InvalidArgumentException::EMPTY_PROPERTY_NAME_STR,
286 1
                InvalidArgumentException::EMPTY_PROPERTY_NAME
287
            );
288
        }
289
290 30
        return $propertyName;
291
    }
292
293
    /**
294
     * Validate a list of property values
295
     *
296
     * @param array $values Property values
297
     * @return array Validated property values
298
     * @throws InvalidArgumentException If the value is not a nested item
299
     */
300 30
    protected function validatePropertyValues(array $values)
301
    {
302 30
        $nonEmptyPropertyValues = [];
303
304
        // Run through all property values
305
        /** @var ValueInterface $value */
306 30
        foreach ($values as $value) {
307
            // If the value is not a nested item
308 30
            if (!($value instanceof ValueInterface)) {
309 1
                throw new InvalidArgumentException(
310 1
                    sprintf(InvalidArgumentException::INVALID_PROPERTY_VALUE_STR, gettype($value)),
311 1
                    InvalidArgumentException::INVALID_PROPERTY_VALUE
312
                );
313
            }
314
315 29
            if (!$value->isEmpty()) {
316 29
                $nonEmptyPropertyValues[] = $value;
317
            }
318
        }
319
320 29
        return $nonEmptyPropertyValues;
321
    }
322
323
    /**
324
     * Validate a single item type
325
     *
326
     * @param \stdClass|Iri|string $type Item type
327
     * @return Iri|null Validated item type
328
     * @throws InvalidArgumentException If the item type object is invalid
329
     */
330 46
    protected function validateType($type)
331
    {
332 46
        $type = IriFactory::create($type);
0 ignored issues
show
Bug introduced by
It seems like $type defined by \Jkphl\Micrometa\Domain\...iFactory::create($type) on line 332 can also be of type object<Jkphl\Micrometa\Domain\Item\Iri>; however, Jkphl\Micrometa\Domain\F...ry\IriFactory::create() does only seem to accept string|object<stdClass>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
333 45
        return strlen($type->name) ? $type : null;
334
    }
335
}
336