Vytvorenie vlastnej funkcie pre latte

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

Ahojte.

Prosim vas, je mozne spravit nieco take, ze do <div> <a> .. cohokolvek pridam napriklad n:hidden a tento prvok sa mi potom nebude generovat a teda zobrazovat na vystupe?

Ide mi o to, ze mam v systeme nieco ako moduly (pozor, nemyslit si s Nette modulmi) a na zaklade prihlasenia uzivatela model vyhodnoti ktore moduly ma mat uzivatel pristupne.

Moduly, ktore su pre uzivatela pristupne za zapisu do pola.

Pr:

$bundles = [1,2,5,78,99];

V kode mam napriklad button, ktory patri modulu č.4 a teda by bolo riesenie spravit:

<div n:if="inArray(4, $bundles)">  ...  </div>

No chcel by som si to nejako zjednodusit a to tym, ze by som si vytvoril filter a zapisoval:

<div {4:bundle}>  ...  </div>

tento filter by mal na vystupe bud nic, vtedy by sa <div> normalne zobrazil, alebo n:hidden

Potialto by som to zvladol, no potreboval by som v tomto pripade dany div nezobrazovat a to ani v kode, cize ziadne schovavanie stylom a ani javascriptom.

Snad som to vysvetlil dostatocne.

Dakujem za pripadne rady a info :)

ali
Člen | 342
+
0
-

Ja bych rek, ze n:if je ta spravna cesta.

vladimir.biro
Člen | 163
+
0
-

ali napsal(a):

Ja bych rek, ze n:if je ta spravna cesta.

A sla by aspon spravit vlastna funkcia?

Napriklad:

<a href="#" n:if="b(4)"></a>

S tym, ze by som si niekde vytvoril:

<?php

b($i) {
	return (in_array($i, $this->bundleManager->getBundles())) ? true : false;
}

...

// -- toto by samozrejme bralo data z DB a po roznych kontrolach
getBundles()
{
	return [1,2,3,4];
}

?>

Ide mi o to, co najviac to zjednodusit, pretoze to budem pouzivat kade tade a zaroven aby som do tej funkcie vede zasahovat aj neskor a zaroven nemusel vsetko prepisovat na x miestach.

Editoval vladimir.biro (23. 11. 2017 19:59)

ali
Člen | 342
+
0
-

Jdes na to blbe, snazis se vracet z sablony do presenteru, coz je spatne.

Udelej to tak, ze $this->bundleManager->getBundles() ti bude vracet pole/object, ktery predas do sablony, neco jako:

$this->template->bundles = [
	1 => ['bundleId' => 1, 'name' => 'foo1', 'havePermission' => true],
	2 => ['bundleId' => 2, 'name' => 'foo2', 'havePermission' => false],
	...
];

A v sablone to pak budes vykreslovat nejakym takovymhle stylem:

{foreach $bundles as $bundle}
	{if $bundle[havePermission]}
		<a>{$bundle[name]}</a>
	{else}
		<i>{$bundle[name]}</i>
	{/if}
{/foreach}

Editoval ali (24. 11. 2017 5:46)

vladimir.biro
Člen | 163
+
0
-

ali napsal(a):

Jdes na to blbe, snazis se vracet z sablony do presenteru, coz je spatne.

Udelej to tak, ze $this->bundleManager->getBundles() ti bude vracet pole/object, ktery predas do sablony, neco jako:

$this->template->bundles = [
	1 => ['bundleId' => 1, 'name' => 'foo1', 'havePermission' => true],
	2 => ['bundleId' => 2, 'name' => 'foo2', 'havePermission' => false],
	...
];

A v sablone to pak budes vykreslovat nejakym takovymhle stylem:

{foreach $bundles as $bundle}
	{if $bundle[havePermission]}
		<a>{$bundle[name]}</a>
	{else}
		<i>{$bundle[name]}</i>
	{/if}
{/foreach}

fuu .. to som prave nechcel.

Chcel som, aby som to mal v sablone co najjednoduchsie. Tvoje riesenie je este komplikovanejsie (pre oko), ako to, co som popisal vyssie.

Samozrejme ked sa jedna o automaticky vypis menu (napriklad) tak to je samozrejem OK. Menu dokonca velmi podobne generujem, no potrebujem kontrolovat aj rozne casti kodu vsade na stranke a taketo podminekovanie by mi z toho spravilo bodrel.

V kazdom priprade ale dakujem za snahu :)

vladimir.biro
Člen | 163
+
0
-

Tak som to nakoniec vyriesil cekom elegantne cez makra … akurat som sa ich musel naucit vytvarat :D

