Jak vypsat promměnnou z presenteru do Latte

prima.kluk
Člen | 2
+
0
-

Mám tento presenter, formulář

<?php

declare(strict_types=1);

namespace App\FrontendModule\Presenters;

use Nette;
use App\Presenters\ArticleTemplate;
use App\Presenters\BasePresent;
use Nette\Application\UI\Form;
use App\Presenters\BasePresenter;
use App\FrontendModule\Model\CountManager;
use Nette\Utils\ArrayHash;
use Nette\Utils\DateTime;
use Nette\Database\Table\ActiveRow;
/*use Nette\Database\Table\Selection;
use App\Model\DatabaseManager;*/
use Nette\SmartObject;


class RegistracePresenter extends Nette\Application\UI\Presenter
{

    private $database;
    private CountManager $countManager;

    public function __construct(Nette\Database\Context $database, CountManager $countManager)
    {
        $this->database = $database;
        $this->countManager = $countManager;

    }

	protected function createComponentRegistraceInForm(): Form
	{
		$form = new Form;
		$form->addEmail('email', 'e-mail:')
			->setRequired('Prosím vyplňte svůj e-mail.')
			/*->setOption('description', Html::el('p')
					->setHtml('Toto číslo zůstane skryté. <a href="...">Podmínky uchovávání Vašeho čísla</a>'))*/;

		$pohlavi = [
				'm' => 'muž',
				'z' => 'žena',
			];
		$form->addRadioList('pohlavi', 'Pohlaví:', $pohlavi)
			->setRequired('Prosím vyplňte pohlaví.');

		$form->addInteger('vek', 'Věk:')
			->addRule($form::RANGE, 'Věk musí být od %d do %d let', [16, 99])
			->setRequired('Prosím vyplňte věk.');

		$form->addPassword('password', 'Heslo:')
			->setRequired('Zvolte si heslo')
			->addRule($form::MIN_LENGTH, 'Heslo musí mít alespoň %d znaků', 5)
			->setHtmlAttribute('placeholder', 'zvolte si heslo');


		$form->addPassword('passwordVerify', 'Heslo znovu:')
			->setRequired('Opakujte heslo ještě jednou pro kontrolu')
			->addRule($form::EQUAL, 'Hesla se neshodují', $form['password'])
			->setOmitted()
			->setHtmlAttribute('placeholder', 'opakujte pro kontrolu');

		$form->addSubmit('send', 'Registrovat se');

		$form->onSuccess[] = [$this, 'registrationFormSucceeded'];

         $this->template->count = 'ahoj';

		return $form;

	}

    Public function registrationFormSucceeded($form, $values)
    {
        $mail = $form->getComponent('email');
        $count = $this->countManager->hledaEmail($mail);

         $this->template->count = 'ahoj';


		     if($count < 1){


		      //  $values["password"] = Nette\Security\Passwords::hash('password');
		      //  $values["role"] = 'registred';

		      $dateTime = new \DateTime();

		        $row = $this->database->table('users')->insert($values);

		        $result = $this->database->query('UPDATE users SET', [
							'datum_registrace' => $dateTime,
						], 'WHERE id = ?', $row->id);

		        $result->getRowCount(); // vrací počet ovlivněných řádků

		        $this->flashMessage('Byl jste zaregistrován', 'success');
		        $this->redirect('Homepage:');

		    }else{

		        $this->flashMessage('Vy už jste zaregistrován(a)', 'warning');
		        $this->redirect('this');

		    }
    }

/*
	public function registraceInFormSucceeded(Form $form, \stdClass $values): void
	{
		try {
			$this->getUser()->login($values->username, $values->password);
			$this->redirect('Homepage:');

		} catch (Nette\Security\AuthenticationException $e) {
			$form->addError('Nesprávné přihlašovací jméno nebo heslo.');
		}
	}*/
}

