Completed
Push — master ( 748172...28d82c )
by Mike
06:47
created

Extension::getFilters()   C

Complexity

Conditions 9
Paths 1

Size

Total Lines 99

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
nc 1
nop 0
dl 0
loc 99
ccs 0
cts 37
cp 0
crap 90
rs 6.4662
c 0
b 0
f 0

How to fix   Long Method   

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
declare(strict_types=1);
4
5
/**
6
 * This file is part of phpDocumentor.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @link https://phpdoc.org
12
 */
13
14
namespace phpDocumentor\Transformer\Writer\Twig;
15
16
use ArrayIterator;
17
use Parsedown;
18
use phpDocumentor\Descriptor\Collection;
19
use phpDocumentor\Descriptor\Descriptor;
20
use phpDocumentor\Descriptor\DescriptorAbstract;
21
use phpDocumentor\Descriptor\Interfaces\VisibilityInterface;
22
use phpDocumentor\Descriptor\NamespaceDescriptor;
23
use phpDocumentor\Descriptor\PackageDescriptor;
24
use phpDocumentor\Descriptor\ProjectDescriptor;
25
use Twig\Extension\AbstractExtension;
26
use Twig\Extension\GlobalsInterface;
27
use Twig\TwigFilter;
28
use Twig\TwigFunction;
29
use function array_unshift;
30
use function count;
31
use function method_exists;
32
use function str_replace;
33
use function strtolower;
34
use function var_export;
35
36
/**
37
 * Basic extension adding phpDocumentor specific functionality for Twig
38
 * templates.
39
 *
40
 * Global variables:
41
 *
42
 * - *ast_node*, the current $data element
43
 *
44
 * Functions:
45
 *
46
 * - *path(string) *, converts the given relative path to be based of the projects
47
 *   root instead of the current directory
48
 *
49
 * Filters:
50
 *
51
 * - *markdown*, converts the associated text from Markdown formatting to HTML.
52
 * - *trans*, translates the given string
53
 * - *route*, attempts to generate a URL for a given Descriptor
54
 * - *sort_desc*, sorts the given objects by their Name property/getter in a descending fashion
55
 * - *sort_asc*, sorts the given objects by their Name property/getter in a ascending fashion
56
 */
