Completed
Pull Request — master (#3)
by Saulius
04:38 queued 02:08
created

TruncateHtml::setTruncateOperationMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
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, self::TRUNCATE_HTML_WORD, self::TRUNCATE_HTML_SENTENCE
24
    ];
25
26
    private $encoding = 'utf-8';
27
28
    private $truncateWordsOperation;
29
30
    private $truncateSentencesOperation;
31
    /**
32
     * @var CountWordsInterface
33
     */
34
    private $countWordsOperation;
35
    /**
36
     * @var CountSentencesInterface
37
     */
38
    private $countSentencesOperation;
39
40 1
    public function __construct(
41
        TruncateInterface $truncateOperation,
42
        TruncateWordsInterface $truncateWordsOperation,
43
        TruncateSentencesInterface $truncateSentencesOperation,
44
        CountWordsInterface $countWordsOperation,
45
        CountSentencesInterface $countSentencesOperation
46
    ) {
47 1
        $this->truncateOperation = $truncateOperation;
48 1
        $this->truncateWordsOperation = $truncateWordsOperation;
49 1
        $this->truncateSentencesOperation = $truncateSentencesOperation;
50 1
        $this->countWordsOperation = $countWordsOperation;
51 1
        $this->countSentencesOperation = $countSentencesOperation;
52 1
    }
53
54 5
    public function execute(string $value, int $length, string $suffix = '...'): string
55
    {
56 5
        $config = \HTMLPurifier_Config::create(null);
57
58 5
        $lexer = \HTMLPurifier_Lexer::create($config);
59 5
        $tokens = $lexer->tokenizeHTML($value, $config, new \HTMLPurifier_Context());
60 5
        $openTokens = [];
61 5
        $totalCount = 0;
62 5
        $depth = 0;
63 5
        $truncated = [];
64 5
        foreach ($tokens as $token) {
65 5
            if ($token instanceof \HTMLPurifier_Token_Start) {
66 5
                $openTokens[$depth] = $token->name;
67 5
                $truncated[] = $token;
68 5
                ++$depth;
69 5
            } elseif ($token instanceof \HTMLPurifier_Token_Text && $totalCount <= $length) {
70
71 5
                $currentLength = $this->truncateByMethod($token->data, $length - $totalCount, $suffix);
72
73 5
                $totalCount += $currentLength;
74 5
                $truncated[] = $token;
75 3
            } elseif ($token instanceof \HTMLPurifier_Token_End) {
76 3
                if ($token->name === $openTokens[$depth - 1]) {
77 3
                    --$depth;
78 3
                    unset($openTokens[$depth]);
79 3
                    $truncated[] = $token;
80
                }
81 1
            } elseif ($token instanceof \HTMLPurifier_Token_Empty) {
82 1
                $truncated[] = $token;
83
            }
84 5
            if ($totalCount >= $length) {
85 5
                if (0 < \count($openTokens)) {
86 5
                    \krsort($openTokens);
87 5
                    foreach ($openTokens as $name) {
88 5
                        $truncated[] = new \HTMLPurifier_Token_End($name);
89
                    }
90
                }
91 5
                break;
92
            }
93
        }
94 5
        $context = new \HTMLPurifier_Context();
95 5
        $generator = new \HTMLPurifier_Generator($config, $context);
96
97 5
        return $generator->generateFromTokens($truncated).($totalCount >= $length ? $suffix : '');
98
    }
99
100 5
    private function truncateByMethod(string &$value, int $length, string $suffix): int
101
    {
102 5
        return $this->{$this->truncateOperationMethod}($value, $length, $suffix);
103
    }
104
105 1
    private function truncate(string &$value, int $length, string $suffix): int
106
    {
107 1
        $value = $this->truncateOperation->execute($value, $length, $suffix);
108
109 1
        return \mb_strlen($value, $this->encoding);
110
    }
111
112 1
    private function truncateWords(string &$value, int $count, string $suffix): int
113
    {
114 1
        $value = $this->truncateWordsOperation->execute($value, $count, $suffix);
115
116 1
        return $this->countWordsOperation->execute($value);
117
    }
118
119 3
    private function truncateSentences(string &$value, int $count, string $suffix): int
120
    {
121 3
        $value = $this->truncateSentencesOperation->execute($value, $count, $suffix);
122 3
        return $this->countSentencesOperation->execute($value);
123
    }
124
125
    /**
126
     * @param string $truncateOperationMethod
127
     *
128
     * @return TruncateHtml
129
     */
130 5
    public function setTruncateOperationMethod(string $truncateOperationMethod): void
131
    {
132 5
        if (!in_array($truncateOperationMethod, $this->truncateOperationMethods)) {
133 1
            throw new \InvalidArgumentException(\sprintf('`%s` truncate operation method is not supported.', $truncateOperationMethod));
134
        }
135
136 4
        $this->truncateOperationMethod = $truncateOperationMethod;
137 4
    }
138
139
140
}
141