Completed
Push — develop ( c4d989...a97889 )
by Jaap
12s
created

JsonpRenderer::transformClass()   F

Complexity

Conditions 15
Paths 9216

Size

Total Lines 85
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

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

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

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $destination is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $template is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
51
    {
52
        // TODO: Implement render() method.
53
    }
54
55
    /**
56
     * Generate a series of JSONP files based on the ProjectDescriptor's structure in the target directory.
57
     *
58
     * This method is responsible for writing a series of JSONP files to disk in the directory specified by the
59
     * user when starting phpDocumentor. A complete description of what is generated can be found in the documentation
60
     * of this class itself.
61
     *
62
     * @param Jsonp $action
63
     *
64
     * @return void
65
     */
66
    public function handle(Action $action)
67
    {
68
        $project = $this->analyzer->getProjectDescriptor();
0 ignored issues
show
Bug introduced by
The property analyzer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
69
        $folder = $action->getRenderPass()->getDestination() . '/' . ltrim($action->getDestination(), '\\/');
0 ignored issues
show
Bug introduced by
The method getRenderPass() does not seem to exist on object<phpDocumentor\Dom...nderer\Template\Action>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
It seems like you code against a concrete implementation and not the interface phpDocumentor\DomainModel\Renderer\Template\Action as the method getDestination() does only exist in the following implementations of said interface: phpDocumentor\Applicatio...plate\Action\AppendFile, phpDocumentor\Applicatio...plate\Action\Checkstyle, phpDocumentor\Applicatio...emplate\Action\CopyFile, phpDocumentor\Applicatio...r\Template\Action\Graph, phpDocumentor\Applicatio...r\Template\Action\Jsonp, phpDocumentor\Applicatio...plate\Action\Sourcecode, phpDocumentor\Applicatio...er\Template\Action\Twig, phpDocumentor\Applicatio...rer\Template\Action\Xml, phpDocumentor\Applicatio...rer\Template\Action\Xsl.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
70
        @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...
71
        @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...
72
73
        // Generate namespaces json
74
        $namespaces = $this->getNamespaceTree($project->getNamespace());
75
        file_put_contents($folder . '/namespaces.json', 'namespaces(' . json_encode($namespaces) . ');');
76
77
        // Generate packages json
78
        $packages = $this->getPackageTree($project->getIndexes()->get('packages')->get('\\'));
79
        file_put_contents($folder . '/packages.json', 'packages(' . json_encode($packages) . ');');
80
81
        // Generate per-class json
82
        foreach ($project->getIndexes()->get('elements') as $element) {
83
            if ($element instanceof ClassDescriptor) {
0 ignored issues
show
Bug introduced by
The class phpDocumentor\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...
84
                $this->writeClassToDisk($folder, $element, $this->transformClass($element));
85
                continue;
86
            }
87
            if ($element instanceof InterfaceDescriptor) {
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...rer\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...
88
                $this->writeClassToDisk($folder, $element, $this->transformInterface($element));
89
                continue;
90
            }
91
            if ($element instanceof TraitDescriptor) {
0 ignored issues
show
Bug introduced by
The class phpDocumentor\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...
92
                $this->writeClassToDisk($folder, $element, $this->transformTrait($element));
93
                continue;
94
            }
95
        }
96
97
        // Generate files json
98
        foreach ($project->getFiles() as $file) {
99
            $this->writeFileToDisk($folder, $file, $this->transformFile($file));
100
        }
101
    }
102
103
    /**
104
     * Generates an associative array containing all properties and child elements for a file.
105
     *
106
     * @param FileDescriptor $element
107
     *
108
     * @return string[]
109
     */
110
    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...
