Completed
Push — master ( 09a7d5...a22bfe )
by Mike
02:34
created

SpanNodeRenderer::renderTokens()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
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\Guides\NodeRenderers;
15
16
use InvalidArgumentException;
17
use phpDocumentor\Guides\Environment;
18
use phpDocumentor\Guides\InvalidLink;
19
use phpDocumentor\Guides\Nodes\Node;
20
use phpDocumentor\Guides\Nodes\SpanNode;
21
use phpDocumentor\Guides\RestructuredText\Span\SpanToken;
22
use function get_class;
23
use function is_string;
24
use function preg_replace;
25
use function preg_replace_callback;
26
use function sprintf;
27
use function str_replace;
28
29
abstract class SpanNodeRenderer implements NodeRenderer, SpanRenderer
30
{
31
    /** @var Environment */
32
    protected $environment;
33
34
    public function __construct(Environment $environment)
35
    {
36
        $this->environment = $environment;
37
    }
38
39
    public function render(Node $node) : string
40
    {
41
        if ($node instanceof SpanNode === false) {
42
            throw new InvalidArgumentException('Invalid node presented');
43
        }
44
45
        $value = $node->getValue();
46
47
        $span = $this->renderSyntaxes($value);
0 ignored issues
show
Documentation introduced by
$value is of type callable|null, but the function expects a string.

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...
48
49
        $span = $this->renderTokens($node, $span);
50
51
        return $span;
52
    }
53
54
    /**
55
     * @param string[] $attributes
56
     */
57
    public function link(?string $url, string $title, array $attributes = []) : string
58
    {
59
        $url = (string) $url;
60
61
        return $this->environment->getRenderer()->render(
62
            'link.html.twig',
63
            [
64
                'url' => $this->environment->generateUrl($url),
65
                'title' => $title,
66
                'attributes' => $attributes,
67
            ]
68
        );
69
    }
70
71
    private function renderSyntaxes(string $span) : string
72
    {
73
        $span = $this->escape($span);
74
75
        $span = $this->renderStrongEmphasis($span);
76
77
        $span = $this->renderEmphasis($span);
78
79
        $span = $this->renderNbsp($span);
80
81
        $span = $this->renderVariables($span);
82
83
        $span = $this->renderBrs($span);
84
85
        return $span;
86
    }
87
88
    private function renderStrongEmphasis(string $span) : string
89
    {
90
        return preg_replace_callback(
91
            '/\*\*(.+)\*\*/mUsi',
92
            function (array $matches) : string {
93
                return $this->strongEmphasis($matches[1]);
94
            },
95
            $span
96
        );
97
    }
98
99
    private function renderEmphasis(string $span) : string
100
    {
101
        return preg_replace_callback(
102
            '/\*(.+)\*/mUsi',
103
            function (array $matches) : string {
104
                return $this->emphasis($matches[1]);
105
            },
106
            $span
107
        );
108
    }
109
110
    private function renderNbsp(string $span) : string
111
    {
112
        return preg_replace('/~/', $this->nbsp(), $span);
113
    }
114
115
    private function renderVariables(string $span) : string
116
    {
117
        return preg_replace_callback(
118
            '/\|(.+)\|/mUsi',
119
            function (array $match) : string {
120
                $variable = $this->environment->getVariable($match[1]);
121
122
                if ($variable === null) {
123
                    return '';
124
                }
125
126
                if ($variable instanceof Node) {
127
                    return $this->environment->getNodeRendererFactory()
128
                        ->get(get_class($variable))
129
                        ->render($variable);
130
                }
131
132
                if (is_string($variable)) {
133
                    return $variable;
134
                }
135
136
                return (string) $variable;
137
            },
138
            $span
139
        );
140
    }
141
142
    private function renderBrs(string $span) : string
143
    {
144
        // Adding brs when a space is at the end of a line
145
        return preg_replace('/ \n/', $this->br(), $span);
146
    }
147
148
    private function renderTokens(SpanNode $node, string $span) : string
149
    {
150
        foreach ($node->getTokens() as $token) {
151
            $span = $this->renderToken($token, $span);
152
        }
153
154
        return $span;
155
    }
156
157
    private function renderToken(SpanToken $spanToken, string $span) : string
158
    {
159
        switch ($spanToken->getType()) {
160
            case SpanToken::TYPE_LITERAL:
161
                return $this->renderLiteral($spanToken, $span);
162
            case SpanToken::TYPE_REFERENCE:
163
                return $this->renderReference($spanToken, $span);
164
            case SpanToken::TYPE_LINK:
165
                return $this->renderLink($spanToken, $span);
166
        }
167
168
        throw new InvalidArgumentException(sprintf('Unknown token type %s', $spanToken->getType()));
169
    }
170
171
    private function renderLiteral(SpanToken $spanToken, string $span) : string
172
    {
173
        return str_replace(
174
            $spanToken->getId(),
175
            $this->literal($spanToken->get('text')),
176
            $span
177
        );
178
    }
179
180
    private function renderReference(SpanToken $spanToken, string $span) : string
181
    {
182
        $reference = $this->environment->resolve($spanToken->get('section'), $spanToken->get('url'));
183
184
        if ($reference === null) {
185
            $this->environment->addInvalidLink(new InvalidLink($spanToken->get('url')));
186
187
            return str_replace($spanToken->getId(), $spanToken->get('text'), $span);
188
        }
189
190
        $link = $this->reference($reference, $spanToken->getTokenData());
191
192
        return str_replace($spanToken->getId(), $link, $span);
193
    }
194
195
    private function renderLink(SpanToken $spanToken, string $span) : string
196
    {
197
        $url = $spanToken->get('url');
198
        $link = $spanToken->get('link');
199
200
        if ($url === '') {
201
            $url = $this->environment->getLink($link);
202
203
            if ($url === '') {
204
                $metaEntry = $this->environment->getMetaEntry();
205
206
                if ($metaEntry !== null && $metaEntry->hasTitle($link)) {
207
                    $url = $metaEntry->getUrl() . '#' . Environment::slugify($link);
208
                }
209
            }
210
211
            if ($url === '') {
212
                $this->environment->addInvalidLink(new InvalidLink($link));
213
214
                return str_replace($spanToken->getId(), $link, $span);
215
            }
216
        }
217
218
        $link = $this->link($url, $this->renderSyntaxes($link));
219
220
        return str_replace($spanToken->getId(), $link, $span);
221
    }
222
}
223