Completed
Branch master (6c7c3c)
by Joschi
02:33
created

Item   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 7
dl 0
loc 264
ccs 64
cts 64
cp 1
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __get() 0 4 1
A getProperty() 0 12 3
A getPropertyIndex() 0 12 2
A getPropertyValue() 0 5 2
A isOfType() 0 17 3
A isOfProfiledTypes() 0 11 3
A isTypeInNames() 0 5 3
A getType() 0 4 1
A getFirstProperty() 0 22 3
A getProperties() 0 8 2
A toObject() 0 4 1
A getFormat() 0 4 1
A getId() 0 4 1
A getLanguage() 0 4 1
A getValue() 0 4 1
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category Jkphl
7
 * @package Jkphl\Micrometa
8
 * @subpackage Jkphl\Micrometa\Ports
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\Ports\Item;
38
39
use Jkphl\Micrometa\Application\Contract\ValueInterface;
40
use Jkphl\Micrometa\Application\Factory\AliasFactory;
41
use Jkphl\Micrometa\Application\Factory\PropertyListFactory;
42
use Jkphl\Micrometa\Application\Item\ItemInterface as ApplicationItemInterface;
43
use Jkphl\Micrometa\Application\Item\PropertyListInterface;
44
use Jkphl\Micrometa\Domain\Exceptions\OutOfBoundsException as DomainOutOfBoundsException;
45
use Jkphl\Micrometa\Domain\Item\Iri;
46
use Jkphl\Micrometa\Infrastructure\Factory\ItemFactory;
47
use Jkphl\Micrometa\Infrastructure\Factory\ProfiledNamesFactory;
48
use Jkphl\Micrometa\Infrastructure\Parser\ProfiledNamesList;
49
use Jkphl\Micrometa\Ports\Exceptions\InvalidArgumentException;
50
use Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException;
51
52
/**
53
 * Micro information item
54
 *
55
 * @package Jkphl\Micrometa
56
 * @subpackage Jkphl\Micrometa\Ports
57
 */