111
    {
112
        $file = array(
113
            'name' => $element->getName(),
114
            'path' => $element->getPath(),
115
            'summary' => $element->getSummary(),
116
            'description' => $element->getDescription(),
117
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...derer\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...
118
                ? $element->getFullyQualifiedStructuralElementName()
119
                : (string)$element,
120
            'constants' => array(),
121
            'functions' => array(),
122
            'classes' => array(),
123
            'interfaces' => array(),
124
            'traits' => array(),
125
            'namespace-aliases' => array(),
126
            'markers' => array(),
127
        );
128
129
        foreach ($element->getNamespaceAliases() as $alias => $namespace) {
130
            $file['namespace-aliases'][$alias] = $namespace;
131
        }
132
133
        foreach ($element->getConstants() as $constant) {
134
            $file['constants'][] = $this->transformConstant($constant);
135
        }
136
        foreach ($element->getFunctions() as $function) {
137
            $file['functions'][] = $this->transformFunction($function);
138
        }
139
        /** @var TraitDescriptor $trait */
140
        foreach ($element->getTraits() as $trait) {
141
            $file['traits'][] = $trait->getFullyQualifiedStructuralElementName();
142
        }
143
        /** @var InterfaceDescriptor $interface */
144
        foreach ($element->getInterfaces() as $interface) {
145
            $file['interface'][] = $interface->getFullyQualifiedStructuralElementName();
146
        }
147
        /** @var ClassDescriptor $class */
148
        foreach ($element->getClasses() as $class) {
149
            $file['classes'][] = $class->getFullyQualifiedStructuralElementName();
150
        }
151
152
        foreach ($element->getMarkers() as $marker) {
153
            $file['markers'] = $marker;
154
        }
155
        foreach ($element->getAllErrors() as $error) {
156
            $file['errors'][] = $error;
157
        }
158
159
        return $file;
160
    }
161
162
    /**
163
     * Generates an associative array containing all properties and child elements for a class.
164
     *
165
     * @param ClassDescriptor $element
166
     *
167
     * @return string[]
168
     */
169
    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...
170
    {
171
        $class = array(
172
            'type' => 'class',
173
            'name' => $element->getName(),
174
            'line' => $element->getLine(),
175
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
176
            'final' => $element->isFinal(),
177
            'abstract' => $element->isAbstract(),
178
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
179
            'summary' => $element->getSummary(),
180
            'description' => $element->getDescription(),
181
            'extends' => $element->getParent() instanceof ClassDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\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...
182
                ? $element->getParent()->getFullyQualifiedStructuralElementName()
183
                : $element->getParent(),
184
            'implements' => array(),
185
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...derer\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...
186
                ? $element->getFullyQualifiedStructuralElementName()
187
                : (string)$element,
188
            'file' => $element->getFile()->getPath(),
189
            'uses' => array(),
190
            'constants' => array(),
191
            'methods' => array(),
192
            'properties' => array()
193
        );
194
195
        /** @var TraitDescriptor|string $trait */
196
        foreach ($element->getUsedTraits() as $trait) {
197
            $class['uses'][] = $trait instanceof TraitDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\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...
198
                ? $trait->getFullyQualifiedStructuralElementName()
199
                : $trait;
200
        }
201
202
        /** @var InterfaceDescriptor $interface */
203
        foreach ($element->getInterfaces() as $interface) {
204
            $interfaceFqcn = is_string($interface)
205
                ? $interface
206
                : $interface->getFullyQualifiedStructuralElementName();
207
            $class['implements'][] = $interfaceFqcn;
208
        }
209
210
        /** @var ConstantDescriptor $constant */
211
        foreach ($element->getConstants() as $constant) {
212
            $class['constants'][] = $this->transformConstant($constant);
213
        }
214
215
        /** @var ConstantDescriptor $constant */
216
        foreach ($element->getInheritedConstants() as $constant) {
217
            $class['constants'][] = $this->transformConstant($constant);
218
        }
219
220
        /** @var PropertyDescriptor $property */
221
        foreach ($element->getProperties() as $property) {
222
            $class['properties'][] = $this->transformProperty($property);
223
        }
224
225
        /** @var PropertyDescriptor $property */
226
        foreach ($element->getInheritedProperties() as $property) {
227
            $class['properties'][] = $this->transformProperty($property);
228
        }
229
230
        /** @var PropertyDescriptor $property */
231
        foreach ($element->getMagicProperties() as $property) {
232
            $class['properties'][] = $this->transformProperty($property);
233
        }
234
235
        /** @var MethodDescriptor $method */
236
        foreach ($element->getMethods() as $method) {
237
            $class['methods'][] = $this->transformMethod($method);
238
        }
239
240
        /** @var MethodDescriptor $property */
241
        foreach ($element->getInheritedMethods() as $method) {
242
            $class['methods'][] = $this->transformMethod($method);
243
        }
244
245
        /** @var MethodDescriptor $property */
246
        foreach ($element->getMagicMethods() as $method) {
247
            $class['methods'][] = $this->transformMethod($method);
248
        }
249
250
        $class['tags'] = $this->transformTags($element);
251
252
        return $class;
253
    }
