Trim lines in template files

prokki
Member | 3
+
0
-

Hi

Is there a possibility to trim lines in templates? I am currently working with text mails and indentations are really important. Especially in (nested) loops lines has to be adjusted. The following is a simple example, I need much more loops and conditions inside loops:

--------------------------------------------------------------------------------
{foreach $stations as $station}
    {$station->getSomething()} - {$station->getSomethingElse()}
    {foreach $station->getWindow() as $window}
        {$window->getTotalPrice()}
        {if $window->isFrench()}
            [....]
        {/if}
    {/foreach}
    --------------------------------------------------------------------------------
{/foreach}

The result should look like

--------------------------------------------------------------------------------
Something - Something else
Price: 123.00
--------------------------------------------------------------------------------
Something - Something else
Price: 123.00
--------------------------------------------------------------------------------

but actually it looks like

--------------------------------------------------------------------------------
    Something - Something else
    Price: 123.00
    --------------------------------------------------------------------------------
    Something - Something else
    Price: 123.00
    --------------------------------------------------------------------------------

I have tried to work with spaceless or strip but either

  • the output looks weird, i.e. no line breaks at all or
  • the template looks weird afterwards, so it is even better to skip these filters – and then the template still looks unreadable.
--------------------------------------------------------------------------------
{foreach $stations as $station}
{$station->getSomething()} - {$station->getSomethingElse()}
{foreach $station->getWindow() as $window}
{$window->getTotalPrice()} {if $window->isFrench()}[....]{/if}{/foreach}
--------------------------------------------------------------------------------
{/foreach}

I am looking for something like {<< to trim all leading whitespaces until the last line break or {spaceless-leading} or whatever. Example:

--------------------------------------------------------------------------------
{<< foreach $stations as $station}
    {<< $station->getSomething()} - {$station->getSomethingElse()}
    {<< foreach $station->getWindow() as $window}
        {<< $window->getTotalPrice()}
        {<< if $window->isFrench()}
            [....]
        {<< /if}
    {<< /foreach}
    --------------------------------------------------------------------------------
{<< /foreach}

Has anyone an idea?

Best,

Falko

prokki
Member | 3
+
0
-

CZechBoY wrote:

try |strip

https://latte.nette.org/en/filters#…

Like I mentioned above, i tried to use the strip filter but to be honest, I haven't found a way to use strip without destroying the template layout. strip removes also newlines, so either

  1. I have to change every line and add add several additional blocks that it works (which again destroys the readable template) or
  2. the complete text is in one line.

Just to remind you: It is not a html template, it is a text template file which is used for text mails, so I need to keep the newlines.

Last edited by prokki (2019-10-30 09:26)

nightfish
Member | 518
+
0
-

@prokki Do you ever need to keep leading spaces? If not, you could use regexp to strip all leading spaces from the template output. Something along the lines of:

<?php

$data = '
  some spaces
    even more spaces
no spaces

empty line above
';

var_dump(preg_replace('~^ +~m', '', $data));

If you need to preserve some of the spaces, then you'll need to mark the lines (e.g. with <<).

<?php

$data = '
  some spaces
    <<even more spaces # this space is trimmed, the rest is kept as-is
no spaces

empty line above
';

var_dump(preg_replace('~^ +<<~m', '', $data));
CZechBoY
Member | 3608
+
0
-

OK, just make you own stripWithoutNewLines filter, and use it. Or without own filter, you can do |replaceRE:'~^ +~m','' as previous post mentioned.

Last edited by CZechBoY (2019-10-30 22:57)

prokki
Member | 3
+
0
-

Hi @CZechBoY and @nightfish

I tried to implement your suggested solutions and followed now the stripWithoutNewLines advise.

<?php

class Strings
{
    public static function ltrimStreamWS(string $buffer, $replaceBy = ''): string
    {
        $replacedFirst = preg_replace("/^(?:\\h+)/", sprintf("%s", (string)$replaceBy), $buffer);
        $replaced = preg_replace("/\n(?:\\h+)/", sprintf("\n%s", (string)$replaceBy), $replacedFirst);
        return $replaced;
    }
}

class Macros extends Latte\Macros\MacroSet
{

    [...]
    $me->addMacro('trimLeadingWhitespaces', [$me, 'macroTrimLeadingWhitespaces'], [$me,

    public function macroTrimLeadingWhitespaces(MacroNode $node, PhpWriter $writer): void
    {
        if ($node->modifiers) {
            throw new CompileException('Modifiers are not allowed in ' . $node->getNotation());
        }

        $node->data->capture = true;
        $node->data->replaceBy = empty($node->args) ? null : $writer->write('%node.word');
    }

    public function macroEndTrimLeadingWhitespaces(MacroNode $node, PhpWriter $writer): void
    {
        if (!$node->data->capture) {
            throw new CompileException('Missing start block {trimLeadingWhitespaces}.');
        }
        $node->data->capture = false;

        $node->openingCode = \sprintf('<?php ob_start(function ($s) { return Strings::ltrimStreamWS($s, %s); }, 4096); ?>', empty($node->data->replaceBy) ? '""' : $node->data->replaceBy);

        $node->closingCode = '<?php ob_end_flush(); ?>';
    }
}
?>

--------------------------------------------------------------------------------
{trimLeadingWhitespaces}
     {foreach $stations as $station}
         {$station->getSomething()} - {$station->getSomethingElse()}
         {foreach $station->getWindow() as $window}
             {$window->getTotalPrice()}
             {if $window->isFrench()}
                 [....]
             {/if}
         {/foreach}
         --------------------------------------------------------------------------------
    {/foreach}
{/trimLeadingWhitespaces}

I think it is not the best solution but so far it works. Thanks for your help!

Best,

Falko