Completed
Push — master ( 95e445...ca4763 )
by Joschi
03:42 queued 01:06
created

Item::getValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 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 © 2018 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 © 2018 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
     *
83
     * @return ValueInterface|ValueInterface[]|array|ItemInterface First value of an item property
84
     * @api
85
     */
86 2
    public function __get($name)
87
    {
88 2
        return $this->getProperty($name, null, 0);
89
    }
90
91
    /**
92
     * Get a single property (value)
93
     *
94
     * @param string|\stdClass|Iri $name Property name
95
     * @param string $profile            Property profile
96
     * @param int|null $index            Property value index
97
     *
98
     * @return ValueInterface|ValueInterface[]|array|ItemInterface Property value(s)
99
     * @throws OutOfBoundsException If the property name is unknown
100
     * @throws OutOfBoundsException If the property value index is out of bounds
101
     * @api
102
     */
103 7
    public function getProperty($name, $profile = null, $index = null)
104
    {
105
        try {
106 7
            $propertyValues = $this->item->getProperty($name, $profile);
107 4
        } catch (DomainOutOfBoundsException $exception) {
108 4
            throw new OutOfBoundsException($exception->getMessage(), $exception->getCode());
109
        }
110
111
        // Return the value(s)
112 7
        return ($index === null) ?
113 7
            array_map([$this, 'getPropertyValue'], $propertyValues) : $this->getPropertyIndex($propertyValues, $index);
114
    }
115
116
    /**
117
     * Return a particular property index
118
     *
119
     * @param ValueInterface[] $propertyValues Property values
120
     * @param int $index                       Property value index
121
     *
122
     * @return ValueInterface|ItemInterface
123
     */
124 6
    protected function getPropertyIndex(array $propertyValues, $index)
125
    {
126
        // If the property value index is out of bounds
127 6
        if (!isset($propertyValues[$index])) {
128 1
            throw new OutOfBoundsException(
129 1
                sprintf(OutOfBoundsException::INVALID_PROPERTY_VALUE_INDEX_STR, $index),
130 1
                OutOfBoundsException::INVALID_PROPERTY_VALUE_INDEX
131
            );
132
        }
133
134 5
        return $this->getPropertyValue($propertyValues[$index]);
135
    }
136
137
    /**
138
     * Prepare a property value for returning it
139
     *
140
     * @param ValueInterface $value Property value
141
     *
142
     * @return ValueInterface|ItemInterface Returnable property value
143
     */
144 7
    protected function getPropertyValue(ValueInterface $value)
145
    {
146 7
        return ($value instanceof ApplicationItemInterface) ?
147 7
            ItemFactory::createFromApplicationItem($value) : $value;
148
    }
149
150
    /**
151
     * Return whether the item is of a particular type (or contained in a list of types)
152
     *
153
     * The item type(s) can be specified in a variety of ways, @see ProfiledNamesFactory::createFromArguments()
154
     *
155
     * @param array ...$types Item types
156
     *
157
     * @return boolean Item type is contained in the list of types
158
     * @api
159
     */
160 5
    public function isOfType(...$types)
161
    {
162
        /** @var ProfiledNamesList $profiledTypes */
163 5
        $profiledTypes = ProfiledNamesFactory::createFromArguments($types);
164 5
        $aliasFactory  = new AliasFactory();
165
166
        // Run through all item types
167
        /** @var \stdClass $itemType */
168 5
        foreach ($this->item->getType() as $itemType) {
169 5
            $itemTypeNames = $aliasFactory->createAliases($itemType->name);
170 5
            if ($this->isOfProfiledTypes($itemType->profile, $itemTypeNames, $profiledTypes)) {
171 5
                return true;
172
            }
173
        }
174
175 3
        return false;
176
    }
177
178
    /**
179
     * Return whether an aliased item type is contained in a set of query types
180
     *
181
     * @param string $profile          Type profile
182
     * @param array $names             Aliased type names
183
     * @param ProfiledNamesList $types Query types
184
     *
185
     * @return bool Item type is contained in the set of query types
186
     */
