Completed
Push — refactor-to-hexagonal-and-tigh... ( a5838a...fd9b77 )
by Mike
09:10
created

JsonpRenderer::transformClass()   F

Complexity

Conditions 15
Paths 9216

Size

Total Lines 85
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 85
rs 2
cc 15
eloc 50
nc 9216
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Application\Renderer;
4
5
use DomainModel\Renderer;
6
use phpDocumentor\DomainModel\Path;
7
use phpDocumentor\DomainModel\Views\View;
8
9
/**
10
 * Writes the collected data as a series of JSONP files.
11
 *
12
 * This writer will create a series of JSONP files that represent all of the data collected by phpDocumentor on a
13
 * project. These JSONP files can then be exposed by an API, consumed by a Javascript framework or otherwise be
14
 * re-used.
15
 *
16
 * The original reason for creating this writer was to use it to fuel a Javascript framework based template and as
17
 * such some assumptions have been done in the layout that help with that goal. One of those has been the choice for
18
 * JSONP opposed to JSON as JSONP makes it possible to open the JSON content from a local file (`file://`) without
19
 * having issues with Cross-domain requests.
20
 *
21
 * Because these are static pre-generated files the callback name is not configurable via a query parameter $callback
22
 * as is usually the case but a fixed callback name is used for each individual file.
23
 *
24
 * The following files are generated:
25
 *
26
 * namespaces.json (callback name: `namespaces`)
27
 *     Contains a tree structure of all namespaces and has a listing of all child elements. Constants
28
 *     and functions have their complete contents included but classes, interfaces and traits only have
29
 *     an FQCN listed so that you can refer to another JSONP file.
30
 *
31
 * packages.json (callback name: `packages`)
32
 *     Contains a tree structure of all packages and has a listing of all child elements. Constants
33
 *     and functions have their complete contents included but classes, interfaces and traits only have
34
 *     an FQCN listed so that you can refer to another JSONP file.
35
 *
36
 * files/*.json (callback name: `fileDefinition`)
37
 *     The subfolder `files` will contain a JSONP file for each file in a project. This file contains a listing of all
38
 *     child elements. Constants and functions have their complete contents included but classes, interfaces and
39
 *     traits only have an FQCN listed so that you can refer to another JSONP file.
40
 *
41
 * classes/*.json (callback name: `classDefinition`)
42
 *     The subfolder `classes` will contain a JSONP file for each class, interface and trait in a project. Each file
43
 *     contains a listing of all properties and child elements for a class, interface or trait. This includes a
44
 *     member `type` that can be either 'class', 'interface' or 'trait' to distinguish between the three types
45
 *     of 'classes'.
46
 */
47
class JsonpRenderer implements Renderer
0 ignored issues
show
Complexity introduced by
This class has a complexity of 88 which exceeds the configured maximum of 50.

The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.

Some resources for further reading:

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

