MappingFactory   B
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 283
Duplicated Lines 18.37 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 11
Bugs 0 Features 1
Metric Value
wmc 36
c 11
b 0
f 1
lcom 1
cbo 2
dl 52
loc 283
rs 8.8

12 Methods

Rating   Name   Duplication   Size   Complexity  
B fromClass() 0 36 5
A fromArray() 0 22 3
A getClass() 0 10 2
A getSelfUrl() 10 10 2
A getIdProperties() 0 4 2
A setAliasedProperties() 17 17 4
B getClassProperties() 0 21 5
A setHideProperties() 17 17 4
A setRelationships() 0 18 4
A setCuries() 0 6 2
A setProperties() 0 4 1
A getOtherUrls() 8 8 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * Author: Nil Portugués Calderó <[email protected]>
5
 * Date: 7/26/15
6
 * Time: 12:11 PM.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace NilPortugues\Api\Mapping;
12
13
use NilPortugues\Api\Mappings\ApiMapping;
14
use NilPortugues\Api\Mappings\HalMapping;
15
use NilPortugues\Api\Mappings\JsonApiMapping;
16
use ReflectionClass;
17
18
/**
19
 * Class MappingFactory.
20
 */
21
class MappingFactory
22
{
23
    const CLASS_KEY = 'class';
24
    const ALIAS_KEY = 'alias';
25
    const ALIASED_PROPERTIES_KEY = 'aliased_properties';
26
    const HIDE_PROPERTIES_KEY = 'hide_properties';
27
    const ID_PROPERTIES_KEY = 'id_properties';
28
    const URLS_KEY = 'urls';
29
    const CURIES_KEY = 'curies';
30
    const RELATIONSHIPS_KEY = 'relationships';
31
    const SELF_KEY = 'self';
32
33
    /**
34
     * @var array
35
     */
36
    protected static $classProperties = [];
37
38
    /**
39
     * @param string $className
40
     *
41
     * @throws MappingException
42
     *
43
     * @return Mapping
44
     *
45
     * @since 2.0.0
46
     */
47
    public static function fromClass($className)
48
    {
49
        /* @var ApiMapping|HalMapping|JsonApiMapping $instance */
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
50
        $className = '\\'.ltrim($className, '\\');
51
        if (!class_exists($className, true)) {
52
            throw new MappingException(
53
                \sprintf('Provided class %s could not be loaded.', $className)
54
            );
55
        }
56
        $instance = new $className();
57
58
        if (!in_array(ApiMapping::class, \class_implements($instance, true))) {
59
            throw new MappingException(
60
                \sprintf('Class %s must implement %s.', \ltrim($className, '\\'), ApiMapping::class)
61
            );
62
        }
63
64
        $mappedClass = [
65
            static::CLASS_KEY => $instance->getClass(),
66
            static::ALIAS_KEY => $instance->getAlias(),
67
            static::ALIASED_PROPERTIES_KEY => $instance->getAliasedProperties(),
68
            static::HIDE_PROPERTIES_KEY => $instance->getHideProperties(),
69
            static::ID_PROPERTIES_KEY => $instance->getIdProperties(),
70
            static::URLS_KEY => $instance->getUrls(),
71
        ];
72
73
        if (\in_array(HalMapping::class, \class_implements($instance, true))) {
74
            $mappedClass[static::CURIES_KEY] = $instance->getCuries();
75
        }
76
77
        if (\in_array(JsonApiMapping::class, \class_implements($instance, true))) {
78
            $mappedClass[static::RELATIONSHIPS_KEY] = $instance->getRelationships();
79
        }
80
81
        return static::fromArray($mappedClass);
82
    }
83
84
    /**
85
     * @param array $mappedClass
86
     *
87
     * @throws MappingException
88
     *
89
     * @return Mapping
90
     */
91
    public static function fromArray(array &$mappedClass)
92
    {
93
        $className = static::getClass($mappedClass);
94
        $resourceUrl = static::getSelfUrl($mappedClass);
95
        $idProperties = static::getIdProperties($mappedClass);
96
97
        $mapping = new Mapping($className, $resourceUrl, $idProperties);
98
        $mapping->setClassAlias((empty($mappedClass[static::ALIAS_KEY])) ? $className : $mappedClass[static::ALIAS_KEY]);
99
100
        static::setAliasedProperties($mappedClass, $mapping, $className);
101
        static::setHideProperties($mappedClass, $mapping, $className);
102
        static::setRelationships($mappedClass, $mapping, $className);
103
        static::setCuries($mappedClass, $mapping);
104
        static::setProperties($mapping, $className);
105
106
        $otherUrls = static::getOtherUrls($mappedClass);
107
        if (!empty($otherUrls)) {
108
            $mapping->setUrls($otherUrls);
109
        }
110
111
        return $mapping;
112
    }
113
114
    /**
115
     * @param array $mappedClass
116
     *
117
     * @throws MappingException
118
     *
119
     * @return mixed
120
     */
121
    protected static function getClass(array &$mappedClass)
122
    {
123
        if (empty($mappedClass[static::CLASS_KEY])) {
124
            throw new MappingException(
125
                'Could not find "class" property. This is required for class to be mapped'
126
            );
127
        }
128
129
        return $mappedClass[static::CLASS_KEY];
130
    }
131
132
    /**
133
     * @param array $mappedClass
134
     *
135
     * @throws MappingException
136
     *
137
     * @return mixed
138
     */
139 View Code Duplication
    protected static function getSelfUrl(array &$mappedClass)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
    {
141
        if (empty($mappedClass[static::URLS_KEY][static::SELF_KEY])) {
142
            throw new MappingException(
143
                'Could not find "self" property under "urls". This is required in order to make the resource to be reachable.'
144
            );
145
        }
146
147
        return $mappedClass[static::URLS_KEY][static::SELF_KEY];
148
    }
149
150
    /**
151
     * @param array $mappedClass
152
     *
153
     * @return mixed
154
     */
155
    protected static function getIdProperties(array &$mappedClass)
156
    {
157
        return (!empty($mappedClass[static::ID_PROPERTIES_KEY])) ? $mappedClass[static::ID_PROPERTIES_KEY] : [];
158
    }
159
160
    /**
161
     * @param array   $mappedClass
162
     * @param Mapping $mapping
163
     * @param string  $className
164
     *
165
     * @throws MappingException
166
     */
167 View Code Duplication
    protected static function setAliasedProperties(array &$mappedClass, Mapping $mapping, $className)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
    {
169
        if (false === empty($mappedClass[static::ALIASED_PROPERTIES_KEY])) {
170
            $mapping->setPropertyNameAliases($mappedClass[static::ALIASED_PROPERTIES_KEY]);
171
            foreach (\array_keys($mapping->getAliasedProperties()) as $propertyName) {
172
                if (false === \in_array($propertyName, static::getClassProperties($className), true)) {
173
                    throw new MappingException(
174
                        \sprintf(
175
                            'Could not alias property %s in class %s because it does not exist.',
176
                            $propertyName,
177
                            $className
178
                        )
179
                    );
180
                }
181
            }
182
        }
183
    }
184
185
    /**
186
     * Recursive function to get an associative array of class properties by
187
     * property name, including inherited ones from extended classes.
188
     *
189
     * @param string $className Class name
190
     *
191
     * @return array
192
     *
193
     * @link http://php.net/manual/es/reflectionclass.getproperties.php#88405
194
     */
195
    protected static function getClassProperties($className)
196
    {
197
        if (empty(static::$classProperties[$className])) {
198
            $ref = new ReflectionClass($className);
199
            $properties = [];
200
            foreach ($ref->getProperties() as $prop) {
201
                $f = $prop->getName();
202
                $properties[$f] = $prop;
203
            }
204
205
            if ($parentClass = $ref->getParentClass()) {
206
                $parentPropsArr = static::getClassProperties($parentClass->getName());
207
                if (\count($parentPropsArr) > 0) {
208
                    $properties = \array_merge($parentPropsArr, $properties);
209
                }
210
            }
211
            static::$classProperties[$className] = \array_keys($properties);
212
        }
213
214
        return static::$classProperties[$className];
215
    }
216
217
    /**
218
     * @param array   $mappedClass
219
     * @param Mapping $mapping
220
     * @param string  $className
221
     *
222
     * @throws MappingException
223
     */
224 View Code Duplication
    protected static function setHideProperties(array &$mappedClass, Mapping $mapping, $className)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
    {
226
        if (false === empty($mappedClass[static::HIDE_PROPERTIES_KEY])) {
227
            $mapping->setHiddenProperties($mappedClass[static::HIDE_PROPERTIES_KEY]);
228
            foreach ($mapping->getHiddenProperties() as $propertyName) {
229
                if (false === \in_array($propertyName, static::getClassProperties($className), true)) {
230
                    throw new MappingException(
231
                        \sprintf(
232
                            'Could not hide property %s in class %s because it does not exist.',
233
                            $propertyName,
234
                            $className
235
                        )
236
                    );
237
                }
238
            }
239
        }
240
    }
241
242
    /**
243
     * @param array   $mappedClass
244
     * @param Mapping $mapping
245
     * @param string  $className
246
     *
247
     * @throws MappingException
248
     */
249
    protected static function setRelationships(array &$mappedClass, Mapping $mapping, $className)
250
    {
251
        if (!empty($mappedClass[static::RELATIONSHIPS_KEY])) {
252
            foreach ($mappedClass[static::RELATIONSHIPS_KEY] as $propertyName => $urls) {
253
                if (false === \in_array($propertyName, static::getClassProperties($className))) {
254
                    throw new MappingException(
255
                        \sprintf(
256
                            'Could not find property %s in class %s because it does not exist.',
257
                            $propertyName,
258
                            $className
259
                        )
260
                    );
261
                }
262
263
                $mapping->setRelationshipUrls($propertyName, $urls);
264
            }
265
        }
266
    }
267
268
    /**
269
     * @param array   $mappedClass
270
     * @param Mapping $mapping
271
     */
272
    protected static function setCuries(array &$mappedClass, Mapping $mapping)
273
    {
274
        if (false === empty($mappedClass[static::CURIES_KEY])) {
275
            $mapping->setCuries($mappedClass[static::CURIES_KEY]);
276
        }
277
    }
278
279
    /**
280
     * @param Mapping $mapping
281
     * @param string  $className
282
     *
283
     * @throws MappingException
284
     */
285
    protected static function setProperties(Mapping $mapping, $className)
286
    {
287
        $mapping->setProperties(static::getClassProperties($className));
288
    }
289
290
    /**
291
     * @param array $mappedClass
292
     *
293
     * @return mixed
294
     */
295 View Code Duplication
    protected static function getOtherUrls(array $mappedClass)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296
    {
297
        if (!empty($mappedClass[static::URLS_KEY][static::SELF_KEY])) {
298
            unset($mappedClass[static::URLS_KEY][static::SELF_KEY]);
299
        }
300
301
        return $mappedClass[static::URLS_KEY];
302
    }
303
}
304