Latte filtr pro odstranění komentářů z vygenerováného HTML

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
hiny
Člen | 35
+
0
-

Zdravím, snažím se pomocí vlastního filtru odstranit komentáře z vygenerovaného HTML.

Napadlo mě, že to vyřeším tak, že celou šablonu @layout.latte zabalím do bloku navíc a použiji na něj filtr. Nicméně mi Laděnka vypisuje následující varování:

User Warning

Filter |stripcomments is called with incompatible content type HTML, try to prepend |stripHtml.

Což je pěkné, ale pokud bych to udělal, tak dostanu čistý text, což logicky nechci.

Nette verze 2.4.

BasePresenter

<?php

abstract class BasePresenter extends UI\Presenter
{
// ... "Nepodstatný" zbytek
protected function beforeRender()
	{
		parent::beforeRender();

		// Filtr pro odstranění komentářů
		$this->template->addFilter('stripcomments', function ($s) {

			// Odebrání html komentářů <!-- -->
			$result = preg_replace('/<!--(.|\n)*?-->/', '', $s);

			return $result;
		});
	}

}
?>

@layout.latte

{block #allhtml|stripcomments}
{*
...
obsah šablony
...
*}
{/block}

Sice to dělá co má, ale není to jaksi ono. Moje otázka zní, jak to udělat, abych mohl používat filtry na vygenerovaný HTML kód, bez tohoto varování? Případně nějaký lepší způsob.

GEpic
Člen | 562
+
0
-

A proč se o to snažíš a nepíšeš veškeré komentáře rovnou přes 'latte komentáře'? Nechápu, proč jsou v generovaném souboru / obsahu komentáře, víš.

Editoval GEpic (21. 7. 2016 22:39)

hiny
Člen | 35
+
0
-

GEpic napsal(a):

V případě že si těmito latte komentáři označím bloky/části kódu a následně stejně zakomentuji vetší část kódu, která tyto komentáře obsahuje, tak se celek mine účinkem a celé se to rozbije. Proto používám klasické HTML komentáře a pokud potřebuji zakomentovat větší část kódu použiji latte komentáře.

Viz:

<ul>
	{* prvek x1 *}
	<li>x1</li>
	{* tohle zatím není potřeba
	<li>x2</li>
	<li>x2</li>
	{* prvek x3 *}
	<li>x3</li>
	<li>x4</li>
	*}
	<li>x</li>
</ul>

Nicméně to jsme úplně mimo téma. Neřešíme otázku proč, ale jak ;-) Myslím, že otázka proč se tu řešila několikrát, ale zatím nikdo nenapsal, jak to udělat. Prosím tedy o zdržení se podobných komentářů.

GEpic
Člen | 562
+
0
-

hiny napsal(a):

GEpic napsal(a):

V případě že si těmito latte komentáři označím bloky/části kódu a následně stejně zakomentuji vetší část kódu, která tyto komentáře obsahuje, tak se celek mine účinkem a celé se to rozbije. Proto používám klasické HTML komentáře a pokud potřebuji zakomentovat větší část kódu použiji latte komentáře.

Viz:

<ul>
	{* prvek x1 *}
	<li>x1</li>
	{* tohle zatím není potřeba
	<li>x2</li>
	<li>x2</li>
	{* prvek x3 *}
	<li>x3</li>
	<li>x4</li>
	*}
	<li>x</li>
</ul>

Nicméně to jsme úplně mimo téma. Neřešíme otázku proč, ale jak ;-) Myslím, že otázka proč se tu řešila několikrát, ale zatím nikdo nenapsal, jak to udělat. Prosím tedy o zdržení se podobných komentářů.

Já se neptám ‚proč‘ abych se ti vysmíval nebo něco, ale když odpovíš na mé proč, budu vědět záměr a budu moci nad problémem přemýšlet. A myslím, že to tak má většina lidí zde na fóru. :)

Mě by třeba zajímalo, odkud bereš ten generovaný kód, zda-li je možnost ho v presenteru nějak vytáhnout? My totiž například parsujeme makra z generovaného obsahu, a stačí to v beforeRender prohnat metodou, kde už se o to preg_replace_all postará. Do šablony pak putuje už to, co se má skutečně vypsat a není potřeba to pak už nijak upravovat.

Editoval GEpic (22. 7. 2016 0:38)

hiny
Člen | 35
+
0
-

@GEpic Díky za nakopnutí směrem k makrům.

Nakonec jsem se inspiroval makrem spaceless a pro mou potřebu vytvořil následující třídu, kterou jsem zaregistroval v config.neon.

latte:
	macros:
		- App\Utils\CustomMacros
namespace App\Utils;

use Latte;
use Latte\CompileException;
use Latte\MacroNode;
use Latte\PhpWriter;

class CustomMacros extends Latte\Macros\MacroSet
{

	public static function install(Latte\Compiler $compiler)
	{
		$me = new static($compiler);

		$me->addMacro('stripcomments', [$me, 'macroStripComments'], [$me, 'macroStripComments']);
	}

	public function macroStripComments(MacroNode $node, PhpWriter $writer)
	{
		if ($node->modifiers || $node->args) {
			throw new CompileException('Modifiers and arguments are not allowed in ' . $node->getNotation());
		}
		if (!$node->closing) {
			return;
		} else {
			// Odebrání html komentářů <!-- -->
			$node->content = preg_replace('/<!--(.|\n)*?-->/', '', $node->content);
		}
	}

}

Makro volám v šabloně @layout.latte hned na začátku.

{stripcomments}
<!DOCTYPE html>
<!-- Zbytek šablony -->
{snippet content}
	{include #content}
{/snippet}
<!-- Bude odstaněno -->
</html>{/stripcomments}

Nicméně v tento moment budu muset použít toto makro v každé includované šabloně či načtené komponentě, stejně jako makro spaceless.

Je nějaké řešení jak toto obejít, abych ho nemusel všude vkládat a napsal ho jenom jednou do hlavní šablony?

hiny
Člen | 35
+
0
-

Zatím jediné funkční řešení, při kterém mi bude stačit upravit jednu šablonu a nemuset hlídat, zda jsem do nějaké šablony nezapomněl přidat makro, je vrátit se od makra zpět k filtru a původní myšlence.

Takže výsledek je stejný jako v 1. příspěvku s dodatečnou úpravou Latte\Runtime\FilterExecutor, čímž jsem obešel to varování.

	public function filterContent($name, FilterInfo $info, $arg)
	{
		/** ... */
			if ($info->contentType !== Engine::CONTENT_TEXT && $lname !== "stripcomments") {
				trigger_error("Filter |$name is called with incompatible content type " . strtoupper($info->contentType)
					. ($info->contentType === Engine::CONTENT_HTML ? ', try to prepend |stripHtml.' : '.'), E_USER_WARNING);
			}
		/** ... */
	}
Roman Ožana
Člen | 52
+
0
-

Vyřešil bych to takhle (Latte 2.4.2):

$this->template->addFilter('stripcomments', function (\Latte\Runtime\FilterInfo $fileInfo, $s) {
// Odebrání html komentářů <!-- -->
$result = preg_replace('/<!--(.|\n)*?-->/', '', $s);
return $result;
});

viz FilterExecutor.php podmínka zde https://github.com/…Executor.php#L152 a další zde https://github.com/…Executor.php#L185