187 5
    protected function isOfProfiledTypes($profile, array $names, ProfiledNamesList $types)
188
    {
189
        // Run through all query types
190
        /** @var \stdClass $queryType */
191 5
        foreach ($types as $queryType) {
192 5
            if ($this->isTypeInNames($queryType, $profile, $names)) {
193 5
                return true;
194
            }
195
        }
196
197 3
        return false;
198
    }
199
200
    /**
201
     * Test whether a type is contained in a list of names
202
     *
203
     * @param \stdClass $type Type
204
     * @param string $profile Type profile
205
     * @param array $names    Aliased type names
206
     *
207
     * @return bool Type is contained in names list
208
     */
209 5
    protected function isTypeInNames($type, $profile, array $names)
210
    {
211 5
        return in_array($type->name, $names) &&
212 5
               (($type->profile === null) ? true : ($type->profile == $profile));
213
    }
214
215
    /**
216
     * Get all values of the first available property in a stack
217
     *
218
     * The property stack can be specified in a variety of ways, @see ProfiledNamesFactory::createFromArguments()
219
     *
220
     * @param array $properties Properties
221
     *
222
     * @return ValueInterface[]|array Property values
223
     * @throws InvalidArgumentException If no property name was given
224
     * @throws OutOfBoundsException If none of the requested properties is known
225
     * @api
226
     */
227 2
    public function getFirstProperty(...$properties)
228
    {
229
        /** @var ProfiledNamesList $properties */
230 2
        $properties = ProfiledNamesFactory::createFromArguments(func_get_args());
231
232
        // Prepare a default exception
233 2
        $exception = new OutOfBoundsException(
234 2
            OutOfBoundsException::NO_MATCHING_PROPERTIES_STR,
235 2
            OutOfBoundsException::NO_MATCHING_PROPERTIES
236
        );
237
238
        // Run through all properties
239 2
        foreach ($properties as $property) {
240
            try {
241 2
                return (array)$this->getProperty($property->name, $property->profile);
242 1
            } catch (OutOfBoundsException $exception) {
243 1
                continue;
244
            }
245
        }
246
247 1
        throw $exception;
248
    }
249
250
    /**
251
     * Return all properties
252
     *
253
     * @return PropertyListInterface Properties
254
     * @api
255
     */
256 1
    public function getProperties()
257
    {
258 1
        $propertyList = (new PropertyListFactory())->create();
259 1
        foreach ($this->item->getProperties() as $propertyName => $propertyValues) {
260 1
            $propertyList[$propertyName] = array_map([$this, 'getPropertyValue'], $propertyValues);
261
        }
262
263 1
        return $propertyList;
264
    }
265
266
    /**
267
     * Return an object representation of the item
268
     *
269
     * @return \stdClass Micro information item
270
     * @api
271
     */
272 2
    public function toObject()
273
    {
274 2
        return $this->item->export();
275
    }
276
277
    /**
278
     * Get the item type
279
     *
280
     * @return \stdClass[] Item type
281
     * @api
282
     */
283 1
    public function getType()
284
    {
285 1
        return $this->item->getType();
286
    }
287
288
    /**
289
     * Get the item format
290
     *
291
     * @return int Item format
292
     * @api
293
     */
294 1
    public function getFormat()
295
    {
296 1
        return $this->item->getFormat();
297
    }
298
299
    /**
300
     * Get the item ID
301
     *
302
     * @return string Item ID
303
     * @api
304
     */
305 1
    public function getId()
306
    {
307 1
        return $this->item->getId();
308
    }
309
310
    /**
311
     * Get the item language
312
     *
313
     * @return string Item language
314
     * @api
315
     */
316 1
    public function getLanguage()
317
    {
318 1
        return $this->item->getLanguage();
319
    }
320
321
    /**
322
     * Return the item value
323
     *
324
     * @return string Item value
325
     * @api
326
     */
327 1
    public function getValue()
328
    {
329 1
        return $this->item->getValue();
330
    }
331
}
332