1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of the Sonata Project package. |
7
|
|
|
* |
8
|
|
|
* (c) Thomas Rabaix <[email protected]> |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, please view the LICENSE |
11
|
|
|
* file that was distributed with this source code. |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace Sonata\AdminBundle\Twig\Extension; |
15
|
|
|
|
16
|
|
|
use Symfony\Component\String\UnicodeString as SymfonyUnicodeString; |
17
|
|
|
use Twig\Environment; |
18
|
|
|
use Twig\Extension\AbstractExtension; |
19
|
|
|
use Twig\Extensions\TextExtension; |
20
|
|
|
use Twig\TwigFilter; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* NEXT_MAJOR: Remove this class. |
24
|
|
|
* |
25
|
|
|
* Decorates `Twig\Extra\String\StringExtension` in order to provide the `$cut` |
26
|
|
|
* argument for `Symfony\Component\String\UnicodeString::truncate()`. |
27
|
|
|
* This class must be removed when the component ships this feature. |
28
|
|
|
* |
29
|
|
|
* @internal |
30
|
|
|
* |
31
|
|
|
* @see https://github.com/symfony/symfony/pull/35649 |
32
|
|
|
* @deprecated since sonata-project/admin-bundle 3.69, to be removed in 4.0. |
33
|
|
|
* |
34
|
|
|
* @author Javier Spagnoletti <[email protected]> |
35
|
|
|
*/ |
36
|
|
|
final class StringExtension extends AbstractExtension |
37
|
|
|
{ |
38
|
|
|
/** |
39
|
|
|
* @var AbstractExtension |
40
|
|
|
*/ |
41
|
|
|
private $legacyExtension; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var bool |
45
|
|
|
*/ |
46
|
|
|
private $legacy; |
47
|
|
|
|
48
|
|
|
public function __construct(?AbstractExtension $legacyExtension = null) |
49
|
|
|
{ |
50
|
|
|
if (!$legacyExtension instanceof TextExtension && !$legacyExtension instanceof DeprecatedTextExtension) { |
51
|
|
|
throw new \TypeError(sprintf( |
|
|
|
|
52
|
|
|
'Argument 1 passed to %s::__construct() must be instance of %s or %s', |
53
|
|
|
self::class, |
54
|
|
|
TextExtension::class, |
55
|
|
|
DeprecatedTextExtension::class |
56
|
|
|
)); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
$this->legacyExtension = $legacyExtension; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @return TwigFilter[] |
64
|
|
|
*/ |
65
|
|
|
public function getFilters(): array |
66
|
|
|
{ |
67
|
|
|
return [ |
68
|
|
|
new TwigFilter('sonata_truncate', [$this, 'deprecatedTruncate'], ['needs_environment' => true]), |
69
|
|
|
]; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @return SymfonyUnicodeString|string |
74
|
|
|
*/ |
75
|
|
|
public function deprecatedTruncate(Environment $env, ?string $text, int $length = 30, bool $preserve = false, string $ellipsis = '...') |
76
|
|
|
{ |
77
|
|
|
@trigger_error( |
|
|
|
|
78
|
|
|
'The "sonata_truncate" twig filter is deprecated' |
79
|
|
|
.' since sonata-project/admin-bundle 3.69 and will be removed in 4.0. Use "u.truncate" instead.', |
80
|
|
|
E_USER_DEPRECATED |
81
|
|
|
); |
82
|
|
|
|
83
|
|
|
if ($this->legacyExtension instanceof TextExtension) { |
84
|
|
|
return twig_truncate_filter($env, $text, $length, $preserve, $ellipsis); |
|
|
|
|
85
|
|
|
} elseif ($this->legacyExtension instanceof DeprecatedTextExtension) { |
86
|
|
|
return $this->legacyExtension->twigTruncateFilter($env, $text, $length, $preserve, $ellipsis); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
return $this->legacyTruncteWithUnicodeString($text, $length, $preserve, $ellipsis); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
public function legacyTruncteWithUnicodeString(?string $text, int $length = 30, bool $preserve = false, string $ellipsis = '...'): SymfonyUnicodeString |
93
|
|
|
{ |
94
|
|
|
return (new SymfonyUnicodeString($text ?? ''))->truncate($length, $ellipsis, $preserve); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
private function twigTruncateFilter(Environment $env, ?string $value, int $length = 30, bool $preserve = false, $separator = '...') |
|
|
|
|
98
|
|
|
{ |
99
|
|
|
if (\function_exists('mb_get_info')) { |
100
|
|
|
if (mb_strlen($value, $env->getCharset()) > $length) { |
101
|
|
|
if ($preserve) { |
102
|
|
|
// If breakpoint is on the last word, return the value without separator. |
103
|
|
|
if (false === ($breakpoint = mb_strpos($value, ' ', $length, $env->getCharset()))) { |
104
|
|
|
return $value; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$length = $breakpoint; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
return rtrim(mb_substr($value, 0, $length, $env->getCharset())).$separator; |
111
|
|
|
} |
112
|
|
|
} else { |
113
|
|
|
if (\strlen($value) > $length) { |
114
|
|
|
if ($preserve) { |
115
|
|
|
if (false !== ($breakpoint = strpos($value, ' ', $length))) { |
116
|
|
|
$length = $breakpoint; |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
return rtrim(substr($value, 0, $length)).$separator; |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
return $value; |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.