Loading history...
Complexity introduced by
The class JsonpRenderer has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
Loading history...
48
{
49
    public function render(View $view, Path $destination, $template = null)
50
    {
51
        // TODO: Implement render() method.
52
    }
53
54
    /**
55
     * Generate a series of JSONP files based on the ProjectDescriptor's structure in the target directory.
56
     *
57
     * This method is responsible for writing a series of JSONP files to disk in the directory specified by the
58
     * user when starting phpDocumentor. A complete description of what is generated can be found in the documentation
59
     * of this class itself.
60
     *
61
     * @param Jsonp $action
62
     *
63
     * @return void
64
     */
65
    public function handle(Action $action)
66
    {
67
        $project = $this->analyzer->getProjectDescriptor();
68
        $folder = $action->getRenderPass()->getDestination() . '/' . ltrim($action->getDestination(), '\\/');
69
        @mkdir($folder . 'classes');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
70
        @mkdir($folder . 'files');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
71
72
        // Generate namespaces json
73
        $namespaces = $this->getNamespaceTree($project->getNamespace());
74
        file_put_contents($folder . '/namespaces.json', 'namespaces(' . json_encode($namespaces) . ');');
75
76
        // Generate packages json
77
        $packages = $this->getPackageTree($project->getIndexes()->get('packages')->get('\\'));
78
        file_put_contents($folder . '/packages.json', 'packages(' . json_encode($packages) . ');');
79
80
        // Generate per-class json
81
        foreach ($project->getIndexes()->get('elements') as $element) {
82
            if ($element instanceof ClassDescriptor) {
0 ignored issues
show
Bug introduced by
The class Application\Renderer\ClassDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
83
                $this->writeClassToDisk($folder, $element, $this->transformClass($element));
84
                continue;
85
            }
86
            if ($element instanceof InterfaceDescriptor) {
0 ignored issues
show
Bug introduced by
The class Application\Renderer\InterfaceDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
87
                $this->writeClassToDisk($folder, $element, $this->transformInterface($element));
88
                continue;
89
            }
90
            if ($element instanceof TraitDescriptor) {
0 ignored issues
show
Bug introduced by
The class Application\Renderer\TraitDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
91
                $this->writeClassToDisk($folder, $element, $this->transformTrait($element));
92
                continue;
93
            }
94
        }
95
96
        // Generate files json
97
        foreach ($project->getFiles() as $file) {
98
            $this->writeFileToDisk($folder, $file, $this->transformFile($file));
99
        }
100
    }
101
102
    /**
103
     * Generates an associative array containing all properties and child elements for a file.
104
     *
105
     * @param FileDescriptor $element
106
     *
107
     * @return string[]
108
     */
109
    private function transformFile(FileDescriptor $element)
0 ignored issues
show
Complexity introduced by
This operation has 1280 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
110
    {
111
        $file = array(
112
            'name' => $element->getName(),
113
            'path' => $element->getPath(),
114
            'summary' => $element->getSummary(),
115
            'description' => $element->getDescription(),
116
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\PackageDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
117
                ? $element->getFullyQualifiedStructuralElementName()
118
                : (string)$element,
119
            'constants' => array(),
120
            'functions' => array(),
121
            'classes' => array(),
122
            'interfaces' => array(),
123
            'traits' => array(),
124
            'namespace-aliases' => array(),
125
            'markers' => array(),
126
        );
127
128
        foreach ($element->getNamespaceAliases() as $alias => $namespace) {
129
            $file['namespace-aliases'][$alias] = $namespace;
130
        }
131
132
        foreach ($element->getConstants() as $constant) {
133
            $file['constants'][] = $this->transformConstant($constant);
134
        }
135
        foreach ($element->getFunctions() as $function) {
136
            $file['functions'][] = $this->transformFunction($function);
137
        }
138
        /** @var TraitDescriptor $trait */
139
        foreach ($element->getTraits() as $trait) {
140
            $file['traits'][] = $trait->getFullyQualifiedStructuralElementName();
141
        }
142
        /** @var InterfaceDescriptor $interface */
143
        foreach ($element->getInterfaces() as $interface) {
144
            $file['interface'][] = $interface->getFullyQualifiedStructuralElementName();
145
        }
146
        /** @var ClassDescriptor $class */
147
        foreach ($element->getClasses() as $class) {
148
            $file['classes'][] = $class->getFullyQualifiedStructuralElementName();
149
        }
150
151
        foreach ($element->getMarkers() as $marker) {
152
            $file['markers'] = $marker;
153
        }
154
        foreach ($element->getAllErrors() as $error) {
155
            $file['errors'][] = $error;
156
        }
157
158
        return $file;
159
    }
160
161
    /**
162
     * Generates an associative array containing all properties and child elements for a class.
163
     *
164
     * @param ClassDescriptor $element
165
     *
166
     * @return string[]
167
     */
168
    private function transformClass(ClassDescriptor $element)
0 ignored issues
show
Complexity introduced by
This operation has 230400 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
169
    {
170
        $class = array(
171
            'type' => 'class',
172
            'name' => $element->getName(),
173
            'line' => $element->getLine(),
174
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
175
            'final' => $element->isFinal(),
176
            'abstract' => $element->isAbstract(),
177
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
178
            'summary' => $element->getSummary(),
179
            'description' => $element->getDescription(),
180
            'extends' => $element->getParent() instanceof ClassDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\ClassDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
181
                ? $element->getParent()->getFullyQualifiedStructuralElementName()
182
                : $element->getParent(),
183
            'implements' => array(),
184
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\PackageDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
185
                ? $element->getFullyQualifiedStructuralElementName()
186
                : (string)$element,
187
            'file' => $element->getFile()->getPath(),
188
            'uses' => array(),
189
            'constants' => array(),
190
            'methods' => array(),
191
            'properties' => array()
192
        );
193
194
        /** @var TraitDescriptor|string $trait */
195
        foreach ($element->getUsedTraits() as $trait) {
196
            $class['uses'][] = $trait instanceof TraitDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\TraitDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
197
                ? $trait->getFullyQualifiedStructuralElementName()
198
                : $trait;
199
        }
200
201
        /** @var InterfaceDescriptor $interface */
202
        foreach ($element->getInterfaces() as $interface) {
203
            $interfaceFqcn = is_string($interface)
204
                ? $interface
205
                : $interface->getFullyQualifiedStructuralElementName();
206
            $class['implements'][] = $interfaceFqcn;
207
        }
208
209
        /** @var ConstantDescriptor $constant */
210
        foreach ($element->getConstants() as $constant) {
211
            $class['constants'][] = $this->transformConstant($constant);
212
        }
213
214
        /** @var ConstantDescriptor $constant */
215
        foreach ($element->getInheritedConstants() as $constant) {
216
            $class['constants'][] = $this->transformConstant($constant);
217
        }
218
219
        /** @var PropertyDescriptor $property */
220
        foreach ($element->getProperties() as $property) {
221
            $class['properties'][] = $this->transformProperty($property);
222
        }
223
224
        /** @var PropertyDescriptor $property */
225
        foreach ($element->getInheritedProperties() as $property) {
226
            $class['properties'][] = $this->transformProperty($property);
227
        }
228
229
        /** @var PropertyDescriptor $property */
230
        foreach ($element->getMagicProperties() as $property) {
231
            $class['properties'][] = $this->transformProperty($property);
232
        }
233
234
        /** @var MethodDescriptor $method */
235
        foreach ($element->getMethods() as $method) {
236
            $class['methods'][] = $this->transformMethod($method);
237
        }
238
239
        /** @var MethodDescriptor $property */
240
        foreach ($element->getInheritedMethods() as $method) {
241
            $class['methods'][] = $this->transformMethod($method);
242
        }
243
244
        /** @var MethodDescriptor $property */
245
        foreach ($element->getMagicMethods() as $method) {
246
            $class['methods'][] = $this->transformMethod($method);
247
        }
248
249
        $class['tags'] = $this->transformTags($element);
250
251
        return $class;
252
    }
253
254
    /**
255
     * Generates an associative array containing all properties and child elements for an interface.
256
     *
257
     * @param InterfaceDescriptor $element
258
     *
259
     * @return string[]
260
     */
261
    private function transformInterface(InterfaceDescriptor $element)
0 ignored issues
show
Complexity introduced by
This operation has 480 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
262
    {
263
        $interface = array(
264
            'type' => 'interface',
265
            'name' => $element->getName(),
266
            'line' => $element->getLine(),
267
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
268
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
269
            'summary' => $element->getSummary(),
270
            'description' => $element->getDescription(),
271
            'extends' => array(),
272
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\PackageDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
273
                ? $element->getFullyQualifiedStructuralElementName()
274
                : (string)$element,
275
            'file' => $element->getFile()->getPath(),
276
            'constants' => array(),
277
            'methods' => array(),
278
        );
279
280
        /** @var InterfaceDescriptor $extendedInterface */
281
        foreach ($element->getParent() as $extendedInterface) {
282
            $interfaceFqcn = is_string($extendedInterface)
283
                ? $extendedInterface
284
                : $extendedInterface->getFullyQualifiedStructuralElementName();
285
            $interface['extends'][] = $interfaceFqcn;
286
        }
287
288
        /** @var ConstantDescriptor $property */
289
        foreach ($element->getConstants() as $constant) {
290
            $interface['constants'][] = $this->transformConstant($constant);
291
        }
292
293
        /** @var ConstantDescriptor $constant */
294
        foreach ($element->getInheritedConstants() as $constant) {
295
            $interface['constants'][] = $this->transformConstant($constant);
296
        }
297
298
        /** @var MethodDescriptor $method */
299
        foreach ($element->getMethods() as $method) {
300
            $interface['methods'][] = $this->transformMethod($method);
301
        }
302
303
        /** @var MethodDescriptor $property */
304
        foreach ($element->getInheritedMethods() as $method) {
305
            $interface['methods'][] = $this->transformMethod($method);
306
        }
307
308
        $interface['tags'] = $this->transformTags($element);
309
310
        return $interface;
311
    }
312
313
    /**
314
     * Generates an associative array containing all properties and child elements for a trait.
315
     *
316
     * @param TraitDescriptor $element
317
     *
318
     * @return string[]
319
     */
320
    private function transformTrait(TraitDescriptor $element)
0 ignored issues
show
Complexity introduced by
This operation has 1920 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
321
    {
322
        $trait = array(
323
            'type' => 'trait',
324
            'name' => $element->getName(),
325
            'line' => $element->getLine(),
326
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
327
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
328
            'summary' => $element->getSummary(),
329
            'description' => $element->getDescription(),
330
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\PackageDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
331
                ? $element->getFullyQualifiedStructuralElementName()
332
                : (string)$element,
333
            'file' => $element->getFile()->getPath(),
334
            'uses' => array(),
335
            'constants' => array(),
336
            'methods' => array(),
337
        );
338
339
        /** @var TraitDescriptor|string $usedTrait */
340
        foreach ($element->getUsedTraits() as $usedTrait) {
341
            $trait['uses'][] = $usedTrait instanceof TraitDescriptor
0 ignored issues
show
Bug introduced by
The class Application\Renderer\TraitDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
342
                ? $usedTrait->getFullyQualifiedStructuralElementName()
343
                : $usedTrait;
344
        }
345
346
        /** @var PropertyDescriptor $property */
347
        foreach ($element->getProperties() as $property) {
348
            $trait['properties'][] = $this->transformProperty($property);
349
        }
350
351
        /** @var PropertyDescriptor $property */
352
        foreach ($element->getInheritedProperties() as $property) {
353
            $trait['properties'][] = $this->transformProperty($property);
354
        }
355
356
        /** @var PropertyDescriptor $property */
357
        foreach ($element->getMagicProperties() as $property) {
358
            $trait['properties'][] = $this->transformProperty($property);
359
        }
360
361
        /** @var MethodDescriptor $method */
362
        foreach ($element->getMethods() as $method) {
363
            $trait['methods'][] = $this->transformMethod($method);
364
        }
365
366
        /** @var MethodDescriptor $property */
367
        foreach ($element->getInheritedMethods() as $method) {
368
            $trait['methods'][] = $this->transformMethod($method);
369
        }
370
371
        /** @var MethodDescriptor $property */
372
        foreach ($element->getMagicMethods() as $method) {
373
            $trait['methods'][] = $this->transformMethod($method);
374
        }
375
376
        $trait['tags'] = $this->transformTags($element);
377
378
        return $trait;
379
    }
380
381
    /**
382
     * Generates an associative array containing all properties for a constant.
383
     *
384
     * @param ConstantDescriptor $constant
385
     *
386
     * @return string[]
387
     */
388
    private function transformConstant(ConstantDescriptor $constant)
389
    {
390
        $result = array(
391
            'name' => $constant->getName(),
392
            'fqsen' => $constant->getValue(),
393
            'summary' => $constant->getSummary(),
394
            'description' => $constant->getDescription(),
395
            'type' => $this->transformTypes($constant->getTypes()),
396
            'line' => $constant->getLine(),
397
            'file' => $constant->getFile()->getPath()
398
        );
399
400
        $fullyQualifiedNamespaceName = $constant->getNamespace() instanceof NamespaceDescriptor
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $fullyQualifiedNamespaceName exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
Bug introduced by
The class Application\Renderer\NamespaceDescriptor does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
401
            ? $constant->getNamespace()->getFullyQualifiedStructuralElementName()
402
            : null;
403
        if ($fullyQualifiedNamespaceName) {
404
            $result['namespace'] = $fullyQualifiedNamespaceName;
405
        }
406
407
        $result['tags'] = $this->transformTags($constant);
408
409
        return $result;
410
    }
411
412
    /**
413
     * Generates an associative array containing all properties for a property.
414
     *
415
     * @param PropertyDescriptor $property
416
     *
417
     * @return string[]
418
     */
419
    private function transformProperty(PropertyDescriptor $property)
420
    {
421
        $result = array(
422
            'name' => $property->getName(),
423
            'fqsen' => $property->getFullyQualifiedStructuralElementName(),
424
            'summary' => $property->getSummary(),
425
            'description' => $property->getDescription(),
426
            'line' => $property->getLine(),
427
            'visibility' => $property->getVisibility(),
428
            'static' => $property->isStatic(),
429
            'default' => $property->getDefault(),
430
            'type' => $this->transformTypes($property->getTypes()),
431
        );
432
433
        $result['tags'] = $this->transformTags($property);
434
435
        return $result;
436
    }
437
438
    /**
439
     * Generates an associative array containing all properties for a function.
440
     *
441
     * @param FunctionDescriptor $function
442
     *
443
     * @return string[]
444
     */
445
    private function transformFunction(FunctionDescriptor $function)
446
    {
447
        $result = array(
448
            'name' => $function->getName(),
449
            'namespace' => $function->getNamespace()->getFullyQualifiedStructuralElementName(),
450
            'fqsen' => $function->getFullyQualifiedStructuralElementName(),
451
            'line' => $function->getLine(),
452
            'summary' => $function->getSummary(),
453
            'description' => $function->getDescription(),
454
            'file' => $function->getFile()->getPath(),
455
            'arguments' => array()
456
        );
457
458
        /** @var ArgumentDescriptor $argument */
459
        foreach ($function->getArguments() as $argument) {
460
            $result['arguments'][] = $this->transformArgument($argument);
461
        }
462
463
        $result['tags'] = $this->transformTags($function);
464
465
        return $result;
466
    }
467
468
    /**
469
     * Generates an associative array containing all properties for a method.
470
     *
471
     * @param MethodDescriptor $method
472
     *
473
     * @return string[]
474
     */
475
    private function transformMethod(MethodDescriptor $method)
476
    {
477
        $result = array(
478
            'name' => $method->getName(),
479
            'fqsen' => $method->getFullyQualifiedStructuralElementName(),
480
            'summary' => $method->getSummary(),
481
            'description' => $method->getDescription(),
482
            'line' => $method->getLine(),
483
            'abstract' => $method->isAbstract(),
484
            'final' => $method->isFinal(),
485
            'static' => $method->isStatic(),
486
            'visibility' => $method->getVisibility(),
487
            'arguments' => array(),
488
        );
489
490
        /** @var ArgumentDescriptor $argument */
491
        foreach ($method->getArguments() as $argument) {
492
            $result['arguments'][] = $this->transformArgument($argument);
493
        }
494
495
        $result['tags'] = $this->transformTags($method);
496
497
        return $result;
498
    }
499
500
    /**
501
     * Generates an associative array containing all properties for an argument.
502
     *
503
     * @param ArgumentDescriptor $argument
504
     *
505
     * @return string[]
506
     */
507
    private function transformArgument(ArgumentDescriptor $argument)
508
    {
509
        $argument = array(
510
            'name' => $argument->getName(),
511
            'description' => $argument->getDescription(),
512
            'type' => $this->transformTypes($argument->getTypes()),
513
            'default' => $argument->getDefault(),
514
            'byReference' => $argument->isByReference(),
515
            'variadic' => $argument->isVariadic(),
516
        );
517
        return $argument;
518
    }
519
520
    /**
521
     * Generates an associative array containing all properties for all tags of the given element.
522
     *
523
     * @param DescriptorAbstract $element
524
     *
525
     * @return string
526
     */
527
    private function transformTags(DescriptorAbstract $element)
528
    {
529
        $tags = array();
530
        foreach ($element->getTags() as $tagName => $tagGroup) {
531
            $tags[$tagName] = array();
532
533
            /** @var TagDescriptor $tag */
534
            foreach ($tagGroup as $tag) {
535
                $tags[$tagName][] = $this->transformTag($tag);
536
            }
537
        }
538
        return $tags;
539
    }
540
541
    /**
542
     * Generates an associative array containing all properties for a tag.
543
     *
544
     * @param TagDescriptor $tag
545
     *
546
     * @return string[]
547
     */
548
    private function transformTag(TagDescriptor $tag)
549
    {
550
        $tagArray = array(
551
            'name' => $tag->getName(),
552
            'description' => $tag->getDescription(),
553
        );
554
555
        // TODO: make the tests below configurable from the outside so that more could be added using plugins
556
        if (method_exists($tag, 'getTypes')) {
557
            $tagArray['type'] = $this->transformTypes($tag->getTypes());
558
        } elseif (method_exists($tag, 'getType')) {
559
            $tagArray['type'] = $this->transformTypes($tag->getType());
560
        }
561
        if (method_exists($tag, 'getVariableName')) {
562
            $tagArray['variable'] = $tag->getVariableName();
563
        }
564
        if (method_exists($tag, 'getReference')) {
565
            $tagArray['link'] = $tag->getReference();
566
        } elseif (method_exists($tag, 'getLink')) {
567
            $tagArray['link'] = $tag->getLink();
568
        }
569
        if (method_exists($tag, 'getMethodName')) {
570
            $tagArray['methodName'] = $tag->getMethodName();
571
        }
572
573
        return $tagArray;
574
    }
575
576
    /**
577
     * Generates an associative array containing all types that are detected in the given type collection.
578
     *
579
     * @param DescriptorAbstract[]|string[] $types
580
     *
581
     * @return string[]
582
     */
583
    private function transformTypes($types)
584
    {
585
        $typeStrings = array();
586
        foreach ($types as $type) {
587
            $typeStrings[] = $type instanceof DescriptorAbstract
0 ignored issues
show
Bug introduced by
The class Application\Renderer\DescriptorAbstract does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
588
                ? $type->getFullyQualifiedStructuralElementName()
589
                : (string)$type;
590
        }
591
592
        return $typeStrings;
593
    }
594
595
    /**
596
     * Composes a tree of namespaces with their children.
597
     *
598
     * Note that only constants, functions and child-namespaces are fully specified. Classes, interfaces and
599
     * traits are FQCNs that can be used to look up the right details in the classes folder. This is done on
600
     * purpose to reduce bandwidth,
601
     *
602
     * @param NamespaceDescriptor $namespaceDescriptor
603
     *
604
     * @return string[]
605
     */
606
    private function getNamespaceTree($namespaceDescriptor)
607
    {
608
        $namespace = array(
609
            'name' => $namespaceDescriptor->getName(),
610
            'fqnn' => $namespaceDescriptor->getFullyQualifiedStructuralElementName(),
611
            'namespaces' => array(),
612
            'constants' => array(),
613
            'functions' => array(),
614
            'classes' => array(),
615
            'interfaces' => array(),
616
            'traits' => array(),
617
        );
618
619
        foreach ($namespaceDescriptor->getChildren() as $subNamespace) {
620
            $namespace['namespaces'][] = $this->getNamespaceTree($subNamespace);
621
        }
622
623
        /** @var ConstantDescriptor $constant */
624
        foreach ($namespaceDescriptor->getConstants() as $constant) {
625
            $namespace['constants'][] = $this->transformConstant($constant);
626
        }
627
628
        /** @var FunctionDescriptor $function */
629
        foreach ($namespaceDescriptor->getFunctions() as $function) {
630
            $namespace['functions'][] = $this->transformFunction($function);
631
        }
632
633
        /** @var ClassDescriptor $class */
634
        foreach ($namespaceDescriptor->getClasses() as $class) {
635
            $namespace['classes'][] = $class->getFullyQualifiedStructuralElementName();
636
        }
637
638
        /** @var TraitDescriptor $trait */
639
        foreach ($namespaceDescriptor->getTraits() as $trait) {
640
            $namespace['traits'][] = $trait->getFullyQualifiedStructuralElementName();
641
        }
642
643
        /** @var InterfaceDescriptor $class */
644
        foreach ($namespaceDescriptor->getInterfaces() as $interface) {
645
            $namespace['interfaces'][] = $interface->getFullyQualifiedStructuralElementName();
646
        }
647
648
        return $namespace;
649
    }
650
651
    /**
652
     * Composes a tree of packages with their children.
653
     *
654
     * Note that only constants, functions and child-packages are fully specified. Classes, interfaces and
655
     * traits are FQCNs that can be used to look up the right details in the classes folder. This is done on
656
     * purpose to reduce bandwidth,
657
     *
658
     * @param PackageDescriptor $packageDescriptor
659
     *
660
     * @return string[]
661
     */
662
    private function getPackageTree($packageDescriptor)
663
    {
664
        $package = array(
665
            'name' => $packageDescriptor->getName(),
666
            'fqnn' => $packageDescriptor->getFullyQualifiedStructuralElementName(),
667
            'packages' => array(),
668
            'constants' => array(),
669
            'functions' => array(),
670
            'classes' => array(),
671
            'interfaces' => array(),
672
            'traits' => array(),
673
        );
674
675
        foreach ($packageDescriptor->getChildren() as $subPackage) {
676
            $package['packages'][] = $this->getPackageTree($subPackage);
677
        }
678
679
        /** @var ConstantDescriptor $constant */
680
        foreach ($packageDescriptor->getConstants() as $constant) {
681
            $package['constants'][] = $this->transformConstant($constant);
682
        }
683
684
        /** @var FunctionDescriptor $function */
685
        foreach ($packageDescriptor->getFunctions() as $function) {
686
            $package['functions'][] = $this->transformFunction($function);
687
        }
688
689
        /** @var ClassDescriptor $class */
690
        foreach ($packageDescriptor->getClasses() as $class) {
691
            $package['classes'][] = $class->getFullyQualifiedStructuralElementName();
692
        }
693
694
        /** @var TraitDescriptor $trait */
695
        foreach ($packageDescriptor->getTraits() as $trait) {
696
            $package['traits'][] = $trait->getFullyQualifiedStructuralElementName();
697
        }
698
699
        /** @var InterfaceDescriptor $class */
700
        foreach ($packageDescriptor->getInterfaces() as $interface) {
701
            $package['interfaces'][] = $interface->getFullyQualifiedStructuralElementName();
702
        }
703
704
        return $package;
705
    }
706
707
    /**
708
     * Renders the given class to the provided folder with the FQCN in the element as filename.
709
     *
710
     * @param string                                              $folder
711
     * @param ClassDescriptor|InterfaceDescriptor|TraitDescriptor $element
712
     * @param string[]                                            $class
713
     *
714
     * @return void
715
     */
716
    private function writeClassToDisk($folder, $element, array $class)
717
    {
718
        file_put_contents(
719
            $folder . 'classes/'
720
            . str_replace('\\', '.', ltrim($element->getFullyQualifiedStructuralElementName(), '\\'))
721
            . '.json',
722
            'classDefinition(' . json_encode($class) . ');'
723
        );
724
    }
725
726
    /**
727
     * Renders the given file description to the provided folder with the path in the element as filename.
728
     *
729
     * @param string         $folder
730
     * @param FileDescriptor $element
731
     * @param string[]       $file
732
     *
733
     * @return void
734
     */
735
    private function writeFileToDisk($folder, FileDescriptor $element, array $file)
736
    {
737
        file_put_contents(
738
            $folder . 'files/'
739
            . str_replace(array('\\', '/'), '.', ltrim($element->getPath(), '/\\'))
740
            . '.json',
741
            'fileDefinition(' . json_encode($file) . ');'
742
        );
743
    }
744
}
745