254
255
    /**
256
     * Generates an associative array containing all properties and child elements for an interface.
257
     *
258
     * @param InterfaceDescriptor $element
259
     *
260
     * @return string[]
261
     */
262
    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...
263
    {
264
        $interface = array(
265
            'type' => 'interface',
266
            'name' => $element->getName(),
267
            'line' => $element->getLine(),
268
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
269
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
270
            'summary' => $element->getSummary(),
271
            'description' => $element->getDescription(),
272
            'extends' => array(),
273
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...derer\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...
274
                ? $element->getFullyQualifiedStructuralElementName()
275
                : (string)$element,
276
            'file' => $element->getFile()->getPath(),
277
            'constants' => array(),
278
            'methods' => array(),
279
        );
280
281
        /** @var InterfaceDescriptor $extendedInterface */
282
        foreach ($element->getParent() as $extendedInterface) {
283
            $interfaceFqcn = is_string($extendedInterface)
284
                ? $extendedInterface
285
                : $extendedInterface->getFullyQualifiedStructuralElementName();
286
            $interface['extends'][] = $interfaceFqcn;
287
        }
288
289
        /** @var ConstantDescriptor $property */
290
        foreach ($element->getConstants() as $constant) {
291
            $interface['constants'][] = $this->transformConstant($constant);
292
        }
293
294
        /** @var ConstantDescriptor $constant */
295
        foreach ($element->getInheritedConstants() as $constant) {
296
            $interface['constants'][] = $this->transformConstant($constant);
297
        }
298
299
        /** @var MethodDescriptor $method */
300
        foreach ($element->getMethods() as $method) {
301
            $interface['methods'][] = $this->transformMethod($method);
302
        }
303
304
        /** @var MethodDescriptor $property */
305
        foreach ($element->getInheritedMethods() as $method) {
306
            $interface['methods'][] = $this->transformMethod($method);
307
        }
308
309
        $interface['tags'] = $this->transformTags($element);
310
311
        return $interface;
312
    }
313
314
    /**
315
     * Generates an associative array containing all properties and child elements for a trait.
316
     *
317
     * @param TraitDescriptor $element
318
     *
319
     * @return string[]
320
     */
321
    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...
322
    {
323
        $trait = array(
324
            'type' => 'trait',
325
            'name' => $element->getName(),
326
            'line' => $element->getLine(),
327
            'fqsen' => $element->getFullyQualifiedStructuralElementName(),
328
            'namespace' => $element->getNamespace()->getFullyQualifiedStructuralElementName(),
329
            'summary' => $element->getSummary(),
330
            'description' => $element->getDescription(),
331
            'package' => $element instanceof PackageDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...derer\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...
332
                ? $element->getFullyQualifiedStructuralElementName()
333
                : (string)$element,
334
            'file' => $element->getFile()->getPath(),
335
            'uses' => array(),
336
            'constants' => array(),
337
            'methods' => array(),
338
        );
339
340
        /** @var TraitDescriptor|string $usedTrait */
341
        foreach ($element->getUsedTraits() as $usedTrait) {
342
            $trait['uses'][] = $usedTrait instanceof TraitDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\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...
343
                ? $usedTrait->getFullyQualifiedStructuralElementName()
344
                : $usedTrait;
345
        }
346
347
        /** @var PropertyDescriptor $property */
348
        foreach ($element->getProperties() as $property) {
349
            $trait['properties'][] = $this->transformProperty($property);
350
        }
351
352
        /** @var PropertyDescriptor $property */
353
        foreach ($element->getInheritedProperties() as $property) {
354
            $trait['properties'][] = $this->transformProperty($property);
355
        }
356
357
        /** @var PropertyDescriptor $property */
358
        foreach ($element->getMagicProperties() as $property) {
359
            $trait['properties'][] = $this->transformProperty($property);
360
        }
361
362
        /** @var MethodDescriptor $method */
363
        foreach ($element->getMethods() as $method) {
364
            $trait['methods'][] = $this->transformMethod($method);
365
        }
366
367
        /** @var MethodDescriptor $property */
368
        foreach ($element->getInheritedMethods() as $method) {
369
            $trait['methods'][] = $this->transformMethod($method);
370
        }
371
372
        /** @var MethodDescriptor $property */
373
        foreach ($element->getMagicMethods() as $method) {
374
            $trait['methods'][] = $this->transformMethod($method);
375
        }
376
377
        $trait['tags'] = $this->transformTags($element);
378
379
        return $trait;
380
    }
