Dostání proměnné do componenty header

unjustolaf
Člen | 29
+
0
-

Dobrý den,

Začel jsem v nette frameworku tvořit svůj první e-shop, s mnoha problémy jsem se už popral a dokázal je vyřešit ale tento ne.

Mám vytvořený header.latte ve složce templates/Components, který automaticky renderuji na začátek každé stránky v mém projektu pomocí {include „Components/header.latte“} v souboru layout.latte. Teď jsem se ale dostal do fáze kde bych potřeboval aby při každém načtení kterékoliv stránky v mém projektu se při zobrazovaní mého headeru (navbaru) v něm zobrazovala hodnota všeho zboží v košíku.

Vytvořil jsem si metodu která mi spočítá hodnotu všeho zboží v košíku daného uživatele a funguje bezchybně, můj opravdu jediný problém je, že nedokážu dostat výslednou hodnotu této metody do toho headeru (neboli templatu).

Takto vypadá moje metoda, která mi získá celkovou hodnotu zboží v košíku:

<?php
	public function getTotalPrice()
    {
        $total_price_sum = 0;
        $itemsInCart = $this->database->table("cart")->where("user_id", $this->user->getId())->fetchAll();

        foreach ($itemsInCart as $item) {
            $total_price_sum = $total_price_sum + ($item->item_price * $item->item_quantity);
        }

        return $total_price_sum;
    }
?>

Takto vypadá můj marný pokus vytvořit Presenter ze kterého by daný header dostal proměnnou s názvem „cartTotal“:

<?php
	class ComponentsPresenter extends BasePresenter
{
    private $database;
    private $cart;

    public function __construct(Context $database, Cart $cart)
    {
        $this->database = $database;
        $this->cart = $cart;
    }

    public function renderHeader()
    {
        $usersCart = $this->database->table("cart")->where("user_id", $this->getUser()->getId())->Count();

        if ($usersCart !== NULL)
        {
            $cartTotal = $this->cart->getTotalPrice();
            $this->template->cartTotal = $cartTotal;

        }
    }
?>

Zvláštní je, že když jdu na url /www/components/header tak se proměnná normálně načte ale ve chvíli kdy header loaduji přes layout.latte ji template nevidí.

Error = Undefined variable: cartTotal

Prosím pomožte mi, strávil jsem nad tímto již několik hodin a stále na to nedokážu přijít.
Potřebuji vědět jak dostanu proměnnou do mé componenty header.latte kterou zobrazuji na každé stránce?

S pozdravem,
unjustolaf

MajklNajt
Člen | 501
+
0
-

Ahoj, odporúčam v prvom rade poriadne preštudovať životný cyklus presenteru https://doc.nette.org/…n/presenters#… – renderNiečo vôbec neslúži na vykreslenie „časti“ stránky…

Ale ku konkrétnemu problému – ak chceš, aby sa ti nejaké premenné vkladali do šablóny pri každom requeste, musíš to dať do metódy beforeRender:

public function beforeRender()
{
		parent::beforeRender()
    $usersCart = $this->database->table("cart")->where("user_id", $this->getUser()->getId())->Count();

    if ($usersCart !== NULL)
    {
        $cartTotal = $this->cart->getTotalPrice();
        $this->template->cartTotal = $cartTotal;
    }
}

Nie je to úplne ideálne riešenie, krajšie a použiteľnejšie by bolo spraviť si komponentu, ale na to časom prídeš sám :)

unjustolaf
Člen | 29
+
0
-

Ahoj, mockrát děkuji za ochotu pomoct mi s mým problémem. V nette frameworku dělám chvíli a neměl jsem moc od koho se jisté věci naučit a v dokumentaci se z vélké části ztrácím. Jistě si životní cyklus presenterů znovu prostuduji :).

Teď k mému problému, tvoje řešení jsem zkusil a bohužel mi vyskakuje pořád ten stejný error.

Když jdu na url: localhost:8888/e-shop/e-shop/www/components/header vše funguje jak má, proměnná je normálně přístupná.

Když ale jdu na jakoukoliv jinou stránku kde se automaticky renderuje header.latte z layout.latte, proměnná je stále nepřístupná.

