Failed Conditions
Push — master ( d49c03...6343d0 )
by Bernhard
05:03
created

ModuleFileConverter   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 258
Duplicated Lines 5.81 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 97.6%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 15
loc 258
wmc 49
lcom 1
cbo 10
ccs 122
cts 125
cp 0.976
rs 8.5454

5 Methods

Rating   Name   Duplication   Size   Complexity  
A compareBindingDescriptors() 0 5 1
A toJson() 15 15 1
A fromJson() 0 10 2
D addModuleFileToJson() 0 111 22
D addJsonToModuleFile() 0 84 23

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ModuleFileConverter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ModuleFileConverter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the puli/manager package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Manager\Module;
13
14
use Puli\Discovery\Api\Type\BindingParameter;
15
use Puli\Discovery\Api\Type\BindingType;
16
use Puli\Discovery\Binding\ClassBinding;
17
use Puli\Discovery\Binding\ResourceBinding;
18
use Puli\Manager\Api\Discovery\BindingDescriptor;
19
use Puli\Manager\Api\Discovery\BindingTypeDescriptor;
20
use Puli\Manager\Api\Module\ModuleFile;
21
use Puli\Manager\Api\Repository\PathMapping;
22
use Puli\Manager\Assert\Assert;
23
use Rhumsaa\Uuid\Uuid;
24
use stdClass;
25
use Webmozart\Json\Conversion\JsonConverter;
26
27
/**
28
 * Converts module files to JSON and back.
29
 *
30
 * @since  1.0
31
 *
32
 * @author Bernhard Schussek <[email protected]>
33
 */