Chci vypsat v Latte (výhledově počet existujících stejných emailů, ale zatím pozdrav „ahoj“, což jsem dal $this->template->count = ‚ahoj‘;

V Latte pak mám:

{block content}
<h2 n:block=title>Přihlášení</h2>
{$count}
{control registraceInForm}

A hází to chybu v Laděnce – Undefined variable: count

Můžete poradit, co dělám blbě?

`
`

Marek Bartoš
Nette Blogger | 1167
+
0
-

Do $this->template->count přiřazuješ pozdě. V šabloně chceš pracovat s $count, které však začne existoval až o řádek níž, když poprvé přistoupíš ke komponentě formuláře, čímž se zavolá createComponentRegistraceInForm(), ve které proměnnou nastavuješ.
Komponenta by měla nastavovat při renderu jen proměnné do vlastní šablony, na nastavování proměnných předka je v createComponent*() pozdě. Ideálně bys měl nastavení šablony přesunout do beforeRender() nebo render*()

Michal Kumžák
Člen | 106
+
0
-

Marek Bartoš napsal(a):

Do $this->template->count přiřazuješ pozdě. V šabloně chceš pracovat s $count, které však začne existoval až o řádek níž, když poprvé přistoupíš ke komponentě formuláře, čímž se zavolá createComponentRegistraceInForm(), ve které proměnnou nastavuješ.
Komponenta by měla nastavovat při renderu jen proměnné do vlastní šablony, na nastavování proměnných předka je v createComponent*() pozdě. Ideálně bys měl nastavení šablony přesunout do beforeRender() nebo render*()

To není tak úplně pravda. Po odeslání formuláře, se nejdříve vytvoří komponenta a teprve pak se volá případný render (většinou se totiž provádí přesměrování). Pokud tedy v succeeded nastavuje hodnotu do template, tak se pak v render zobrazí.
Jeho problém je ale v tom, že ta hodnota se naplní jen někdy, proto musí vypsání té hodnoty v latte podmínit:

{ifset $count}
  {$count}
{/ifset}
Marek Bartoš
Nette Blogger | 1167
+
0
-

@MichalKumžák Do proměnné přiřazuje dvakrát, jednou v createComponent. Přiřazení v onSuccess jsem ignoroval záměrně, právě proto že by se mělo přesměrovávat (i kdyby na this) a v takovém případě to přiřazení nedává smysl.

Mít volitelně nedefinovanou či neinicializovanou property bych nedoporučoval, krom edge cases (rozlišení null a nezaslané hodnoty v api) je běžnější řešení mít property nullable

Editoval Marek Bartoš (11. 9. 2021 19:46)

Michal Kumžák
Člen | 106
+
0
-

@MarekBartoš – No právě že jsou i případy, kdy přesměrování nepotřebuješ, například při filtrování, nebo vyhledávání.

Polki
Člen | 553
+
0
-

@MichalKumžák Pravdu máš, ale formuláře mají tu vlastnost, že F5 je znovu odešle.
Proto se vždy po úspěchu přesměrovává.

Tyto konkrétní případy se pak řeší nějakým třeba JS kódem, který jen simuluje odeslání a místo toho udělá request za formulář apod. Ajax to samozřejmě řeší, ale když chceš třeba filtr propsat i do URL, tak to stejně už děláš jinak.

Michal Kumžák
Člen | 106
+
0
-

Polki napsal(a):

@MichalKumžák Pravdu máš, ale formuláře mají tu vlastnost, že F5 je znovu odešle.
Proto se vždy po úspěchu přesměrovává.

Tyto konkrétní případy se pak řeší nějakým třeba JS kódem, který jen simuluje odeslání a místo toho udělá request za formulář apod. Ajax to samozřejmě řeší, ale když chceš třeba filtr propsat i do URL, tak to stejně už děláš jinak.

Standardní vyhledávání se odesílá jednoduše GETem a pak neřešíš nějaký refresh.

chemix
Nette Core | 1296
+
+1
-

@primakluk, cele bych to resil trosku jinak, predavanim dat do formulare v konstruktoru a nejaky pomocnik, co ta data zjisti. Ale jako rychle reseni, mam pocit, ze by ti melo pomoci pridat actionDefault() a v ni zavolat vytvoreni formulare o “fous” driv a tim i do sablony dostat hodnotu.

Viz dokumentace https://doc.nette.org/…in-presenter

$this->getComponent('registrationForm');

PS: me trvalo presunout formulare mimo presentery nekolik let, ale nakonec jsem za to moc rad. Nektere veci se tim trosku “komplikuji”, ale zaroven se zlepsuje citelnost, jasnost a zavislosti