Můj nynější kód v ComponentsPresenteru:

<?php

namespace App\Presenters;

use Nette;
use Nette\Database\Context;
use App\Model\Cart;

class ComponentsPresenter extends BasePresenter
{
    private $database;
    private $cart;

    public function __construct(Context $database, Cart $cart)
    {
        $this->database = $database;
        $this->cart = $cart;
    }

    public function beforeRender()
    {
		parent::beforeRender();
		$usersCart = $this->database->table("cart")->where("user_id", $this->getUser()->getId())->Count();

        if ($usersCart !== NULL)
        {
            $cartTotal = $this->cart->getTotalPrice();
            $this->template->cartTotal = $cartTotal;
        }
    }


}
?>
Ondřej Kubíček
Člen | 494
+
0
-

protože určitě na jiné stránce načítáš jiný presenter, tak tu metodu beforeRender dej do BasePresenter

CZechBoY
Člen | 3608
+
0
-

btw připomínky k dokumentaci se vždycky hodí… Můžeš založit issue na githubu nebo napsat co kde není jasné třeba tady?

unjustolaf
Člen | 29
+
0
-

To jsem zkoušel už dávno, ale vždy mi vyskočí error při prohledávání databáze na řádku:

<?php
	$usersCart = $this->database->table("cart")->where("user_id", $this->getUser()->getId())->Count();
?>

Error: Call to a member function table() on null

Přitom je to úplně stejný kód jako v ComponentsPresenteru

Celý kód BasePresenteru zde:

<?php

namespace App\Presenters;

use Nette;
use Nette\Database\Context;

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
    private $database;

    public function __construct(Context $database)
    {
        $this->database = $database;
    }

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

        $user = $this->getUser();

        if ($user->isLoggedIn())
        {
            $this->template->loggedin = $user->getIdentity();

			$usersCart = $this->database->table("cart")->where("user_id", $this->getUser()->getId())->Count();

        	if ($usersCart !== NULL)
        	{
            	$cartTotal = $this->cart->getTotalPrice();
            	$this->template->cartTotal = $cartTotal;
        	}
        }

    }
}

?>
Ondřej Kubíček
Člen | 494
+
+1
-

zkus si to tam předat přes @inject a constructor smaž

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
    /** @var Context @inject */
    public $database;

...
}
unjustolaf
Člen | 29
+
0
-

Ondřej Kubíček napsal(a):

zkus si to tam předat přes @inject a constructor smaž

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
    /** @var Context @inject */
    public $database;

...
}

Ondřeji i všem Vám ostatním mockrát děkuji za pomoct s mým problémem, toto řešení mi pomohlo.

Na závěr poslední otázka, abych si z tohohle něco taky odnesl. Když mám tento "@inject" v mém BasePresenteru, všechny ostatní Presentery už proměnnou $database vidí, nebo musím v každém presenteru kde pracuji s databází opět vytvořit tento inject nebo constructor ?

Ondřej Kubíček
Člen | 494
+
0
-

to už jsou základy php, takže public propery samozřejmě už podle názvu vidí jak potomci, tak ji můžeš volat i zvenku

unjustolaf
Člen | 29
+
0
-

Omlouvám se měl jsem tam někde překlep a nefungovalo mi to když jsem v tom daném presenteru odebral constructor tak jsem místo pořádného hledání chyby položil hloupou otázku.

Jen mě ještě zajímalo k čemu je v BasePresenteru tento řádek, nepřijde mi že by něco dělal.

<?php
parent::beforeRender();
?>

A ještě jednou děkuji. Nedokážeš si představit jak moc si mi pomohl.

Pavel Kravčík
Člen | 1196
+
+1
-

@unjustolaf: Jestli používáš nějaké IDE (jestli ne – začni), tak pomocí CTRL+levé myšítko Tě to do té funkce odkáže a můžeš se podívat co se tam děje. Zajistíš kontinuitu – tj. provede se co je ve funkci rodiče a ty k tomu můžeš něco přidat, pokud tu metodu přetěžuješ od rodiče.