TextExtension::linkifyMail()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Jasny\Twig;
4
5
use Twig\Extension\AbstractExtension;
6
use Twig\TwigFilter;
7
8
/**
9
 * Text functions for Twig.
10
 */
11
class TextExtension extends AbstractExtension
12
{
13
    /**
14
     * Return extension name
15
     *
16
     * @return string
17
     */
18
    public function getName()
19
    {
20
        return 'jasny/text';
21
    }
22
23
    /**
24
     * {@inheritdoc}
25
     */
26 25
    public function getFilters()
27
    {
28
        return [
29 25
            new TwigFilter('paragraph', [$this, 'paragraph'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
30 25
            new TwigFilter('line', [$this, 'line']),
31 25
            new TwigFilter('less', [$this, 'less'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
32 25
            new TwigFilter('truncate', [$this, 'truncate'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
33 25
            new TwigFilter('linkify', [$this, 'linkify'], ['pre_escape' => 'html', 'is_safe' => ['html']])
34
        ];
35
    }
36
37
    /**
38
     * Add paragraph and line breaks to text.
39
     *
40
     * @param string $value
41
     * @return string
42
     */
43 2
    public function paragraph($value)
44
    {
45 2
        if (!isset($value)) {
46 1
            return null;
47
        }
48
49 1
        return '<p>' . preg_replace(['~\n(\s*)\n\s*~', '~(?<!</p>)\n\s*~'], ["</p>\n\$1<p>", "<br>\n"], trim($value)) .
50 1
            '</p>';
51
    }
52
53
    /**
54
     * Get a single line
55
     *
56
     * @param string $value
57
     * @param int    $line   Line number (starts at 1)
58
     * @return string
59
     */
60 4
    public function line($value, $line = 1)
61
    {
62 4
        if (!isset($value)) {
63 1
            return null;
64
        }
65
66 3
        $lines = explode("\n", $value);
67
68 3
        return isset($lines[$line - 1]) ? $lines[$line - 1] : null;
69
    }
70
71
    /**
72
     * Cut of text on a pagebreak.
73
     *
74
     * @param string $value
75
     * @param string $replace
76
     * @param string $break
77
     * @return string
78
     */
79 4
    public function less($value, $replace = '...', $break = '<!-- pagebreak -->')
80
    {
81 4
        if (!isset($value)) {
82 1
            return null;
83
        }
84
85 3
        $pos = stripos($value, $break);
86 3
        return $pos === false ? $value : substr($value, 0, $pos) . $replace;
87
    }
88
89
    /**
90
     * Cut of text if it's to long.
91
     *
92
     * @param string $value
93
     * @param int    $length
94
     * @param string $replace
95
     * @return string
96
     */
97 4
    public function truncate($value, $length, $replace = '...')
98
    {
99 4
        if (!isset($value)) {
100 1
            return null;
101
        }
102
103 3
        return strlen($value) <= $length ? $value : substr($value, 0, $length - strlen($replace)) . $replace;
104
    }
105
106
    /**
107
     * Linkify a HTTP(S) link.
108
     *
109
     * @param string $protocol  'http' or 'https'
110
     * @param string $text
111
     * @param array  $links     OUTPUT
112
     * @param string $attr
113
     * @param string $mode
114
     * @return string
115
     */
116 6
    protected function linkifyHttp($protocol, $text, array &$links, $attr, $mode)
117
    {
118 6
        $regexp = $mode != 'all'
119 5
            ? '~(?:(https?)://([^\s<>]+)|(?<!\w@)\b(www\.[^\s<>]+?\.[^\s<>]+))(?<![\.,:;\?!\'"\|])~i'
120 6
            : '~(?:(https?)://([^\s<>]+)|(?<!\w@)\b([^\s<>@]+?\.[^\s<>]+)(?<![\.,:]))~i';
121
122
        return preg_replace_callback($regexp, function ($match) use ($protocol, &$links, $attr) {
123 5
            if ($match[1]) {
124
                $protocol = $match[1];
125
            }
126 5
            $link = $match[2] ?: $match[3];
127
128 5
            return '<' . array_push($links, '<a' . $attr . ' href="' . $protocol . '://' . $link . '">'
129 5
                . rtrim($link, '/') . '</a>') . '>';
130 6
        }, $text);
131
    }
132
133
    /**
134
     * Linkify a mail link.
135
     *
136
     * @param string $text
137
     * @param array  $links     OUTPUT
138
     * @param string $attr
139
     * @return string
140
     */
141 5
    protected function linkifyMail($text, array &$links, $attr)
142
    {
143 5
        $regexp = '~([^\s<>]+?@[^\s<>]+?\.[^\s<>]+)(?<![\.,:;\?!\'"\|])~';
144
145
        return preg_replace_callback($regexp, function ($match) use (&$links, $attr) {
146 4
            return '<' . array_push($links, '<a' . $attr . ' href="mailto:' . $match[1] . '">' . $match[1] . '</a>')
147 4
                . '>';
148 5
        }, $text);
149
    }
150
151
152
    /**
153
     * Linkify a link.
154
     *
155
     * @param string $protocol
156
     * @param string $text
157
     * @param array  $links     OUTPUT
158
     * @param string $attr
159
     * @param string $mode
160
     * @return string
161
     */
162 4
    protected function linkifyOther($protocol, $text, array &$links, $attr, $mode)
163
    {
164 4
        if (strpos($protocol, ':') === false) {
165 4
            $protocol .= in_array($protocol, ['ftp', 'tftp', 'ssh', 'scp']) ? '://' : ':';
166
        }
167
168 4
        $regexp = $mode != 'all'
169 2
            ? '~' . preg_quote($protocol, '~') . '([^\s<>]+)(?<![\.,:;\?!\'"\|])~i'
170 4
            : '~([^\s<>]+)(?<![\.,:])~i';
171
172
        return preg_replace_callback($regexp, function ($match) use ($protocol, &$links, $attr) {
173 4
            return '<' . array_push($links, '<a' . $attr . ' href="' . $protocol . $match[1] . '">' . $match[1]
174 4
                . '</a>') . '>';
175 4
        }, $text);
176
    }
177
178
    /**
179
     * Turn all URLs in clickable links.
180
     *
181
     * @param string $value
182
     * @param array  $protocols   'http'/'https', 'mail' and also 'ftp', 'scp', 'tel', etc
183
     * @param array  $attributes  HTML attributes for the link
184
     * @param string $mode        normal or all
185
     * @return string
186
     */
187 11
    public function linkify($value, $protocols = ['http', 'mail'], array $attributes = [], $mode = 'normal')
188
    {
189 11
        if (!isset($value)) {
190 1
            return null;
191
        }
192
193
        // Link attributes
194 10
        $attr = '';
195 10
        foreach ($attributes as $key => $val) {
196 1
            $attr .= ' ' . $key . '="' . htmlentities($val) . '"';
197
        }
198
199 10
        $links = [];
200
201
        // Extract existing links and tags
202
        $text = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) {
203 1
            return '<' . array_push($links, $match[1]) . '>';
204 10
        }, $value);
205
206
        // Extract text links for each protocol
207 10
        foreach ((array)$protocols as $protocol) {
208 10
            switch ($protocol) {
209 10
                case 'http':
210 10
                case 'https':
211 6
                    $text = $this->linkifyHttp($protocol, $text, $links, $attr, $mode);
212 6
                    break;
213 9
                case 'mail':
214 5
                    $text = $this->linkifyMail($text, $links, $attr);
215 5
                    break;
216
                default:
217 4
                    $text = $this->linkifyOther($protocol, $text, $links, $attr, $mode);
218 4
                    break;
219
            }
220
        }
221
222
        // Insert all link
223
        return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) {
224 10
            return $links[$match[1] - 1];
225 10
        }, $text);
226
    }
227
}
228