58
class Item extends ItemList implements ItemInterface
59
{
60
    /**
61
     * Application item
62
     *
63
     * @var ApplicationItemInterface
64
     */
65
    protected $item;
66
67
    /**
68
     * Item constructor
69
     *
70
     * @param ApplicationItemInterface $item Application item
71
     */
72 16
    public function __construct(ApplicationItemInterface $item)
73
    {
74 16
        $this->item = $item;
75 16
        parent::__construct(ItemFactory::createFromApplicationItems($this->item->getChildren()));
76 16
    }
77
78
    /**
79
     * Get the first value of an item property
80
     *
81
     * @param string $name Item property name
82
     * @return ValueInterface|ValueInterface[]|array|ItemInterface First value of an item property
83
     * @api
84
     */
85 2
    public function __get($name)
86
    {
87 2
        return $this->getProperty($name, null, 0);
88
    }
89
90
    /**
91
     * Get a single property (value)
92
     *
93
     * @param string|\stdClass|Iri $name Property name
94
     * @param string $profile Property profile
95
     * @param int|null $index Property value index
96
     * @return ValueInterface|ValueInterface[]|array|ItemInterface Property value(s)
97
     * @throws OutOfBoundsException If the property name is unknown
98
     * @throws OutOfBoundsException If the property value index is out of bounds
99
     * @api
100
     */
101 7
    public function getProperty($name, $profile = null, $index = null)
102
    {
103
        try {
104 7
            $propertyValues = $this->item->getProperty($name, $profile);
105 4
        } catch (DomainOutOfBoundsException $e) {
106 4
            throw new OutOfBoundsException($e->getMessage(), $e->getCode());
107
        }
108
109
        // Return the value(s)
110 7
        return ($index === null) ?
111 7
            array_map([$this, 'getPropertyValue'], $propertyValues) : $this->getPropertyIndex($propertyValues, $index);
112
    }
113
114
    /**
115
     * Return a particular property index
116
     *
117
     * @param ValueInterface[] $propertyValues Property values
118
     * @param int $index Property value index
119
     * @return ValueInterface|ItemInterface
120
     */
121 6
    protected function getPropertyIndex(array $propertyValues, $index)
122
    {
123
        // If the property value index is out of bounds
124 6
        if (!isset($propertyValues[$index])) {
125 1
            throw new OutOfBoundsException(
126 1
                sprintf(OutOfBoundsException::INVALID_PROPERTY_VALUE_INDEX_STR, $index),
127 1
                OutOfBoundsException::INVALID_PROPERTY_VALUE_INDEX
128
            );
129
        }
130
131 5
        return $this->getPropertyValue($propertyValues[$index]);
132
    }
133
134
    /**
135
     * Prepare a property value for returning it
136
     *
137
     * @param ValueInterface $value Property value
138
     * @return ValueInterface|ItemInterface Returnable property value
139
     */
140 7
    protected function getPropertyValue(ValueInterface $value)
141
    {
142 7
        return ($value instanceof ApplicationItemInterface) ?
143 7
            ItemFactory::createFromApplicationItem($value) : $value;
144
    }
145
146
    /**
147
     * Return whether the item is of a particular type (or contained in a list of types)
148
     *
149
     * The item type(s) can be specified in a variety of ways, @see ProfiledNamesFactory::createFromArguments()
150
     *
151
     * @param array ...$types Item types
152
     * @return boolean Item type is contained in the list of types
153
     * @api
154
     */
155 5
    public function isOfType(...$types)
156
    {
157
        /** @var ProfiledNamesList $profiledTypes */
158 5
        $profiledTypes = ProfiledNamesFactory::createFromArguments($types);
159 5
        $aliasFactory = new AliasFactory();
160
161
        // Run through all item types
162
        /** @var \stdClass $itemType */
163 5
        foreach ($this->item->getType() as $itemType) {
164 5
            $itemTypeNames = $aliasFactory->createAliases($itemType->name);
165 5
            if ($this->isOfProfiledTypes($itemType->profile, $itemTypeNames, $profiledTypes)) {
166 5
                return true;
167
            }
168
        }
169
170 3
        return false;
171
    }
172
173
    /**
174
     * Return whether an aliased item type is contained in a set of query types
175
     *
176
     * @param string $profile Type profile
177
     * @param array $names Aliased type names
178
     * @param ProfiledNamesList $types Query types
179
     * @return bool Item type is contained in the set of query types
180
     */
181 5
    protected function isOfProfiledTypes($profile, array $names, ProfiledNamesList $types)
182
    {
183
        // Run through all query types
184
        /** @var \stdClass $queryType */
185 5
        foreach ($types as $queryType) {
186 5
            if ($this->isTypeInNames($queryType, $profile, $names)) {
187 5
                return true;
188
            }
189
        }
190 3
        return false;
191
    }
192
193
    /**
194
     * Test whether a type is contained in a list of names
195
     *
196
     * @param \stdClass $type Type
197
     * @param string $profile Type profile
198
     * @param array $names Aliased type names
199
     * @return bool Type is contained in names list
200
     */
201 5
    protected function isTypeInNames($type, $profile, array $names)
202
    {
203 5
        return in_array($type->name, $names) &&
204 5
            (($type->profile === null) ? true : ($type->profile == $profile));
205
    }
206
207
    /**
208
     * Get all values of the first available property in a stack
209
     *
210
     * The property stack can be specified in a variety of ways, @see ProfiledNamesFactory::createFromArguments()
211
     *
212
     * @param array $properties Properties
213
     * @return ValueInterface[]|array Property values
214
     * @throws InvalidArgumentException If no property name was given
215
     * @throws OutOfBoundsException If none of the requested properties is known
216
     * @api
217
     */
218 2
    public function getFirstProperty(...$properties)
219
    {
220
        /** @var ProfiledNamesList $properties */
221 2
        $properties = ProfiledNamesFactory::createFromArguments(func_get_args());
222
223
        // Prepare a default exception
224 2
        $e = new OutOfBoundsException(
225 2
            OutOfBoundsException::NO_MATCHING_PROPERTIES_STR,
226 2
            OutOfBoundsException::NO_MATCHING_PROPERTIES
227
        );
228
229
        // Run through all properties
230 2
        foreach ($properties as $property) {
231
            try {
232 2
                return (array)$this->getProperty($property->name, $property->profile);
233 1
            } catch (OutOfBoundsException $e) {
234 1
                continue;
235
            }
236
        }
237
238 1
        throw $e;
239
    }
240
241
    /**
242
     * Return all properties
243
     *
244
     * @return PropertyListInterface Properties
245
     * @api
246
     */
247 1
    public function getProperties()
248
    {
249 1
        $propertyList = (new PropertyListFactory())->create();
250 1
        foreach ($this->item->getProperties() as $propertyName => $propertyValues) {
251 1
            $propertyList[$propertyName] = array_map([$this, 'getPropertyValue'], $propertyValues);
252
        }
253 1
        return $propertyList;
254
    }
255
256
    /**
257
     * Return an object representation of the item
258
     *
259
     * @return \stdClass Micro information item
260
     * @api
261
     */
262 2
    public function toObject()
263
    {
264 2
        return $this->item->export();
265
    }
266
267
    /**
268
     * Get the item type
269
     *
270
     * @return \stdClass[] Item type
271
     * @api
272
     */
273 1
    public function getType()
274
    {
275 1
        return $this->item->getType();
276
    }
277
278
    /**
279
     * Get the item format
280
     *
281
     * @return int Item format
282
     * @api
283
     */
284 1
    public function getFormat()
285
    {
286 1
        return $this->item->getFormat();
287
    }
288
289
    /**
290
     * Get the item ID
291
     *
292
     * @return string Item ID
293
     * @api
294
     */
295 1
    public function getId()
296
    {
297 1
        return $this->item->getId();
298
    }
299
300
    /**
301
     * Get the item language
302
     *
303
     * @return string Item language
304
     * @api
305
     */
306 1
    public function getLanguage()
307
    {
308 1
        return $this->item->getLanguage();
309
    }
310
311
    /**
312
     * Return the item value
313
     *
314
     * @return string Item value
315
     * @api
316
     */
317 1
    public function getValue()
318
    {
319 1
        return $this->item->getValue();
320
    }
321
}
322