Skip to content

md-php/bridge-twig-html-truncation

md-php/bridge-twig-html-truncation is a PHP component that brings md-php/html-truncation functionality into Twig component and provides additional Twig filter and function to truncate HTML code.

Architecture overview

Architecture overview class diagram

Install

composer require md-php/bridge-twig-html-truncation

Usage

# Initialize extension
$truncate  = new \MD\HTML\Action\Truncate();
$extension = new \MD\Bridge\Twig\HTML\Extension\TruncateExtension(truncate: $truncate);

# Initialize component
$loader = new \Twig\Loader\ArrayLoader(templates: []);  // ... just example loader
$twig   = new \Twig\Environment(loader: $loader);

# Usage
$twig->addExtension(extension: $extension);

Extension brings filter and function with the truncate_html_with_text_length name and next signature:

/**
 * Truncates HTML code to concrete length of text, taking care about correct removal of rest of elements and
 * element tags close.
 *
 * The content of element where given max length is reached truncated with adding `$ending` parameter content.
 * All next siblings elements and child are removed from the result.
 * Space characters in the begging or the in end of element text is not counted.
 *
 * @param  string $html      Source HTML code to truncate
 * @param  int    $maxLength Max length of text characters in HTML code to keep until truncation. Unsigned int.
 * @param  string $ending    Content to append to the truncated text, by default is ellipsis `...`
 * @return string            Truncated HTML code.
 *
 * @throws TruncateException
 */
function withTextLength(string $html, int $maxLength, string $ending = '...'): string;

Basic filter usage example:

{{ "<p>some long html code</p>"|truncate_html_with_text_length(4) }}

Filter usage with custom ending example:

{{ "<p>some long html code</p>"|truncate_html_with_text_length(4, '$') }}

Errors handle

Extension is a very tiny wrapper around TruncateInterface class functions. It does not handle thrown exception, in most cases they should never happen. But if explicit error handling is required, decorator around base class may be used, for example:

<?php

declare(strict_types=1);

namespace App;

use MD\HTML\Action\TruncateInterface;
use MD\HTML\Exception\TruncateException;

final class TruncateWithFallbackOnError implements TruncateInterface
{
    /**
     * @var MD\HTML\Action\TruncateInterface
     */
    private $truncate;

    public function __construct(MD\HTML\Action\TruncateInterface $truncate)
    {
        $this->truncate = $truncate;
    }

    #[\Override]
    public function withTextLength(string $html, int $maxLength, string $ending = '...'): string
    {
        try {
            return $this->truncate->withTextLength($html, $maxLength, $ending);
        } catch (TruncateException $exception) {
            // ... handle exception somehow according to your needs: log error or fallback to other implementation ... 
            return '';
        }
    } 
}

Then use next setup:

new \MD\Bridge\Twig\HTML\Extension\TruncateExtension(
    new \App\TruncateWithFallbackOnError(
        new \MD\HTML\Action\Truncate()
    )
);

Markdown and raw content

The truncate filter, which retains HTML markup, can handle both rendered Markdown content and "raw" content that is processed by the raw filter. For example, if application enables a Markdown filter to parse Markdown input, the following use cases are fully supported:

{{ "some very long markdown text"|markdown|raw|truncate_html_with_text_length(8) }}

Integration with Symfony

Define services:

services:
    MD\HTML\Action\TruncateInterface:
        alias: MD\HTML\Action\Truncate
    MD\HTML\Action\Truncate: ~

    MD\Bridge\Twig\HTML\Extension\TruncateExtension:
        arguments:  # ... may be omitted, if autowiring is in use
            $truncate: '@MD\HTML\Action\TruncateInterface'  
        tags:
            - name: twig.extension

and it's ready to use.