Skip to content

Commit

Permalink
Merge pull request #4 from sauls/v1.x
Browse files Browse the repository at this point in the history
Improved TruncateHtml operation
  • Loading branch information
sauls authored Mar 5, 2018
2 parents b84e4c6 + 831936a commit 38b7377
Showing 1 changed file with 99 additions and 46 deletions.
145 changes: 99 additions & 46 deletions src/Operation/StringOperation/TruncateHtml.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class TruncateHtml implements TruncateHtmlInterface
private $truncateOperationMethod = 'truncate';

private $truncateOperationMethods = [
self::TRUNCATE_HTML_LETTER, self::TRUNCATE_HTML_WORD, self::TRUNCATE_HTML_SENTENCE
self::TRUNCATE_HTML_LETTER,
self::TRUNCATE_HTML_WORD,
self::TRUNCATE_HTML_SENTENCE,
];

private $encoding = 'utf-8';
Expand All @@ -37,6 +39,14 @@ class TruncateHtml implements TruncateHtmlInterface
*/
private $countSentencesOperation;

private $openTokens = [];

private $totalCount = 0;

private $depth = 0;

private $truncated = [];

public function __construct(
TruncateInterface $truncateOperation,
TruncateWordsInterface $truncateWordsOperation,
Expand All @@ -53,73 +63,94 @@ public function __construct(

public function execute(string $value, int $length, string $suffix = '...'): string
{
$this->resetVariables();

$config = \HTMLPurifier_Config::create(null);

$lexer = \HTMLPurifier_Lexer::create($config);
$tokens = $lexer->tokenizeHTML($value, $config, new \HTMLPurifier_Context());
$openTokens = [];
$totalCount = 0;
$depth = 0;
$truncated = [];

$this->processTokens($tokens, $length, $suffix);

$context = new \HTMLPurifier_Context();
$generator = new \HTMLPurifier_Generator($config, $context);

return $generator->generateFromTokens($this->truncated).($this->totalCount >= $length ? $suffix : '');
}

private function resetVariables(): void
{
$this->openTokens = [];
$this->depth = 0;
$this->totalCount = 0;
$this->truncated = [];
}

private function processTokens(array $tokens, int $length, string $suffix): void
{
foreach ($tokens as $token) {
if ($token instanceof \HTMLPurifier_Token_Start) {
$openTokens[$depth] = $token->name;
$truncated[] = $token;
++$depth;
} elseif ($token instanceof \HTMLPurifier_Token_Text && $totalCount <= $length) {

$currentLength = $this->truncateByMethod($token->data, $length - $totalCount, $suffix);

$totalCount += $currentLength;
$truncated[] = $token;
} elseif ($token instanceof \HTMLPurifier_Token_End) {
if ($token->name === $openTokens[$depth - 1]) {
--$depth;
unset($openTokens[$depth]);
$truncated[] = $token;
}
} elseif ($token instanceof \HTMLPurifier_Token_Empty) {
$truncated[] = $token;
}
if ($totalCount >= $length) {
if (0 < \count($openTokens)) {
\krsort($openTokens);
foreach ($openTokens as $name) {
$truncated[] = new \HTMLPurifier_Token_End($name);
}
}

$this->processTokenStart($token);
$this->processTokenText($token, $length, $suffix);
$this->processTokenEnd($token);
$this->processTokenEmpty($token);

if ($this->totalCount >= $length) {
$this->processOpenTokens();
break;
}
}
$context = new \HTMLPurifier_Context();
$generator = new \HTMLPurifier_Generator($config, $context);
}

private function processTokenStart($token): void
{
if ($token instanceof \HTMLPurifier_Token_Start) {
$this->openTokens[$this->depth] = $token->name;
$this->truncated[] = $token;
++$this->depth;
}
}

return $generator->generateFromTokens($truncated).($totalCount >= $length ? $suffix : '');
private function processTokenText($token, int $length, string $suffix): void
{
if ($token instanceof \HTMLPurifier_Token_Text && $this->totalCount <= $length) {
$currentLength = $this->truncateByMethod($token->data, $length - $this->totalCount, $suffix);
$this->totalCount += $currentLength;
$this->truncated[] = $token;
}
}

private function truncateByMethod(string &$value, int $length, string $suffix): int
{
return $this->{$this->truncateOperationMethod}($value, $length, $suffix);
}

private function truncate(string &$value, int $length, string $suffix): int
private function processTokenEnd($token): void
{
$value = $this->truncateOperation->execute($value, $length, $suffix);

return \mb_strlen($value, $this->encoding);
if ($token instanceof \HTMLPurifier_Token_End) {
if ($token->name === $this->openTokens[$this->depth - 1]) {
--$this->depth;
unset($this->openTokens[$this->depth]);
$this->truncated[] = $token;
}
}
}

private function truncateWords(string &$value, int $count, string $suffix): int
private function processTokenEmpty($token)
{
$value = $this->truncateWordsOperation->execute($value, $count, $suffix);

return $this->countWordsOperation->execute($value);
if ($token instanceof \HTMLPurifier_Token_Empty) {
$this->truncated[] = $token;
}
}

private function truncateSentences(string &$value, int $count, string $suffix): int
private function processOpenTokens(): void
{
$value = $this->truncateSentencesOperation->execute($value, $count, $suffix);
return $this->countSentencesOperation->execute($value);
if (0 < \count($this->openTokens)) {
\krsort($this->openTokens);
foreach ($this->openTokens as $name) {
$this->truncated[] = new \HTMLPurifier_Token_End($name);
}
}
}

/**
Expand All @@ -130,11 +161,33 @@ private function truncateSentences(string &$value, int $count, string $suffix):
public function setTruncateOperationMethod(string $truncateOperationMethod): void
{
if (!in_array($truncateOperationMethod, $this->truncateOperationMethods)) {
throw new \InvalidArgumentException(\sprintf('`%s` truncate operation method is not supported.', $truncateOperationMethod));
throw new \InvalidArgumentException(\sprintf('`%s` truncate operation method is not supported.',
$truncateOperationMethod));
}

$this->truncateOperationMethod = $truncateOperationMethod;
}

private function truncate(string &$value, int $length, string $suffix): int
{
$value = $this->truncateOperation->execute($value, $length, $suffix);

return \mb_strlen($value, $this->encoding);
}

private function truncateWords(string &$value, int $count, string $suffix): int
{
$value = $this->truncateWordsOperation->execute($value, $count, $suffix);

return $this->countWordsOperation->execute($value);
}

private function truncateSentences(string &$value, int $count, string $suffix): int
{
$value = $this->truncateSentencesOperation->execute($value, $count, $suffix);

return $this->countSentencesOperation->execute($value);
}


}

0 comments on commit 38b7377

Please sign in to comment.