Completed
Pull Request — master (#4)
by Saulius
02:36
created

TruncateHtml::setTruncateOperationMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the sauls/helpers package.
4
 *
5
 * @author    Saulius Vaičeliūnas <[email protected]>
6
 * @link      http://saulius.vaiceliunas.lt
7
 * @copyright 2018
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Sauls\Component\Helper\Operation\StringOperation;
14
15
16
class TruncateHtml implements TruncateHtmlInterface
17
{
18
    private $truncateOperation;
19
20
    private $truncateOperationMethod = 'truncate';
21
22
    private $truncateOperationMethods = [
23
        self::TRUNCATE_HTML_LETTER,
24
        self::TRUNCATE_HTML_WORD,
25
        self::TRUNCATE_HTML_SENTENCE,
26
    ];
27
28
    private $encoding = 'utf-8';
29
30
    private $truncateWordsOperation;
31
32
    private $truncateSentencesOperation;
33
    /**
34
     * @var CountWordsInterface
35
     */
36
    private $countWordsOperation;
37
    /**
38
     * @var CountSentencesInterface
39
     */
40
    private $countSentencesOperation;
41
42
    private $openTokens = [];
43
44
    private $totalCount = 0;
45
46
    private $depth = 0;
47
48
    private $truncated = [];
49
50 1
    public function __construct(
51
        TruncateInterface $truncateOperation,
52
        TruncateWordsInterface $truncateWordsOperation,
53
        TruncateSentencesInterface $truncateSentencesOperation,
54
        CountWordsInterface $countWordsOperation,
55
        CountSentencesInterface $countSentencesOperation
56
    ) {
57 1
        $this->truncateOperation = $truncateOperation;
58 1
        $this->truncateWordsOperation = $truncateWordsOperation;
59 1
        $this->truncateSentencesOperation = $truncateSentencesOperation;
60 1
        $this->countWordsOperation = $countWordsOperation;
61 1
        $this->countSentencesOperation = $countSentencesOperation;
62 1
    }
63
64 5
    public function execute(string $value, int $length, string $suffix = '...'): string
65
    {
66 5
        $this->resetVariables();
67
68 5
        $config = \HTMLPurifier_Config::create(null);
69
70 5
        $lexer = \HTMLPurifier_Lexer::create($config);
71 5
        $tokens = $lexer->tokenizeHTML($value, $config, new \HTMLPurifier_Context());
72
73 5
        $this->processTokens($tokens, $length, $suffix);
74
75 5
        $context = new \HTMLPurifier_Context();
76 5
        $generator = new \HTMLPurifier_Generator($config, $context);
77
78 5
        return $generator->generateFromTokens($this->truncated).($this->totalCount >= $length ? $suffix : '');
79
    }
80
81 5
    private function truncateByMethod(string &$value, int $length, string $suffix): int
82
    {
83 5
        return $this->{$this->truncateOperationMethod}($value, $length, $suffix);
84
    }
85
86
    /**
87
     * @param string $truncateOperationMethod
88
     *
89
     * @return TruncateHtml
90
     */
91 5
    public function setTruncateOperationMethod(string $truncateOperationMethod): void
92
    {
93 5
        if (!in_array($truncateOperationMethod, $this->truncateOperationMethods)) {
94 1
            throw new \InvalidArgumentException(\sprintf('`%s` truncate operation method is not supported.',
95 1
                $truncateOperationMethod));
96
        }
97
98 4
        $this->truncateOperationMethod = $truncateOperationMethod;
99 4
    }
100
101 1
    private function truncate(string &$value, int $length, string $suffix): int
102
    {
103 1
        $value = $this->truncateOperation->execute($value, $length, $suffix);
104
105 1
        return \mb_strlen($value, $this->encoding);
106
    }
107
108 1
    private function truncateWords(string &$value, int $count, string $suffix): int
109
    {
110 1
        $value = $this->truncateWordsOperation->execute($value, $count, $suffix);
111
112 1
        return $this->countWordsOperation->execute($value);
113
    }
114
115 3
    private function truncateSentences(string &$value, int $count, string $suffix): int
116
    {
117 3
        $value = $this->truncateSentencesOperation->execute($value, $count, $suffix);
118
119 3
        return $this->countSentencesOperation->execute($value);
120
    }
121
122 5
    private function resetVariables(): void
123
    {
124 5
        $this->openTokens = [];
125 5
        $this->depth = 0;
126 5
        $this->totalCount = 0;
127 5
        $this->truncated = [];
128 5
    }
129
130 5
    private function processTokens(array $tokens, int $length, string $suffix): void
131
    {
132 5
        foreach ($tokens as $token) {
133
134 5
            $this->processTokenStart($token);
135 5
            $this->processTokenText($token, $length, $suffix);
136 5
            $this->processTokenEnd($token);
137 5
            $this->processTokenEmpty($token);
138
139 5
            if ($this->totalCount >= $length) {
140 5
                $this->processOpenTokens();
141 5
                break;
142
            }
143
        }
144 5
    }
145
146 5
    private function processTokenStart($token): void
147
    {
148 5
        if ($token instanceof \HTMLPurifier_Token_Start) {
149 5
            $this->openTokens[$this->depth] = $token->name;
150 5
            $this->truncated[] = $token;
151 5
            ++$this->depth;
152
        }
153 5
    }
154
155 5
    private function processTokenText($token, int $length, string $suffix): void
156
    {
157 5
        if ($token instanceof \HTMLPurifier_Token_Text && $this->totalCount <= $length) {
158 5
            $currentLength = $this->truncateByMethod($token->data, $length - $this->totalCount, $suffix);
159 5
            $this->totalCount += $currentLength;
160 5
            $this->truncated[] = $token;
161
        }
162 5
    }
163
164 5
    private function processTokenEnd($token): void
165
    {
166 5
        if ($token instanceof \HTMLPurifier_Token_End) {
167 3
            if ($token->name === $this->openTokens[$this->depth - 1]) {
168 3
                --$this->depth;
169 3
                unset($this->openTokens[$this->depth]);
170 3
                $this->truncated[] = $token;
171
            }
172
        }
173 5
    }
174
175 5
    private function processTokenEmpty($token)
176
    {
177 5
        if ($token instanceof \HTMLPurifier_Token_Empty) {
178 1
            $this->truncated[] = $token;
179
        }
180 5
    }
181
182 5
    private function processOpenTokens(): void
183
    {
184 5
        if (0 < \count($this->openTokens)) {
185 5
            \krsort($this->openTokens);
186 5
            foreach ($this->openTokens as $name) {
187 5
                $this->truncated[] = new \HTMLPurifier_Token_End($name);
188
            }
189
        }
190 5
    }
191
192
193
}
194