TruncateStringFilter::filter()   B
last analyzed

Complexity

Conditions 9
Paths 40

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 7.5353
c 0
b 0
f 0
cc 9
nc 40
nop 1
1
<?php
2
/**
3
 * @file
4
 */
5
6
namespace CultuurNet\UDB3\StringFilter;
7
8
use Stringy\Stringy as Stringy;
9
10
class TruncateStringFilter implements StringFilterInterface
11
{
12
    /**
13
     * @var bool
14
     */
15
    protected $wordSafe = false;
16
17
    /**
18
     * @var int
19
     */
20
    protected $minWordSafeLength;
21
22
    /**
23
     * @var bool
24
     */
25
    protected $addEllipsis = false;
26
27
    /**
28
     * @var bool
29
     */
30
    protected $spaceBeforeEllipsis = false;
31
32
    /**
33
     * @var bool
34
     */
35
    protected $sentenceFriendly = false;
36
37
    /**
38
     * @var int
39
     */
40
    protected $maxLength;
41
42
    /**
43
     * @param int $maxLength
44
     */
45
    public function __construct($maxLength)
46
    {
47
        $this->setMaxLength($maxLength);
48
    }
49
50
    /**
51
     * @param int $maxLength
52
     */
53
    public function setMaxLength($maxLength)
54
    {
55
        $this->maxLength = $maxLength;
56
    }
57
58
    /**
59
     * @param bool $toggle
60
     */
61
    public function addEllipsis($toggle = true)
62
    {
63
        $this->addEllipsis = $toggle;
64
    }
65
66
    /**
67
     * @param bool $toggle
68
     */
69
    public function spaceBeforeEllipsis($toggle = true)
70
    {
71
        $this->spaceBeforeEllipsis = $toggle;
72
    }
73
74
    /**
75
     * @param int $minWordSafeLength
76
     */
77
    public function turnOnWordSafe($minWordSafeLength = 1)
78
    {
79
        $this->wordSafe = true;
80
        $this->minWordSafeLength = $minWordSafeLength;
81
    }
82
83
    /**
84
     * When turned on, the filter will try not to truncate in the middle of a sentence.
85
     */
86
    public function beSentenceFriendly()
87
    {
88
        $this->sentenceFriendly = true;
89
    }
90
91
    /**
92
     * @inheritdoc
93
     */
94
    public function filter($string)
95
    {
96
        // Maximum length and minimum length to enable word-safe truncating should always be greater than zero.
97
        $maxLength = max($this->maxLength, 0);
98
        $minWordSafeLength = max($this->minWordSafeLength, 0);
99
100
        // Do not attempt word-safe truncating if the maximum length is smaller than the minimum length to do
101
        // word-safe truncating.
102
        $wordSafe = $this->wordSafe && $maxLength >= $minWordSafeLength;
103
104
        // Define the suffix of the truncated string.
105
        $suffix = '';
106
        if ($this->addEllipsis) {
107
            $ellipsis = '...';
108
            if ($this->spaceBeforeEllipsis) {
109
                $ellipsis = ' ...';
110
            }
111
            $suffix = Stringy::create($ellipsis, 'UTF-8');
112
113
            // If the ellipsis is longer or equal to the maximum length, simply truncate the ellipsis so it fits in
114
            // the maximum length and return it.
115
            if ($suffix->length() >= $maxLength) {
116
                return (string) $suffix->truncate($maxLength);
117
            }
118
        }
119
120
        $stringy = Stringy::create($string, 'UTF-8');
121
122
        $sentencePattern = '/(.*[.!?])(?:\\s|\\h|$|\\\u00a0).*/su';
123
        $trunc = (string) $stringy->first($maxLength);
124
        $hasEndingSymbolInRange = preg_match($sentencePattern, $trunc);
125
126
        if ($this->sentenceFriendly && $hasEndingSymbolInRange === 1) {
127
            $sentenceTruncated = preg_replace($sentencePattern, "$1".$suffix, $trunc);
128
            $truncated = Stringy::create($sentenceTruncated, 'UTF-8');
129
        } elseif ($wordSafe) {
130
            $truncated = $stringy->safeTruncate($maxLength, $suffix);
0 ignored issues
show
Bug introduced by
It seems like $suffix defined by \Stringy\Stringy::create($ellipsis, 'UTF-8') on line 111 can also be of type object<Stringy\Stringy>; however, Stringy\Stringy::safeTruncate() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
131
        } else {
132
            $truncated = $stringy->truncate($maxLength, $suffix);
0 ignored issues
show
Bug introduced by
It seems like $suffix defined by \Stringy\Stringy::create($ellipsis, 'UTF-8') on line 111 can also be of type object<Stringy\Stringy>; however, Stringy\Stringy::truncate() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
133
        }
134
135
        if ($this->addEllipsis) {
136
            // Make sure the string does not end in more than 3 dots. The pattern looks for a sequence of
137
            // 4 or more ("{4,}") dots ("(\\.)") at the end of the string ("$").
138
            $pattern = '(\\.){4,}$';
139
            $truncated = $truncated->regexReplace($pattern, $suffix);
140
        }
141
142
        return (string) $truncated;
143
    }
144
}
145