Completed
Push — develop ( 722f70...af048b )
by Jaap
15:12 queued 05:04
created

Renderer::renderLink()   D

Complexity

Conditions 10
Paths 30

Size

Total Lines 28
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 19
nc 30
nop 2
dl 0
loc 28
rs 4.8196
c 0
b 0
f 0

How to fix   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\Transformer\Router;
4
5
use phpDocumentor\Descriptor\Collection;
6
use phpDocumentor\Descriptor\DescriptorAbstract;
7
use phpDocumentor\Descriptor\Type\CollectionDescriptor;
8
9
/**
10
 * Renders an HTML anchor pointing to the location of the provided element.
11
 */
12
class Renderer
13
{
14
    /** @var string */
15
    protected $destination = '';
16
17
    /** @var Queue */
18
    private $routers;
19
20
    /**
21
     * Initializes this renderer with a set of routers that are checked.
22
     *
23
     * @param Queue $routers
24
     */
25
    public function __construct($routers)
26
    {
27
        $this->routers = $routers;
28
    }
29
30
    /**
31
     * Overwrites the associated routers with a new set of routers.
32
     *
33
     * @param Queue $routers
34
     *
35
     * @return void
36
     */
37
    public function setRouters($routers)
38
    {
39
        $this->routers = $routers;
40
    }
41
42
    /**
43
     * Returns the routers used in generating the URLs for the anchors.
44
     *
45
     * @return Queue
46
     */
47
    public function getRouters()
48
    {
49
        return $this->routers;
50
    }
51
52
    /**
53
     * Sets the destination directory relative to the Project's Root.
54
     *
55
     * The destination is the target directory containing the resulting
56
     * file. This destination is relative to the Project's root and can
57
     * be used for the calculation of nesting depths, etc.
58
     *
59
     * For this specific extension the destination is provided in the
60
     * Twig writer itself.
61
     *
62
     * @param string $destination
63
     *
64
     * @see phpDocumentor\Plugin\Twig\Transformer\Writer\Twig for the invocation
65
     *     of this method.
66
     *
67
     * @return void
68
     */
69
    public function setDestination($destination)
70
    {
71
        $this->destination = $destination;
72
    }
73
74
    /**
75
     * Returns the target directory relative to the Project's Root.
76
     *
77
     * @return string
78
     */
79
    public function getDestination()
80
    {
81
        return $this->destination;
82
    }
83
84
    /**
85
     * @param string|DescriptorAbstract $value
86
     * @param string                    $presentation
87
     *
88
     * @return bool|mixed|string|\string[]
89
     */
90
    public function render($value, $presentation)
91
    {
92
        if (is_array($value) || $value instanceof \Traversable || $value instanceof Collection) {
93
            return $this->renderASeriesOfLinks($value, $presentation);
94
        }
95
96
        if ($value instanceof CollectionDescriptor) {
97
            return $this->renderTypeCollection($value, $presentation);
98
        }
99
100
        return $this->renderLink($value, $presentation);
101
    }
102
103
    /**
104
     * Converts the given path to be relative to the root of the documentation
105
     * target directory.
106
     *
107
     * It is not possible to use absolute paths in documentation templates since
108
     * they may be used locally, or in a subfolder. As such we need to calculate
109
     * the number of levels to go up from the current document's directory and
110
     * then append the given path.
111
     *
112
     * For example:
113
     *
114
     *     Suppose you are in <root>/classes/my/class.html and you want open
115
     *     <root>/my/index.html then you provide 'my/index.html' to this method
116
     *     and it will convert it into ../../my/index.html (<root>/classes/my is
117
     *     two nesting levels until the root).
118
     *
119
     * This method does not try to normalize or optimize the paths in order to
120
     * save on development time and performance, and because it adds no real
121
     * value.
122
     *
123
     * @param string $relative_path
124
     *
125
     * @return string
126
     */
127
    public function convertToRootPath($relative_path)
128
    {
129
        // get the path to the root directory
130
        $path_parts   = explode(DIRECTORY_SEPARATOR, $this->getDestination());
131
        $path_to_root = (count($path_parts) > 1)
132
            ? implode('/', array_fill(0, count($path_parts) -1, '..')).'/'
133
            : '';
134
135
        // append the relative path to the root
136
        if (is_string($relative_path) && ($relative_path[0] != '@')) {
137
            return $path_to_root . ltrim($relative_path, '/');
138
        }
139
140
        $rule = $this->routers->match($relative_path);
141
        if (!$rule) {
142
            return null;
143
        }
144
145
        $generatedPath = $rule->generate($relative_path);
146
147
        return $generatedPath ? $path_to_root . ltrim($generatedPath, '/') : null;
148
    }
149
150
    /**
151
     * Returns a series of anchors and strings for the given collection of routable items.
152
     *
153
     * @param array|\Traversable|Collection $value
154
     * @param string                        $presentation
155
     *
156
     * @return string[]
157
     */
158
    protected function renderASeriesOfLinks($value, $presentation)
159
    {
160
        if ($value instanceof Collection) {
161
            $value = $value->getAll();
162
        }
163
164
        $result = array();
165
        foreach ($value as $path) {
166
            $result[] = $this->render($path, $presentation);
167
        }
168
169
        return $result;
170
    }
171
172
    /**
173
     * Renders the view representation for an array or collection.
174
     *
175
     * @param CollectionDescriptor $value
176
     * @param string               $presentation
177
     *
178
     * @return string
179
     */
180
    protected function renderTypeCollection($value, $presentation)
181
    {
182
        $baseType = $this->render($value->getBaseType(), $presentation);
0 ignored issues
show
Documentation introduced by
$value->getBaseType() is of type object<phpDocumentor\Des...ces\TypeInterface>|null, but the function expects a string|object<phpDocumen...tor\DescriptorAbstract>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
183
        $keyTypes = $this->render($value->getKeyTypes(), $presentation);
0 ignored issues
show
Documentation introduced by
$value->getKeyTypes() is of type array<integer,object<php...erfaces\TypeInterface>>, but the function expects a string|object<phpDocumen...tor\DescriptorAbstract>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
184
        $types = $this->render($value->getTypes(), $presentation);
0 ignored issues
show
Documentation introduced by
$value->getTypes() is of type array<integer,object<php...erfaces\TypeInterface>>, but the function expects a string|object<phpDocumen...tor\DescriptorAbstract>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
185
186
        $arguments = array();
187
        if ($keyTypes) {
188
            $arguments[] = implode('|', $keyTypes);
189
        }
190
        $arguments[] = implode('|', $types);
191
192
        if ($value->getName() == 'array' && count($value->getKeyTypes()) == 0) {
193
            $typeString = (count($types) > 1) ? '(' . reset($arguments) . ')' : reset($arguments);
194
            $collection = $typeString . '[]';
195
        } else {
196
            $collection = ($baseType ? : $value->getName()) . '&lt;' . implode(',', $arguments) . '&gt;';
197
        }
198
199
        return $collection;
200
    }
201
202
    protected function renderLink($path, $presentation)
0 ignored issues
show
Complexity introduced by
This operation has 300 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...
203
    {
204
        $url  = false;
205
        $rule = $this->routers->match($path);
206
        if ($rule) {
207
            $generatedUrl = $rule->generate($path);
208
            $url = $generatedUrl ? ltrim($generatedUrl, '/') : false;
209
        }
210
211
        if (is_string($url)
212
            && $url[0] != '/'
213
            && (strpos($url, 'http://') !== 0)
214
            && (strpos($url, 'https://') !== 0)
215
        ) {
216
            $url = $this->convertToRootPath($url);
217
        }
218
219
        switch ($presentation) {
220
            case 'url': // return the first url
221
                return $url;
222
            case 'class:short':
223
                $parts = explode('\\', $path);
224
                $path = end($parts);
225
                break;
226
        }
227
228
        return $url ? sprintf('<a href="%s">%s</a>', $url, $path) : $path;
229
    }
230
}
231