Riesenie:

1. V modeli si spravim funkciu na vygenerovanie zoznamu ID-ciek povolenych balikov na zaklade urcitych podmienok.

Pre ukazku bude stacit jednoduche pole.

$bundles = [1, 2, 3, 4];

2. V BasePressenter-i vlozim tento zoznam do vsetkych sablon

abstract class BasePresenter extends UI\Presenter
{

    /** @var App\Model\BundlesManager @inject */
    public $bundles;



	public function beforeRender()
    {
        parent::beforeRender();

        $this->template->bundles = $this->bundles; // <-- Zoznam povolenych balikov vlozime do sablony
    }

}

3. Vytvorim si metodu MyMacros …

namespace App\Macros;

use	Latte\MacroNode;
use	Latte\PhpWriter;


class MyMacros extends \Latte\Macros\MacroSet
{

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

		$me->addMacro('bundle',
			array($me, 'bundleStart'),
			array($me, 'bundleEnd')
		);

		return $me;
	}



	/**
	 * {if in_array($param, $bundles) ...}
	 */
	public function bundleStart(MacroNode $node, PhpWriter $writer)
	{
		return $writer->write('if (in_array(%node.args, $bundles)) {');

		/**
		 * Toto mam este rozsirene o to, aby user s rolou 'superadmin' mal pristup aj k modulom,
		 * ktore su zakazane. Mozno by to ale bolo lepsie riesit uz v medeli BundlesManager.
		 *
		 * Takze ja tam mam:
		 * return $writer->write('if (in_array(%node.args, $bundles) || $user->isInRole(\'superadmin\')) {');
		 */
	}



	/**
	 * {/if}
	 */
	public function bundleEnd(MacroNode $node, PhpWriter $writer)
	{
		return $writer->write('}');
	}

}

… a zaregistrujem ju v config.neon

latte:
    macros:
        - App\Macros\MyMacros

4. Nasledne mozem pouzit kdekolvek v sablone

	<a href="#" n:bundle="8">Button pre bundle číslo 8</a>

	{bundle 3}
		<div class="bundle-wrapper">
			Dostupné len ak je povolený bundle číslo 3!
		</div>
	{/bundle}

Prosim Vas, ak mam nieco zle, alebo by sa nieco dalo pouzivat elegantnejsie, alebo mate niekto iny napada, sem s nim :) … rad sa priucim. Dakujem.

Editoval vladimir.biro (24. 11. 2017 11:28)

blaztar
Člen | 93
+
0
-

V Nette 2.4 je ještě nový operátor „in“ v Latte. Ale nevím jak moc je to použitelné, mě to moc nefungovalo co jsem zkoušel, takže to v reálu snad nikde nepoužívám.

// nefunguje
<div n:if="4 in [1,2,4]"></div>

// funguje
{var $four = 4}
<div n:if="$four in [1,2,4]"></div>

// nefunguje
{var $four = 4}
{var $array = [1,2,4]}
<div n:if="$four in $array"></div>

I když místo rady pro tebe bych spíš já potřeboval osvětlit jak se to používá. :)

vladimir.biro
Člen | 163
+
0
-

blaztar napsal(a):

V Nette 2.4 je ještě nový operátor „in“ v Latte. Ale nevím jak moc je to použitelné, mě to moc nefungovalo co jsem zkoušel, takže to v reálu snad nikde nepoužívám.

// nefunguje
<div n:if="4 in [1,2,4]"></div>

// funguje
{var $four = 4}
<div n:if="$four in [1,2,4]"></div>

// nefunguje
{var $four = 4}
{var $array = [1,2,4]}
<div n:if="$four in $array"></div>

I když místo rady pro tebe bych spíš já potřeboval osvětlit jak se to používá. :)

To uz je podla toho, ako to spracovava macro if
Ked do parametra zadas $four in [1,2,3,4] tak do sablony sa vyrenderuje PHP kod if (in_array($four, [1,2,3,4], TRUE)) { … } co PHP v pohode spracuje.

No ked zadas 4 in [1,2,3,4] parameter vobec nezmeni a do sablony vygeneruje if (4 in [1,2,3,4]) { … } co PHP nepzna a vyhodi to chybu.

Preco je tomu tak sa asi netreba zamyslat a pozuvat namiesto toho n:if=„in_array(4, [1,2,3,4])“

:)

Editoval vladimir.biro (24. 11. 2017 22:15)

CZechBoY
Člen | 3608
+
0
-
  1. příklad nedává smysl
  2. ok
  3. nejspíš to jen nefunguje na dynamické/proměnné, mělo by jít dodělat přes pull request :-)