381
382
    /**
383
     * Generates an associative array containing all properties for a constant.
384
     *
385
     * @param ConstantDescriptor $constant
386
     *
387
     * @return string[]
388
     */
389
    private function transformConstant(ConstantDescriptor $constant)
390
    {
391
        $result = array(
392
            'name' => $constant->getName(),
393
            'fqsen' => $constant->getValue(),
394
            'summary' => $constant->getSummary(),
395
            'description' => $constant->getDescription(),
396
            'type' => $this->transformTypes($constant->getTypes()),
397
            'line' => $constant->getLine(),
398
            'file' => $constant->getFile()->getPath()
399
        );
400
401
        $fullyQualifiedNamespaceName = $constant->getNamespace() instanceof NamespaceDescriptor
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...rer\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...
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...
402
            ? $constant->getNamespace()->getFullyQualifiedStructuralElementName()
403
            : null;
404
        if ($fullyQualifiedNamespaceName) {
405
            $result['namespace'] = $fullyQualifiedNamespaceName;
406
        }
407
408
        $result['tags'] = $this->transformTags($constant);
409
410
        return $result;
411
    }
412
413
    /**
414
     * Generates an associative array containing all properties for a property.
415
     *
416
     * @param PropertyDescriptor $property
417
     *
418
     * @return string[]
419
     */
420
    private function transformProperty(PropertyDescriptor $property)
421
    {
422
        $result = array(
423
            'name' => $property->getName(),
424
            'fqsen' => $property->getFullyQualifiedStructuralElementName(),
425
            'summary' => $property->getSummary(),
426
            'description' => $property->getDescription(),
427
            'line' => $property->getLine(),
428
            'visibility' => $property->getVisibility(),
429
            'static' => $property->isStatic(),
430
            'default' => $property->getDefault(),
431
            'type' => $this->transformTypes($property->getTypes()),
432
        );
433
434
        $result['tags'] = $this->transformTags($property);
435
436
        return $result;
437
    }
438
439
    /**
440
     * Generates an associative array containing all properties for a function.
441
     *
442
     * @param FunctionDescriptor $function
443
     *
444
     * @return string[]
445
     */
446
    private function transformFunction(FunctionDescriptor $function)
447
    {
448
        $result = array(
449
            'name' => $function->getName(),
450
            'namespace' => $function->getNamespace()->getFullyQualifiedStructuralElementName(),
451
            'fqsen' => $function->getFullyQualifiedStructuralElementName(),
452
            'line' => $function->getLine(),
453
            'summary' => $function->getSummary(),
454
            'description' => $function->getDescription(),
455
            'file' => $function->getFile()->getPath(),
456
            'arguments' => array()
457
        );
458
459
        /** @var ArgumentDescriptor $argument */
460
        foreach ($function->getArguments() as $argument) {
461
            $result['arguments'][] = $this->transformArgument($argument);
462
        }
463
464
        $result['tags'] = $this->transformTags($function);
465
466
        return $result;
467
    }
468
469
    /**
470
     * Generates an associative array containing all properties for a method.
471
     *
472
     * @param MethodDescriptor $method
473
     *
474
     * @return string[]
475
     */
476
    private function transformMethod(MethodDescriptor $method)
477
    {
478
        $result = array(
479
            'name' => $method->getName(),
480
            'fqsen' => $method->getFullyQualifiedStructuralElementName(),
481
            'summary' => $method->getSummary(),
482
            'description' => $method->getDescription(),
483
            'line' => $method->getLine(),
484
            'abstract' => $method->isAbstract(),
485
            'final' => $method->isFinal(),
486
            'static' => $method->isStatic(),
487
            'visibility' => $method->getVisibility(),
488
            'arguments' => array(),
489
        );
490
491
        /** @var ArgumentDescriptor $argument */
492
        foreach ($method->getArguments() as $argument) {
493
            $result['arguments'][] = $this->transformArgument($argument);
494
        }
495
496
        $result['tags'] = $this->transformTags($method);
497
498
        return $result;
499
    }
500
501
    /**
502
     * Generates an associative array containing all properties for an argument.
503
     *
504
     * @param ArgumentDescriptor $argument
505
     *
506
     * @return string[]
507
     */