57
final class Extension extends AbstractExtension implements ExtensionInterface, GlobalsInterface
58
{
59
    /** @var ProjectDescriptor */
60
    private $data;
61
62
    /** @var LinkRenderer */
63
    private $routeRenderer;
64
65
    /**
66
     * Registers the structure and transformation with this extension.
67
     *
68
     * @param ProjectDescriptor $project Represents the complete Abstract Syntax Tree.
69
     */
70
    public function __construct(
71
        ProjectDescriptor $project,
72
        ?LinkRenderer $routeRenderer = null
73
    ) {
74
        $this->data = $project;
75
        $this->routeRenderer = $routeRenderer->withProject($project);
76
    }
77
78
    /**
79
     * Sets the destination directory relative to the Project's Root.
80
     *
81
     * The destination is the target directory containing the resulting
82
     * file. This destination is relative to the Project's root and can
83
     * be used for the calculation of nesting depths, etc.
84
     *
85
     * @see EnvironmentFactory for the invocation of this method.
86
     */
87
    public function setDestination(string $destination) : void
88
    {
89
        $this->routeRenderer->setDestination($destination);
0 ignored issues
show
Deprecated Code introduced by
The method phpDocumentor\Transforme...derer::setDestination() has been deprecated with message: in favour of withDestination()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
90
    }
91
92
    /**
93
     * Returns an array of global variables to inject into a Twig template.
94
     *
95
     * @return array<string, ProjectDescriptor|bool>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
96
     */
97
    public function getGlobals() : array
98
    {
99
        return [
100
            'project' => $this->data,
101
            'usesNamespaces' => count($this->data->getNamespace()->getChildren()) > 0,
102
            'usesPackages' => count($this->data->getPackage()->getChildren()) > 1,
103
        ];
104
    }
105
106
    /**
107
     * Returns a listing of all functions that this extension adds.
108
     *
109
     * This method is automatically used by Twig upon registering this
110
     * extension (which is done automatically by phpDocumentor) to determine
111
     * an additional list of functions.
112
     *
113
     * See the Class' DocBlock for a listing of functionality added by this
114
     * Extension.
115
     *
116
     * @return TwigFunction[]
117
     */
118
    public function getFunctions() : array
119
    {
120
        return [
121
            new TwigFunction('path', [$this->routeRenderer, 'convertToRootPath']),
122
            new TwigFunction('link', [$this->routeRenderer, 'link']),
123
            new TwigFunction(
124
                'breadcrumbs',
125
                static function (DescriptorAbstract $baseNode) {
126
                    $results = [];
127
                    $namespace = $baseNode instanceof NamespaceDescriptor
128
                        ? $baseNode->getParent()
129
                        : $baseNode->getNamespace();
130
                    while ($namespace instanceof NamespaceDescriptor && $namespace->getName() !== '\\') {
131
                        array_unshift($results, $namespace);
132
                        $namespace = $namespace->getParent();
133
                    }
134
135
                    return $results;
136
                }
137
            ),
138
            new TwigFunction(
139
                'packages',
140
                static function (DescriptorAbstract $baseNode) {
141
                    $results = [];
142
                    $package = $baseNode instanceof PackageDescriptor
143
                        ? $baseNode->getParent()
144
                        : $baseNode->getPackage();
145
                    while ($package instanceof PackageDescriptor && $package->getName() !== '\\') {
146
                        array_unshift($results, $package);
147
                        $package = $package->getParent();
148
                    }
149
150
                    return $results;
151
                }
152
            ),
153
            new TwigFunction('methods', static function (DescriptorAbstract $descriptor) : Collection {
154
                $methods = new Collection();
155
                if (method_exists($descriptor, 'getInheritedMethods')) {
156
                    $methods = $methods->merge($descriptor->getInheritedMethods());
0 ignored issues
show
Documentation Bug introduced by
The method getInheritedMethods does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
157
                }
158
159
                if (method_exists($descriptor, 'getMagicMethods')) {
160
                    $methods = $methods->merge($descriptor->getMagicMethods());
0 ignored issues
show
Documentation Bug introduced by
The method getMagicMethods does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
161
                }
162
163
                if (method_exists($descriptor, 'getMethods')) {
164
                    $methods = $methods->merge($descriptor->getMethods());
0 ignored issues
show
Documentation Bug introduced by
The method getMethods does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
165
                }
166
167
                return $methods;
168
            }),
169
            new TwigFunction('properties', static function (DescriptorAbstract $descriptor) : Collection {
170
                $properties = new Collection();
171
                if (method_exists($descriptor, 'getInheritedProperties')) {
172
                    $properties = $properties->merge($descriptor->getInheritedProperties());
0 ignored issues
show
Documentation Bug introduced by
The method getInheritedProperties does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
173
                }
174
175
                if (method_exists($descriptor, 'getMagicProperties')) {
176
                    $properties = $properties->merge($descriptor->getMagicProperties());
0 ignored issues
show
Documentation Bug introduced by
The method getMagicProperties does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
177
                }
178
179
                if (method_exists($descriptor, 'getProperties')) {
180
                    $properties = $properties->merge($descriptor->getProperties());
0 ignored issues
show
Documentation Bug introduced by
The method getProperties does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
181
                }
182
183
                return $properties;
184
            }),
185
            new TwigFunction('constants', static function (DescriptorAbstract $descriptor) : Collection {
186
                $constants = new Collection();
187
                if (method_exists($descriptor, 'getInheritedConstants')) {
188
                    $constants = $constants->merge($descriptor->getInheritedConstants());
0 ignored issues
show
Documentation Bug introduced by
The method getInheritedConstants does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
189
                }
190
191
                if (method_exists($descriptor, 'getMagicConstants')) {
192
                    $constants = $constants->merge($descriptor->getMagicConstants());
0 ignored issues
show
Documentation Bug introduced by
The method getMagicConstants does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
193
                }
194
195
                if (method_exists($descriptor, 'getConstants')) {
196
                    $constants = $constants->merge($descriptor->getConstants());
0 ignored issues
show
Documentation Bug introduced by
The method getConstants does not exist on object<phpDocumentor\Des...tor\DescriptorAbstract>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
197
                }
198
199
                return $constants;
200
            }),
201
        ];
202
    }
203
204
    /**
205
     * Returns a list of all filters that are exposed by this extension.
206
     *
207
     * @return TwigFilter[]
208
     */
209
    public function getFilters() : array
210
    {
211
        $parser = Parsedown::instance();
212
        $parser->setSafeMode(true);
213
        $routeRenderer = $this->routeRenderer;
214
215
        return [
216
            'markdown' => new TwigFilter(
217
                'markdown',
218
                static function (string $value) use ($parser) : string {
219
                    return str_replace(
220
                        ['<pre>', '<code>'],
221
                        ['<pre class="prettyprint">', '<code class="prettyprint">'],
222
                        $parser->text($value)
223
                    );
224
                },
225
                ['is_safe' => ['all']]
226
            ),
227
            'trans' => new TwigFilter(
228
                'trans',
229
                static function ($value) {
230
                    return $value;
231
                }
232
            ),
233
            'route' => new TwigFilter(
234
                'route',
235
                static function (
236
                    $value,
237
                    string $presentation = LinkRenderer::PRESENTATION_NORMAL
238
                ) use ($routeRenderer) {
239
                    return $routeRenderer->render($value, $presentation);
240
                },
241
                ['is_safe' => ['all']]
242
            ),
243
            'sort' => new TwigFilter(
244
                'sort_*',
245
                /** @var Collection<Descriptor> $collection */
0 ignored issues
show
Documentation introduced by
The doc-type Collection<Descriptor> could not be parsed: Expected "|" or "end of type", but got "<" at position 10. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
246
                static function (string $direction, Collection $collection) : ArrayIterator {
247
                    $iterator = $collection->getIterator();
248
                    $iterator->uasort(
249
                        static function (Descriptor $a, Descriptor $b) use ($direction) {
250
                            $aElem = strtolower($a->getName());
251
                            $bElem = strtolower($b->getName());
252
                            if ($aElem === $bElem) {
253
                                return 0;
254
                            }
255
256
                            if (($direction === 'asc' && $aElem > $bElem) ||
257
                                ($direction === 'desc' && $aElem < $bElem)
258
                            ) {
259
                                return 1;
260
                            }
261
262
                            return -1;
263
                        }
264
                    );
265
266
                    return $iterator;
267
                }
268
            ),
269
            'sortByVisibility' => new TwigFilter(
270
                'sortByVisibility',
271
                /** @var Collection<Descriptor> $collection */
0 ignored issues
show
Documentation introduced by
The doc-type Collection<Descriptor> could not be parsed: Expected "|" or "end of type", but got "<" at position 10. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
272
                static function (Collection $collection) : ArrayIterator {
273
                    $visibilityOrder = [
274
                        'public' => 0,
275
                        'protected' => 1,
276
                        'private' => 2,
277
                    ];
278
                    $iterator = $collection->getIterator();
279
                    $iterator->uasort(
280
                        static function (Descriptor $a, Descriptor $b) use ($visibilityOrder) {
281
                            $prio = 0;
282
                            if ($a instanceof VisibilityInterface && $b instanceof VisibilityInterface) {
283
                                $prio = ($visibilityOrder[$a->getVisibility()] ?? 0) <=> ($visibilityOrder[$b->getVisibility()] ?? 0);
284
                            }
285
286
                            if ($prio !== 0) {
287
                                return $prio;
288
                            }
289
290
                            $aElem = strtolower($a->getName());
291
                            $bElem = strtolower($b->getName());
292
293
                            return $aElem <=> $bElem;
294
                        }
295
                    );
296
297
                    return $iterator;
298
                }
299
            ),
300
            'export' => new TwigFilter(
301
                'export',
302
                static function ($var) {
303
                    return var_export($var, true);
304
                }
305
            ),
306
        ];
307
    }
308
}
309