34
class ModuleFileConverter implements JsonConverter
35
{
36
    /**
37
     * The JSON version this converter supports.
38
     */
39
    const VERSION = '1.0';
40
41
    /**
42
     * The default order of the keys in the written module file.
43
     *
44
     * @var string[]
45
     */
46
    private static $keyOrder = array(
47
        'version',
48
        'name',
49
        'path-mappings',
50
        'bindings',
51
        'binding-types',
52
        'override',
53
        'extra',
54
    );
55
56 3
    public static function compareBindingDescriptors(BindingDescriptor $a, BindingDescriptor $b)
57
    {
58
        // Make sure that bindings are always printed in the same order
59 3
        return strcmp($a->getUuid()->toString(), $b->getUuid()->toString());
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65 14 View Code Duplication
    public function toJson($moduleFile, array $options = array())
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...
66
    {
67 14
        Assert::isInstanceOf($moduleFile, 'Puli\Manager\Api\Module\ModuleFile');
68
69 14
        $jsonData = new stdClass();
70
71 14
        $this->addModuleFileToJson($moduleFile, $jsonData);
72
73
        // Sort according to key order
74 14
        $jsonArray = (array) $jsonData;
75 14
        $orderedKeys = array_intersect_key(array_flip(self::$keyOrder), $jsonArray);
76 14
        $jsonData = (object) array_replace($orderedKeys, $jsonArray);
77
78 14
        return $jsonData;
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 22
    public function fromJson($jsonData, array $options = array())
85
    {
86 22
        Assert::isInstanceOf($jsonData, 'stdClass');
87
88 22
        $moduleFile = new ModuleFile(null, isset($options['path']) ? $options['path'] : null);
89
90 22
        $this->addJsonToModuleFile($jsonData, $moduleFile);
91
92 22
        return $moduleFile;
93
    }
94
95 20
    protected function addModuleFileToJson(ModuleFile $moduleFile, stdClass $jsonData)
96
    {
97 20
        $mappings = $moduleFile->getPathMappings();
98 20
        $bindingDescriptors = $moduleFile->getBindingDescriptors();
99 20
        $typeDescriptors = $moduleFile->getTypeDescriptors();
100 20
        $overrides = $moduleFile->getOverriddenModules();
101 20
        $extra = $moduleFile->getExtraKeys();
102
103 20
        if (null !== $moduleFile->getModuleName()) {
104 2
            $jsonData->name = $moduleFile->getModuleName();
105
        }
106
107 20
        if (count($mappings) > 0) {
108 4
            $jsonData->{'path-mappings'} = new stdClass();
109
110 4
            foreach ($mappings as $mapping) {
111 4
                $puliPath = $mapping->getRepositoryPath();
112 4
                $localPaths = $mapping->getPathReferences();
113
114 4
                $jsonData->{'path-mappings'}->$puliPath = count($localPaths) > 1 ? $localPaths : reset($localPaths);
115
            }
116
        }
117
118 20
        if (count($bindingDescriptors) > 0) {
119 6
            uasort($bindingDescriptors, array(__CLASS__, 'compareBindingDescriptors'));
120
121 6
            $jsonData->bindings = new stdClass();
122
123 6
            foreach ($bindingDescriptors as $bindingDescriptor) {
124 6
                $binding = $bindingDescriptor->getBinding();
125 6
                $bindingData = new stdClass();
126 6
                $bindingData->_class = get_class($binding);
127
128
                // This needs to be moved to external classes to allow adding
129
                // custom binding classes at some point
130 6
                if ($binding instanceof ResourceBinding) {
131 6
                    $bindingData->query = $binding->getQuery();
132
133 6
                    if ('glob' !== $binding->getLanguage()) {
134 6
                        $bindingData->language = $binding->getLanguage();
135
                    }
136
                } elseif ($binding instanceof ClassBinding) {
137 3
                    $bindingData->class = $binding->getClassName();
138
                }
139
140 6
                $bindingData->type = $bindingDescriptor->getTypeName();
141
142
                // Don't include the default values of the binding type
143 6
                if ($binding->hasParameterValues(false)) {
144 1
                    $parameterData = $binding->getParameterValues(false);
145 1
                    ksort($parameterData);
146 1
                    $bindingData->parameters = (object) $parameterData;
147
                }
148
149 6
                $jsonData->bindings->{$bindingDescriptor->getUuid()->toString()} = $bindingData;
150
            }
151
        }
152
153 20
        if (count($typeDescriptors) > 0) {
154 8
            $bindingTypesData = array();
155
156 8
            foreach ($typeDescriptors as $typeDescriptor) {
157 8
                $type = $typeDescriptor->getType();
158 8
                $typeData = new stdClass();
159
160 8
                if ($typeDescriptor->getDescription()) {
161 2
                    $typeData->description = $typeDescriptor->getDescription();
162
                }
163
164 8
                if ($type->hasParameters()) {
165 6
                    $parametersData = array();
166
167 6
                    foreach ($type->getParameters() as $parameter) {
168 6
                        $parameterData = new stdClass();
169
170 6
                        if ($typeDescriptor->hasParameterDescription($parameter->getName())) {
171 3
                            $parameterData->description = $typeDescriptor->getParameterDescription($parameter->getName());
172
                        }
173
174 6
                        if ($parameter->isRequired()) {
175 1
                            $parameterData->required = true;
176
                        }
177
178 6
                        if (null !== $parameter->getDefaultValue()) {
179 3
                            $parameterData->default = $parameter->getDefaultValue();
180
                        }
181
182 6
                        $parametersData[$parameter->getName()] = $parameterData;
183
                    }
184
185 6
                    ksort($parametersData);
186
187 6
                    $typeData->parameters = (object) $parametersData;
188
                }
189
190 8
                $bindingTypesData[$type->getName()] = $typeData;
191
            }
192
193 8
            ksort($bindingTypesData);
194
195 8
            $jsonData->{'binding-types'} = (object) $bindingTypesData;
196
        }
197
198 20
        if (count($overrides) > 0) {
199 3
            $jsonData->override = count($overrides) > 1 ? $overrides : reset($overrides);
200
        }
201
202 20
        if (count($extra) > 0) {
203 2
            $jsonData->extra = (object) $extra;
204
        }
205 20
    }
206
207 38
    protected function addJsonToModuleFile(stdClass $jsonData, ModuleFile $moduleFile)
208
    {
209 38
        if (isset($jsonData->name)) {
210 28
            $moduleFile->setModuleName($jsonData->name);
211
        }
212
213 38
        if (isset($jsonData->{'path-mappings'})) {
214 2
            foreach ($jsonData->{'path-mappings'} as $path => $relativePaths) {
215 2
                $moduleFile->addPathMapping(new PathMapping($path, (array) $relativePaths));
216
            }
217
        }
218
219 38
        if (isset($jsonData->bindings)) {
220 6
            foreach ($jsonData->bindings as $uuid => $bindingData) {
221 6
                $binding = null;
0 ignored issues
show
Unused Code introduced by
$binding is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
222 6
                $class = isset($bindingData->_class)
223 4
                    ? $bindingData->_class
224 6
                    : 'Puli\Discovery\Binding\ResourceBinding';
225
226
                // Move this code to external classes to allow use of custom
227
                // bindings
228
                switch ($class) {
229 6
                    case 'Puli\Discovery\Binding\ClassBinding':
230 3
                        $binding = new ClassBinding(
231 3
                            $bindingData->class,
232 3
                            $bindingData->type,
233 3
                            isset($bindingData->parameters) ? (array) $bindingData->parameters : array(),
234 3
                            Uuid::fromString($uuid)
235
                        );
236 3
                        break;
237
                    case 'Puli\Discovery\Binding\ResourceBinding':
238 5
                        $binding = new ResourceBinding(
239 5
                            $bindingData->query,
240 5
                            $bindingData->type,
241 5
                            isset($bindingData->parameters) ? (array) $bindingData->parameters : array(),
242 5
                            isset($bindingData->language) ? $bindingData->language : 'glob',
243 5
                            Uuid::fromString($uuid)
244
                        );
245 5
                        break;
246
                    default:
247
                        continue 2;
248
                }
249
250 6
                $moduleFile->addBindingDescriptor(new BindingDescriptor($binding));
251
            }
252
        }
253
254 38
        if (isset($jsonData->{'binding-types'})) {
255 3
            foreach ((array) $jsonData->{'binding-types'} as $typeName => $data) {
256 3
                $parameters = array();
257 3
                $parameterDescriptions = array();
258
259 3
                if (isset($data->parameters)) {
260 3
                    foreach ((array) $data->parameters as $parameterName => $parameterData) {
261 3
                        $required = isset($parameterData->required) ? $parameterData->required : false;
262
263 3
                        $parameters[] = new BindingParameter(
264
                            $parameterName,
265 3
                            $required ? BindingParameter::REQUIRED : BindingParameter::OPTIONAL,
266 3
                            isset($parameterData->default) ? $parameterData->default : null
267
                        );
268
269 3
                        if (isset($parameterData->description)) {
270 3
                            $parameterDescriptions[$parameterName] = $parameterData->description;
271
                        };
272
                    }
273
                }
274
275 3
                $moduleFile->addTypeDescriptor(new BindingTypeDescriptor(
276 3
                    new BindingType($typeName, $parameters),
277 3
                    isset($data->description) ? $data->description : null,
278
                    $parameterDescriptions
279
                ));
280
            }
281
        }
282
283 38
        if (isset($jsonData->override)) {
284 2
            $moduleFile->setOverriddenModules((array) $jsonData->override);
285
        }
286
287 38
        if (isset($jsonData->extra)) {
288 2
            $moduleFile->setExtraKeys((array) $jsonData->extra);
289
        }
290 38
    }
291
}
292