508
    private function transformArgument(ArgumentDescriptor $argument)
509
    {
510
        $argument = array(
511
            'name' => $argument->getName(),
512
            'description' => $argument->getDescription(),
513
            'type' => $this->transformTypes($argument->getTypes()),
514
            'default' => $argument->getDefault(),
515
            'byReference' => $argument->isByReference(),
516
            'variadic' => $argument->isVariadic(),
517
        );
518
        return $argument;
519
    }
520
521
    /**
522
     * Generates an associative array containing all properties for all tags of the given element.
523
     *
524
     * @param DescriptorAbstract $element
525
     *
526
     * @return string
527
     */
528
    private function transformTags(DescriptorAbstract $element)
529
    {
530
        $tags = array();
531
        foreach ($element->getTags() as $tagName => $tagGroup) {
532
            $tags[$tagName] = array();
533
534
            /** @var TagDescriptor $tag */
535
            foreach ($tagGroup as $tag) {
536
                $tags[$tagName][] = $this->transformTag($tag);
537
            }
538
        }
539
        return $tags;
540
    }
541
542
    /**
543
     * Generates an associative array containing all properties for a tag.
544
     *
545
     * @param TagDescriptor $tag
546
     *
547
     * @return string[]
548
     */
549
    private function transformTag(TagDescriptor $tag)
550
    {
551
        $tagArray = array(
552
            'name' => $tag->getName(),
553
            'description' => $tag->getDescription(),
554
        );
555
556
        // TODO: make the tests below configurable from the outside so that more could be added using plugins
557
        if (method_exists($tag, 'getTypes')) {
558
            $tagArray['type'] = $this->transformTypes($tag->getTypes());
559
        } elseif (method_exists($tag, 'getType')) {
560
            $tagArray['type'] = $this->transformTypes($tag->getType());
561
        }
562
        if (method_exists($tag, 'getVariableName')) {
563
            $tagArray['variable'] = $tag->getVariableName();
564
        }
565
        if (method_exists($tag, 'getReference')) {
566
            $tagArray['link'] = $tag->getReference();
567
        } elseif (method_exists($tag, 'getLink')) {
568
            $tagArray['link'] = $tag->getLink();
569
        }
570
        if (method_exists($tag, 'getMethodName')) {
571
            $tagArray['methodName'] = $tag->getMethodName();
572
        }
573
574
        return $tagArray;
575
    }
576
577
    /**
578
     * Generates an associative array containing all types that are detected in the given type collection.
579
     *
580
     * @param DescriptorAbstract[]|string[] $types
581
     *
582
     * @return string[]
583
     */
584
    private function transformTypes($types)
585
    {
586
        $typeStrings = array();
587
        foreach ($types as $type) {
588
            $typeStrings[] = $type instanceof DescriptorAbstract
0 ignored issues
show
Bug introduced by
The class phpDocumentor\Applicatio...erer\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...
589
                ? $type->getFullyQualifiedStructuralElementName()
590
                : (string)$type;
591
        }
592
593
        return $typeStrings;
594
    }
595
596
    /**
597
     * Composes a tree of namespaces with their children.
598
     *
599
     * Note that only constants, functions and child-namespaces are fully specified. Classes, interfaces and
600
     * traits are FQCNs that can be used to look up the right details in the classes folder. This is done on
601
     * purpose to reduce bandwidth,
602
     *
603
     * @param NamespaceDescriptor $namespaceDescriptor
604
     *
605
     * @return string[]
606
     */
607
    private function getNamespaceTree($namespaceDescriptor)
