Completed
Pull Request — master (#13)
by
unknown
04:12
created

TextExtension   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 212
Duplicated Lines 7.08 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 96%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 2
dl 15
loc 212
ccs 72
cts 75
cp 0.96
rs 9
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 4 1
A paragraph() 0 9 2
A line() 0 10 3
A getFilters() 0 10 1
B less() 4 13 6
B truncate() 3 10 6
A linkifyHttp() 0 14 4
A linkifyMail() 4 9 1
A linkifyOther() 4 15 4
C linkify() 0 34 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Jasny\Twig;
4
5
/**
6
 * Text functions for Twig.
7
 */
8
class TextExtension extends \Twig_Extension
9
{
10
    /**
11
     * Return extension name
12
     * 
13
     * @return string
14
     */
15 25
    public function getName()
16
    {
17 25
        return 'jasny/text';
18
    }
19
    
20
    /**
21
     * {@inheritdoc}
22
     */
23 25
    public function getFilters()
24
    {
25
        return [
26 25
            new \Twig_SimpleFilter('paragraph', [$this, 'paragraph'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
27 25
            new \Twig_SimpleFilter('line', [$this, 'line']),
28 25
            new \Twig_SimpleFilter('less', [$this, 'less'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
29 25
            new \Twig_SimpleFilter('truncate', [$this, 'truncate'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
30 25
            new \Twig_SimpleFilter('linkify', [$this, 'linkify'], ['pre_escape' => 'html', 'is_safe' => ['html']])
31 25
        ];
32
    }
33
34
    /**
35
     * Add paragraph and line breaks to text.
36
     * 
37
     * @param string $value
38
     * @return string
39
     */
40 2
    public function paragraph($value)
41
    {
42 2
        if (!isset($value)) {
43 1
            return null;
44
        }
45
        
46 1
        return '<p>' . preg_replace(['~\n(\s*)\n\s*~', '~(?<!</p>)\n\s*~'], ["</p>\n\$1<p>", "<br>\n"], trim($value)) .
47 1
            '</p>';
48
    }
49
50
    /**
51
     * Get a single line
52
     * 
53
     * @param string $value 
54
     * @param int    $line   Line number (starts at 1)
55
     * @return string
56
     */
57 4
    public function line($value, $line = 1)
58
    {
59 4
        if (!isset($value)) {
60 1
            return null;
61
        }
62
        
63 3
        $lines = explode("\n", $value);
64
        
65 3
        return isset($lines[$line - 1]) ? $lines[$line - 1] : null;
66
    }
67
    
68
    /**
69
     * Cut of text on a pagebreak.
70
     * 
71
     * @param string $value
72
     * @param string $replace
73
     * @param string $break
74
     * @return string
75
     */
76 4
    public function less($value, $replace = '...', $break = '<!-- pagebreak -->')
77
    {
78 4
        if (!isset($value)) {
79 1
            return null;
80
        }
81
82 3 View Code Duplication
        if (function_exists('mb_stripos') && function_exists('mb_substr')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83 3
            $pos = mb_stripos($value, $break);
84 3
            return $pos === false ? $value : mb_substr($value, 0, $pos) . $replace;
85
        }
86
        $pos = stripos($value, $break);
87
        return $pos === false ? $value : substr($value, 0, $pos) . $replace;
88
    }
89
90
    /**
91
     * Cut of text if it's to long.
92
     * 
93
     * @param string $value
94
     * @param int    $length
95
     * @param string $replace
96
     * @return string
97
     */
98 4
    public function truncate($value, $length, $replace = '...')
99
    {
100 4
        if (!isset($value)) {
101 1
            return null;
102
        }
103 3 View Code Duplication
        if (function_exists('mb_strlen') && function_exists('mb_substr')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
104 3
            return mb_strlen($value) <= $length ? $value : mb_substr($value, 0, $length - strlen($replace)) . $replace;
105
        }
106
        return strlen($value) <= $length ? $value : substr($value, 0, $length - strlen($replace)) . $replace;
107
    }
108
    
109
    /**
110
     * Linkify a HTTP(S) link.
111
     * 
112
     * @param string $protocol  'http' or 'https'
113
     * @param string $text
114
     * @param array  $links     OUTPUT
115
     * @param string $attr
116
     * @param string $mode
117
     */
118 6
    protected function linkifyHttp($protocol, $text, array &$links, $attr, $mode)
119
    {
120
        $regexp = $mode != 'all'
121 6
            ? '~(?:(https?)://([^\s<>]+)|(?<!\w@)\b(www\.[^\s<>]+?\.[^\s<>]+))(?<![\.,:;\?!\'"\|])~i'
122 6
            : '~(?:(https?)://([^\s<>]+)|(?<!\w@)\b([^\s<>@]+?\.[^\s<>]+)(?<![\.,:]))~i';
123
        
124
        return preg_replace_callback($regexp, function ($match) use ($protocol, &$links, $attr) {
125 5
            if ($match[1]) $protocol = $match[1];
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $protocol, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
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
     */
140 5
    protected function linkifyMail($text, array &$links, $attr)
141
    {
142 5
        $regexp = '~([^\s<>]+?@[^\s<>]+?\.[^\s<>]+)(?<![\.,:;\?!\'"\|])~';
143
        
144 View Code Duplication
        return preg_replace_callback($regexp, function ($match) use (&$links, $attr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145 4
            return '<' . array_push($links, '<a' . $attr . ' href="mailto:' . $match[1] . '">' . $match[1] . '</a>')
146 4
                . '>';
147 5
        }, $text);
148
    }
149
    
150
    
151
    /**
152
     * Linkify a link.
153
     * 
154
     * @param string $protocol
155
     * @param string $text
156
     * @param array  $links     OUTPUT
157
     * @param string $attr
158
     * @param string $mode
159
     */
160 4
    protected function linkifyOther($protocol, $text, array &$links, $attr, $mode)
161
    {
162 4
        if (strpos($protocol, ':') === false) {
163 4
            $protocol .= in_array($protocol, ['ftp', 'tftp', 'ssh', 'scp']) ? '://' : ':';
164 4
        }
165
        
166
        $regexp = $mode != 'all'
167 4
            ? '~' . preg_quote($protocol, '~') . '([^\s<>]+)(?<![\.,:;\?!\'"\|])~i'
168 4
            : '~([^\s<>]+)(?<![\.,:])~i';
169
        
170 View Code Duplication
        return preg_replace_callback($regexp, function ($match) use ($protocol, &$links, $attr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171 4
            return '<' . array_push($links, '<a' . $attr . ' href="' . $protocol . $match[1] . '">' . $match[1]
172 4
                . '</a>') . '>';
173 4
        }, $text);
174
    }
175
    
176
    /**
177
     * Turn all URLs in clickable links.
178
     * 
179
     * @param string $value
180
     * @param array  $protocols   'http'/'https', 'mail' and also 'ftp', 'scp', 'tel', etc
181
     * @param array  $attributes  HTML attributes for the link
182
     * @param string $mode        normal or all
183
     * @return string
184
     */
185 11
    public function linkify($value, $protocols = ['http', 'mail'], array $attributes = [], $mode = 'normal')
186
    {
187 11
        if (!isset($value)) {
188 1
            return null;
189
        }
190
        
191
        // Link attributes
192 10
        $attr = '';
193 10
        foreach ($attributes as $key => $val) {
194 1
            $attr .= ' ' . $key . '="' . htmlentities($val) . '"';
195 10
        }
196
        
197 10
        $links = [];
198
        
199
        // Extract existing links and tags
200
        $text = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) {
201 1
            return '<' . array_push($links, $match[1]) . '>';
202 10
        }, $value);
203
        
204
        // Extract text links for each protocol
205 10
        foreach ((array)$protocols as $protocol) {
206
            switch ($protocol) {
207 10
                case 'http':
208 10
                case 'https':   $text = $this->linkifyHttp($protocol, $text, $links, $attr, $mode); break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
209 9
                case 'mail':    $text = $this->linkifyMail($text, $links, $attr); break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
210 4
                default:        $text = $this->linkifyOther($protocol, $text, $links, $attr, $mode); break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
211 4
            }
212 10
        }
213
        
214
        // Insert all link
215 10
        return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) {
216 10
            return $links[$match[1] - 1];
217 10
        }, $text);
218
    }
219
}
220