ItemFactory   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 6
dl 0
loc 221
ccs 60
cts 60
cp 1
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A processPropertyValue() 0 15 4
A normalizeEmptyValue() 0 4 2
A getProperties() 0 11 4
A processProperty() 0 13 4
A validatePropertyStructure() 0 4 4
A getPropertyValues() 0 12 2
A processLanguageTaggedPropertyValue() 0 18 4
A __invoke() 0 20 2
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category   Jkphl
7
 * @package    Jkphl\Micrometa
8
 * @subpackage Jkphl\Micrometa\Application
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\Application\Factory;
38
39
use Jkphl\Micrometa\Application\Contract\ValueInterface;
40
use Jkphl\Micrometa\Application\Exceptions\InvalidArgumentException;
41
use Jkphl\Micrometa\Application\Item\Item;
42
use Jkphl\Micrometa\Application\Item\ItemInterface;
43
use Jkphl\Micrometa\Application\Value\AlternateValues;
44
use Jkphl\Micrometa\Application\Value\StringValue;
45
use Jkphl\Micrometa\Ports\Exceptions\RuntimeException;
46
47
/**
48
 * Item factory
49
 *
50
 * @package    Jkphl\Micrometa
51
 * @subpackage Jkphl\Micrometa\Application
52
 */
53
class ItemFactory
54
{
55
    /**
56
     * Parser format
57
     *
58
     * @var int
59
     */
60
    protected $format;
61
    /**
62
     * Property lit factory
63
     *
64
     * @var PropertyListFactoryInterface
65
     */
66
    protected $propertyListFactory;
67
68
    /**
69
     * Item factory constructor
70
     *
71
     * @param int $format Parser format
72
     */
73 20
    public function __construct($format)
74
    {
75 20
        $this->format              = $format;
76 20
        $this->propertyListFactory = new PropertyListFactory();
77 20
    }
78
79
    /**
80
     * Prepare a single property value
81
     *
82
     * @param mixed $propertyValue Property Value
83
     *
84
     * @return ValueInterface Value
85
     */
86 15
    protected function processPropertyValue($propertyValue)
87
    {
88
        // If this is an item value
89 15
        if (is_object($propertyValue) && isset($propertyValue->type)) {
90 9
            return $this->__invoke($propertyValue);
91
92
            // Else these are alternate values
93 15
        } elseif (is_array($propertyValue)) {
94 2
            return new AlternateValues(array_map([$this, __METHOD__], $propertyValue));
95
        }
96
97 15
        list($propertyValue, $language) = $this->processLanguageTaggedPropertyValue($propertyValue);
98
99 14
        return new StringValue($propertyValue, $language);
100
    }
101
102
    /**
103
     * Create an item instance
104
     *
105
     * The item object is expected to be layed out like this:
106
     *
107
     * {
108
     *     format: 2, // Parser formag
109
     *     type: 'type', // String / IRI object (see below) or list of strings / IRI objects
110
     *     properties: [...], // List of item property objects (see below)
111
     *     value: 'Item value', // Item value (optional)
112
     *     id: 'item-1', // Item ID (optional)
113
     *     children: [...] // Nested item objects (optional)
114
     * }
115
     *
116
     * The item property objects are expected to be layed out like this:
117
     *
118
     * {
119
     *      name: 'name', // Property name
120
     *      profile: 'http://microformats.org/profile/', // Profile
121
     *      values: [...] // List of property values
122
     * }
123
     *
124
     * Item property values may be either
125
     *
126
     * - a string: Interpreted as simple value
127
     * - an array: Interpreted as alternate simple values
128
     * - an object: Interpreted as an object property (recursively processed)
129
     *
130
     * IRI objects are expected to be layed out like this:
131
     *
132
     * {
133
     *      name: 'h-entry',
134
     *      profile: 'http://microformats.org/profile/', // Profile (optional)
135
     * }
136
     *
137
     * @param \stdClass $item Raw item
138
     *
139
     * @return ItemInterface Item instance
140
     */
141 19
    public function __invoke(\stdClass $item)
142
    {
143 19
        $type         = $this->normalizeEmptyValue($item, 'type');
144 19
        $itemId       = $this->normalizeEmptyValue($item, 'id');
145 19
        $itemLanguage = $this->normalizeEmptyValue($item, 'lang');
146 19
        $value        = $this->normalizeEmptyValue($item, 'value');
147 19
        $children     = isset($item->children) ? array_map([$this, __METHOD__], $item->children) : [];
148 19
        $properties   = $this->getProperties($item);
149
150 18
        return new Item(
151 18
            $this->format,
152 18
            $this->propertyListFactory,
153 18
            $type,
154 18
            $properties,
155 18
            $children,
156 18
            $itemId,
157 18
            $itemLanguage,
158 18
            $value
159
        );
160
    }
161
162
    /**
163
     * Normalize an empty item value
164
     *
165
     * @param \stdClass $item  Item
166
     * @param string $property Property name
167
     *
168
     * @return string|null Normalized property value
169
     */
170 19
    protected function normalizeEmptyValue(\stdClass $item, $property)
171
    {
172 19
        return isset($item->$property) ? $item->$property : null;
173
    }
174
175
    /**
176
     * Prepare item properties
177
     *
178
     * @param \stdClass $item Item
179
     *
180
     * @return array Properties
181
     */
182 19
    protected function getProperties(\stdClass $item)
183
    {
184 19
        $properties = [];
185 19
        if (isset($item->properties) && is_array($item->properties)) {
186 18
            foreach ($item->properties as $property) {
187 17
                $this->processProperty($properties, $property);
188
            }
189
        }
190
191 18
        return $properties;
192
    }
193
194
    /**
195
     * Process a property
196
     *
197
     * @param array $properties   Properties
198
     * @param \stdClass $property Property
199
     */
200 17
    protected function processProperty(array &$properties, $property)
201
    {
202
        try {
203 17
            if ($this->validatePropertyStructure($property)) {
204 16
                $property->values = $this->getPropertyValues($property->values);
205 14
                if (count($property->values)) {
206 15
                    $properties[] = $property;
207
                }
208
            }
209 2
        } catch (InvalidArgumentException $exception) {
210
            // Skip this property
211
        }
212 16
    }
213
214
    /**
215
     * Validate if an object is a valid property
216
     *
217
     * @param \stdClass $property Property
218
     *
219
     * @return bool Is a valid property
220
     */
221 17
    protected function validatePropertyStructure($property)
222
    {
223 17
        return is_object($property) && isset($property->profile) && isset($property->name) && isset($property->values);
224
    }
225
226
    /**
227
     * Prepare item property values
228
     *
229
     * @param array $propertyValues Property values
230
     *
231
     * @return array Expanded property values
232
     * @throws InvalidArgumentException If it's not a list of property values
233
     */
234 16
    protected function getPropertyValues($propertyValues)
235
    {
236
        // If it's not a list of property values
237 16
        if (!is_array($propertyValues)) {
238 1
            throw new InvalidArgumentException(
239 1
                InvalidArgumentException::INVALID_PROPERTY_VALUES_STR,
240 1
                InvalidArgumentException::INVALID_PROPERTY_VALUES
241
            );
242
        }
243
244 15
        return array_map([$this, 'processPropertyValue'], $propertyValues);
245
    }
246
247
    /**
248
     * Process a language tagged property value
249
     *
250
     * @param string|\stdClass $propertyValue Property value
251
     *
252
     * @return array Language and property value
253
     * @throws RuntimeException If this is an invalid language tagged value
254
     */
255 15
    protected function processLanguageTaggedPropertyValue($propertyValue)
256
    {
257 15
        $language = null;
258 15
        if (is_object($propertyValue)) {
259
            // If this is an invalid language tagged object
260 3
            if (!isset($propertyValue->lang) || !isset($propertyValue->value)) {
261 1
                throw new RuntimeException(
262 1
                    RuntimeException::INVALID_LANGUAGE_TAGGED_VALUE_STR,
263 1
                    RuntimeException::INVALID_LANGUAGE_TAGGED_VALUE
264
                );
265
            }
266
267 2
            $language      = $propertyValue->lang;
268 2
            $propertyValue = $propertyValue->value;
269
        }
270
271 14
        return [$propertyValue, $language];
272
    }
273
}
274