Completed
Push — develop ( 8eb671...133594 )
by Mike
19:30 queued 09:24
created

src/phpDocumentor/Transformer/Router/Renderer.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
     * @param Queue $routers
38
     */
39 3
    public function __construct($routers)
40
    {
41 3
        $this->routers = $routers;
42 3
    }
43
44
    /**
45
     * Overwrites the associated routers with a new set of routers.
46
     *
47
     * @param Queue $routers
48
     */
49 1
    public function setRouters($routers)
50
    {
51 1
        $this->routers = $routers;
52 1
    }
53
54
    /**
55
     * Returns the routers used in generating the URLs for the anchors.
56
     *
57
     * @return Queue
58
     */
59 2
    public function getRouters()
60
    {
61 2
        return $this->routers;
62
    }
63
64
    /**
65
     * Sets the destination directory relative to the Project's Root.
66
     *
67
     * The destination is the target directory containing the resulting
68
     * file. This destination is relative to the Project's root and can
69
     * be used for the calculation of nesting depths, etc.
70
     *
71
     * For this specific extension the destination is provided in the
72
     * Twig writer itself.
73
     *
74
     * @param string $destination
75
     *
76
     * @see phpDocumentor\Transformer\Writer\Twig for the invocation
77
     *     of this method.
78
     */
79 1
    public function setDestination($destination)
80
    {
81 1
        $this->destination = $destination;
82 1
    }
83
84
    /**
85
     * Returns the target directory relative to the Project's Root.
86
     *
87
     * @return string
88
     */
89 1
    public function getDestination()
90
    {
91 1
        return $this->destination;
92
    }
93
94
    /**
95
     * @param string|DescriptorAbstract $value
96
     * @param string                    $presentation
97
     *
98
     * @return bool|mixed|string|\string[]
99
     */
100 9
    public function render($value, $presentation)
101
    {
102 9
        if (is_array($value) && current($value) instanceof Type) {
103
            return $this->renderType($value, $presentation);
104
        }
105
106 9
        if (is_array($value) || $value instanceof \Traversable || $value instanceof Collection) {
107 3
            return $this->renderASeriesOfLinks($value, $presentation);
108
        }
109
110 9
        if ($value instanceof CollectionDescriptor) {
111 2
            return $this->renderTypeCollection($value, $presentation);
112
        }
113
114 9
        return $this->renderLink($value, $presentation);
115
    }
116
117
    /**
118
     * Converts the given path to be relative to the root of the documentation
119
     * target directory.
120
     *
121
     * It is not possible to use absolute paths in documentation templates since
122
     * they may be used locally, or in a subfolder. As such we need to calculate
123
     * the number of levels to go up from the current document's directory and
124
     * then append the given path.
125
     *
126
     * For example:
127
     *
128
     *     Suppose you are in <root>/classes/my/class.html and you want open
129
     *     <root>/my/index.html then you provide 'my/index.html' to this method
130
     *     and it will convert it into ../../my/index.html (<root>/classes/my is
131
     *     two nesting levels until the root).
132
     *
133
     * This method does not try to normalize or optimize the paths in order to
134
     * save on development time and performance, and because it adds no real
135
     * value.
136
     *
137
     * @param string $relative_path
138
     *
139
     * @return string|null
140
     */
141 6
    public function convertToRootPath($relative_path): ?string
142
    {
143
        // get the path to the root directory
144 6
        $path_parts = explode(DIRECTORY_SEPARATOR, $this->getDestination());
145 6
        $path_to_root = (count($path_parts) > 1)
146 1
            ? implode('/', array_fill(0, count($path_parts) - 1, '..')) . '/'
147 6
            : '';
148
149
        // append the relative path to the root
150 6
        if (is_string($relative_path) && ($relative_path[0] !== '@')) {
151 4
            return $path_to_root . ltrim($relative_path, '/');
152
        }
153
154 2
        $rule = $this->routers->match($relative_path);
155 2
        if (!$rule) {
156 1
            return null;
157
        }
158
159 1
        $generatedPath = $rule->generate($relative_path);
160
161 1
        return $generatedPath ? $path_to_root . ltrim($generatedPath, '/') : null;
162
    }
163
164
    /**
165
     * Returns a series of anchors and strings for the given collection of routable items.
166
     *
167
     * @param array|\Traversable|Collection $value
168
     * @param string                        $presentation
169
     *
170
     * @return string[]
171
     */
172 3
    protected function renderASeriesOfLinks($value, $presentation): array
173
    {
174 3
        if ($value instanceof Collection) {
175 1
            $value = $value->getAll();
176
        }
177
178 3
        $result = [];
179 3
        foreach ($value as $path) {
180 3
            $result[] = $this->render($path, $presentation);
181
        }
182
183 3
        return $result;
184
    }
185
186
    /**
187
     * Renders the view representation for an array or collection.
188
     *
189
     * @param CollectionDescriptor $value
190
     * @param string               $presentation
191
     *
192
     * @return string
193
     */
194 2
    protected function renderTypeCollection($value, $presentation)
195
    {
196 2
        $baseType = $this->render($value->getBaseType(), $presentation);
197 2
        $keyTypes = $this->render($value->getKeyTypes(), $presentation);
198 2
        $types = $this->render($value->getTypes(), $presentation);
199
200 2
        $arguments = [];
201 2
        if ($keyTypes) {
202 1
            $arguments[] = implode('|', $keyTypes);
203
        }
204
205 2
        $arguments[] = implode('|', $types);
206
207 2
        if ($value->getName() === 'array' && count($value->getKeyTypes()) === 0) {
208 1
            $typeString = (count($types) > 1) ? '(' . reset($arguments) . ')' : reset($arguments);
209 1
            $collection = $typeString . '[]';
210
        } else {
211 1
            $collection = ($baseType ?: $value->getName()) . '&lt;' . implode(',', $arguments) . '&gt;';
212
        }
213
214 2
        return $collection;
215
    }
216
217 9
    protected function renderLink($path, $presentation)
218
    {
219 9
        $url = false;
220 9
        $rule = $this->routers->match($path);
221 9
        if ($rule) {
222 9
            $generatedUrl = $rule->generate($path);
223 9
            $url = $generatedUrl ? ltrim($generatedUrl, '/') : false;
224
        }
225
226 9
        if (is_string($url)
227 9
            && $url[0] !== '/'
228 9
            && (strpos($url, 'http://') !== 0)
229 9
            && (strpos($url, 'https://') !== 0)
230 9
            && (strpos($url, 'ftp://') !== 0)
231
        ) {
232 6
            $url = $this->convertToRootPath($url);
233
        }
234
235
        switch ($presentation) {
236 9
            case 'url': // return the first url
237 8
                return $url;
238 1
            case 'class:short':
239 1
                $parts = explode('\\', (string) $path);
240 1
                $path = end($parts);
241 1
                break;
242
        }
243
244 1
        return $url ? sprintf('<a href="%s">%s</a>', $url, $path) : $path;
245
    }
246
247
    private function renderType($value, string $presentation): array
0 ignored issues
show
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...
248
    {
249
        $result = [];
250
        foreach ($value as $type) {
251
            $result[] = (string) $type;
252
        }
253
254
        return $result;
255
    }
256
}
257