608
    {
609
        $namespace = array(
610
            'name' => $namespaceDescriptor->getName(),
611
            'fqnn' => $namespaceDescriptor->getFullyQualifiedStructuralElementName(),
612
            'namespaces' => array(),
613
            'constants' => array(),
614
            'functions' => array(),
615
            'classes' => array(),
616
            'interfaces' => array(),
617
            'traits' => array(),
618
        );
619
620
        foreach ($namespaceDescriptor->getChildren() as $subNamespace) {
621
            $namespace['namespaces'][] = $this->getNamespaceTree($subNamespace);
622
        }
623
624
        /** @var ConstantDescriptor $constant */
625
        foreach ($namespaceDescriptor->getConstants() as $constant) {
626
            $namespace['constants'][] = $this->transformConstant($constant);
627
        }
628
629
        /** @var FunctionDescriptor $function */
630
        foreach ($namespaceDescriptor->getFunctions() as $function) {
631
            $namespace['functions'][] = $this->transformFunction($function);
632
        }
633
634
        /** @var ClassDescriptor $class */
635
        foreach ($namespaceDescriptor->getClasses() as $class) {
636
            $namespace['classes'][] = $class->getFullyQualifiedStructuralElementName();
637
        }
638
639
        /** @var TraitDescriptor $trait */
640
        foreach ($namespaceDescriptor->getTraits() as $trait) {
641
            $namespace['traits'][] = $trait->getFullyQualifiedStructuralElementName();
642
        }
643
644
        /** @var InterfaceDescriptor $class */
645
        foreach ($namespaceDescriptor->getInterfaces() as $interface) {
646
            $namespace['interfaces'][] = $interface->getFullyQualifiedStructuralElementName();
647
        }
648
649
        return $namespace;
650
    }
651
652
    /**
653
     * Composes a tree of packages with their children.
654
     *
655
     * Note that only constants, functions and child-packages are fully specified. Classes, interfaces and
656
     * traits are FQCNs that can be used to look up the right details in the classes folder. This is done on
657
     * purpose to reduce bandwidth,
658
     *
659
     * @param PackageDescriptor $packageDescriptor
660
     *
661
     * @return string[]
662
     */
663
    private function getPackageTree($packageDescriptor)
664
    {
665
        $package = array(
666
            'name' => $packageDescriptor->getName(),
667
            'fqnn' => $packageDescriptor->getFullyQualifiedStructuralElementName(),
668
            'packages' => array(),
669
            'constants' => array(),
670
            'functions' => array(),
671
            'classes' => array(),
672
            'interfaces' => array(),
673
            'traits' => array(),
674
        );
675
676
        foreach ($packageDescriptor->getChildren() as $subPackage) {
677
            $package['packages'][] = $this->getPackageTree($subPackage);
678
        }
679
680
        /** @var ConstantDescriptor $constant */
681
        foreach ($packageDescriptor->getConstants() as $constant) {
682
            $package['constants'][] = $this->transformConstant($constant);
683
        }
684
685
        /** @var FunctionDescriptor $function */
686
        foreach ($packageDescriptor->getFunctions() as $function) {
687
            $package['functions'][] = $this->transformFunction($function);
688
        }
689
690
        /** @var ClassDescriptor $class */
691
        foreach ($packageDescriptor->getClasses() as $class) {
692
            $package['classes'][] = $class->getFullyQualifiedStructuralElementName();
693
        }
694
695
        /** @var TraitDescriptor $trait */
696
        foreach ($packageDescriptor->getTraits() as $trait) {
697
            $package['traits'][] = $trait->getFullyQualifiedStructuralElementName();
698
        }
699
700
        /** @var InterfaceDescriptor $class */
701
        foreach ($packageDescriptor->getInterfaces() as $interface) {
702
            $package['interfaces'][] = $interface->getFullyQualifiedStructuralElementName();
703
        }
704
705
        return $package;
706
    }
707
708
    /**
709
     * Renders the given class to the provided folder with the FQCN in the element as filename.
710
     *
711
     * @param string                                              $folder
712
     * @param ClassDescriptor|InterfaceDescriptor|TraitDescriptor $element
713
     * @param string[]                                            $class
714
     *
715
     * @return void
716
     */
717
    private function writeClassToDisk($folder, $element, array $class)
718
    {
719
        file_put_contents(
720
            $folder . 'classes/'
721
            . str_replace('\\', '.', ltrim($element->getFullyQualifiedStructuralElementName(), '\\'))
722
            . '.json',
723
            'classDefinition(' . json_encode($class) . ');'
724
        );
725
    }
726
727
    /**
728
     * Renders the given file description to the provided folder with the path in the element as filename.
729
     *
730
     * @param string         $folder
731
     * @param FileDescriptor $element
732
     * @param string[]       $file
733
     *
734
     * @return void
735
     */
736
    private function writeFileToDisk($folder, FileDescriptor $element, array $file)
737
    {
738
        file_put_contents(
739
            $folder . 'files/'
740
            . str_replace(array('\\', '/'), '.', ltrim($element->getPath(), '/\\'))
741
            . '.json',
742
            'fileDefinition(' . json_encode($file) . ');'
743
        );
744
    }
745
}
746