Renderer   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 209
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 37.5%

Importance

Changes 0
Metric Value
dl 0
loc 209
ccs 27
cts 72
cp 0.375
rs 9.36
c 0
b 0
f 0
wmc 38
lcom 1
cbo 4

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setDestination() 0 4 1
A getDestination() 0 4 1
B render() 0 16 7
B convertToRootPath() 0 22 6
A renderASeriesOfLinks() 0 13 3
B renderTypeCollection() 0 22 6
B renderLink() 0 29 11
A renderType() 0 9 2
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * This file is part of phpDocumentor.
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @author    Mike van Riel <[email protected]>
11
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
12
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
13
 * @link      http://phpdoc.org
14
 */
15
16
namespace phpDocumentor\Transformer\Router;
17
18
use phpDocumentor\Descriptor\Collection;
19
use phpDocumentor\Descriptor\DescriptorAbstract;
20
use phpDocumentor\Descriptor\Type\CollectionDescriptor;
21
use phpDocumentor\Reflection\Type;
22
23
/**
24
 * Renders an HTML anchor pointing to the location of the provided element.
25
 */
26
class Renderer
27
{
28
    /** @var string */
29
    protected $destination = '';
30
31
    /** @var Queue */
32
    private $routers;
33
34
    /**
35
     * Initializes this renderer with a set of routers that are checked.
36
     */
37 1
    public function __construct(Queue $routers)
38
    {
39 1
        $this->routers = $routers;
40 1
    }
41
42
    /**
43
     * Sets the destination directory relative to the Project's Root.
44
     *
45
     * The destination is the target directory containing the resulting
46
     * file. This destination is relative to the Project's root and can
47
     * be used for the calculation of nesting depths, etc.
48
     *
49
     * For this specific extension the destination is provided in the
50
     * Twig writer itself.
51
     *
52
     * @param string $destination
53
     *
54
     * @see \phpDocumentor\Transformer\Writer\Twig for the invocation
55
     *     of this method.
56
     */
57 1
    public function setDestination($destination)
58
    {
59 1
        $this->destination = $destination;
60 1
    }
61
62
    /**
63
     * Returns the target directory relative to the Project's Root.
64
     *
65
     * @return string
66
     */
67 1
    public function getDestination()
68
    {
69 1
        return $this->destination;
70
    }
71
72
    /**
73
     * @param string|DescriptorAbstract $value
74
     * @param string                    $presentation
75
     *
76
     * @return bool|mixed|string|\string[]
77
     */
78 9
    public function render($value, $presentation)
79
    {
80 9
        if (is_array($value) && current($value) instanceof Type) {
81
            return $this->renderType($value, $presentation);
82
        }
83
84 9
        if (is_array($value) || $value instanceof \Traversable || $value instanceof Collection) {
85 3
            return $this->renderASeriesOfLinks($value, $presentation);
86
        }
87
88 9
        if ($value instanceof CollectionDescriptor) {
89 2
            return $this->renderTypeCollection($value, $presentation);
90
        }
91
92 9
        return $this->renderLink($value, $presentation);
93
    }
94
95
    /**
96
     * Converts the given path to be relative to the root of the documentation
97
     * target directory.
98
     *
99
     * It is not possible to use absolute paths in documentation templates since
100
     * they may be used locally, or in a subfolder. As such we need to calculate
101
     * the number of levels to go up from the current document's directory and
102
     * then append the given path.
103
     *
104
     * For example:
105
     *
106
     *     Suppose you are in <root>/classes/my/class.html and you want open
107
     *     <root>/my/index.html then you provide 'my/index.html' to this method
108
     *     and it will convert it into ../../my/index.html (<root>/classes/my is
109
     *     two nesting levels until the root).
110
     *
111
     * This method does not try to normalize or optimize the paths in order to
112
     * save on development time and performance, and because it adds no real
113
     * value.
114
     *
115
     * @param string $relative_path
116
     *
117
     * @return string|null
118
     */
119 6
    public function convertToRootPath($relative_path): ?string
120
    {
121
        // get the path to the root directory
122 6
        $path_parts = explode(DIRECTORY_SEPARATOR, $this->getDestination());
123 6
        $path_to_root = (count($path_parts) > 1)
124 1
            ? implode('/', array_fill(0, count($path_parts) - 1, '..')) . '/'
125 6
            : '';
126
127
        // append the relative path to the root
128 6
        if (is_string($relative_path) && ($relative_path[0] !== '@')) {
129 4
            return $path_to_root . ltrim($relative_path, '/');
130
        }
131
132 2
        $rule = $this->routers->match($relative_path);
133 2
        if (!$rule) {
134 1
            return null;
135
        }
136
137 1
        $generatedPath = $rule->generate($relative_path);
138
139 1
        return $generatedPath ? $path_to_root . ltrim($generatedPath, '/') : null;
140
    }
141
142
    /**
143
     * Returns a series of anchors and strings for the given collection of routable items.
144
     *
145
     * @param array|\Traversable|Collection $value
146
     * @param string                        $presentation
147
     *
148
     * @return string[]
149
     */
150
    protected function renderASeriesOfLinks($value, $presentation): array
151
    {
152
        if ($value instanceof Collection) {
153
            $value = $value->getAll();
154
        }
155
156
        $result = [];
157
        foreach ($value as $path) {
158
            $result[] = $this->render($path, $presentation);
159
        }
160
161
        return $result;
162
    }
163
164
    /**
165
     * Renders the view representation for an array or collection.
166
     *
167
     * @param CollectionDescriptor $value
168
     * @param string               $presentation
169
     *
170
     * @return string
171
     */
172
    protected function renderTypeCollection($value, $presentation)
173
    {
174
        $baseType = $this->render($value->getBaseType(), $presentation);
0 ignored issues
show
Documentation introduced by Mike van Riel
$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...
175
        $keyTypes = $this->render($value->getKeyTypes(), $presentation);
0 ignored issues
show
Documentation introduced by Mike van Riel
$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...
176
        $types = $this->render($value->getTypes(), $presentation);
0 ignored issues
show
Documentation introduced by Mike van Riel
$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...
177
178
        $arguments = [];
179
        if ($keyTypes) {
180
            $arguments[] = implode('|', $keyTypes);
181
        }
182
183
        $arguments[] = implode('|', $types);
184
185
        if ($value->getName() === 'array' && count($value->getKeyTypes()) === 0) {
186
            $typeString = (count($types) > 1) ? '(' . reset($arguments) . ')' : reset($arguments);
187
            $collection = $typeString . '[]';
188
        } else {
189
            $collection = ($baseType ?: $value->getName()) . '&lt;' . implode(',', $arguments) . '&gt;';
190
        }
191
192
        return $collection;
193
    }
194
195
    protected function renderLink($path, $presentation)
196
    {
197
        $url = false;
198
        $rule = $this->routers->match($path);
199
        if ($rule) {
200
            $generatedUrl = $rule->generate($path);
201
            $url = $generatedUrl ? ltrim($generatedUrl, '/') : false;
202
        }
203
204
        if (is_string($url)
205
            && $url[0] !== '/'
206
            && (strpos($url, 'http://') !== 0)
207
            && (strpos($url, 'https://') !== 0)
208
            && (strpos($url, 'ftp://') !== 0)
209
        ) {
210
            $url = $this->convertToRootPath($url);
211
        }
212
213
        switch ($presentation) {
214
            case 'url': // return the first url
215
                return $url;
216
            case 'class:short':
217
                $parts = explode('\\', (string) $path);
218
                $path = end($parts);
219
                break;
220
        }
221
222
        return $url ? sprintf('<a href="%s">%s</a>', $url, $path) : $path;
223
    }
224
225
    private function renderType($value, string $presentation): array
0 ignored issues
show
Unused Code introduced by Jaapio
The parameter $presentation 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...
226
    {
227
        $result = [];
228
        foreach ($value as $type) {
229
            $result[] = (string) $type;
230
        }
231
232
        return $result;
233
    }
234
}
235