V Error4×xPresenteru nefunguje handle<signal> komponenty

m.brecher
Backer | 128
+
0
-

Mám tento problém – v Error4×xPresenteru nefunguje handle<signal> komponenty.

V layout.latte mám vloženo odhlašovací tlačítko, pro odhlášení signálem komponenty, a uživatel zůstane na stejné stránce (Presenter:action se nezmění).

layout.latte:

{if $user->isLoggedIn()}
	{control logoutButton}
{else}
	<a n:href="User:default" class="login-button">Přihlásit</a>
{/if}

Odhlašovací tlačítko vyrábím jako komponentu tovární metodou v BasePresenteru:

    public function createComponentLogoutButton()
    {
        return new App\Components\LogoutButton;
    }

Třída LogoutButton – obsahuje handler pro obsluhu signálu logoutButton:logout! k volání handleru ale nedojde

class LogoutButton extends Component
{
    public function  render()
    {
        $this->presenter->template->render(__DIR__.'/templates/logoutButton.latte');
    }

    public function  handleLogout(): void
    {
        $this->presenter->user->logout();
        $this->presenter->redirect('this');
    }
}

Šablona tlačítka logoutButton.latte:

<a n:href="logoutButton:logout!" class="login-button">Odhlásit!</a>

Chci, aby se při BadRequestException vykreslil celý layout webu včetně menu. Výjimka BadRequestException skončí nakonec u Error4×xPresenteru. V layoutu je vloženo menu, které se generuje z dat v databázi a odhlašovací tlačítko. Chybová šablona 404.latte se vykreslí do standardního layoutu layout.latte a aby byly k dispozici data, dědí ErrorXxxPresenter z BasePresenteru, kde využije metodu injektXxx() a beforeRender(), kde se závislosti předají do layoutu. Děděním předejdu duplikování kódu, i když s sebou možná nese drobné riziko ohledně bezpečnosti (??)

final class Error4xxPresenter extends BasePresenter
{
   .......
}

Všechno to funguje, až na situaci, když se vyvolá při testování BadRequestException např. záměrně chybějící šablonou akce. Vzniknou hned tři problémy:

  1. Tlačítko neodkazuje na původní presenter, ale na Error4×xPresenter.
  2. Po kliknutí na odhlašovací tlačítko se v presenteru vyvolá signál logoutButton:logout, nedojde ale k zavolání LogoutButton::handleLogout()
  3. $this->presenter->redirect(‚this‘) v handleru signálu tlačítku by přesměroval na aktuální presenter a akci, což je Error4×x, k tomu sice díky chybám ani nedošlo, ale i toto není dobré

Pokud není BadRequestException vš funguje ok, když se vyvolá BadRequestException, tlačítko se vykreslí, signál je presenterem správně zachycen, ale nezavolá se LogoutButton::handleLogout().

Odhaduji, že framework nette nedovolí zpracovat signál, když se presenter forwarduje na další presenter – asi z bezpečnostních důvodů (???)

Zkusil jsem ještě toto, ale není to v Nette dovoleno:

<a n:href=":Presenter:akce:logoutButton:logout!" class="login-button">Odhlásit!</a>

Zřejmě není úplně dobrý nápad při BadRequestException se pokoušet odhlásit. Tak asi při vyvolání Error4×xPresenteru v layout.latte odstraním vykreslení tlačítka a bude to.

K uvedené problematice mám dva dotazy:

  1. Není chybou z pohledu best practice a z pohledu bezpečnosti podědit Error4×xPresenter extends BasePresenter ??
  2. Je zablokování signálu v Error4×xPresenteru správné chování frameworku, nebo tam mám nějakou chybu a mělo by to fungovat ??

Díky za případné nápady.

Editoval m.brecher (24. 9. 2021 3:25)

m.brecher
Backer | 128
+
0
-

Nakonec jsem dospěl k názoru, že ErrorPresenter by neměl z BasePresenteru dědit z bezpečnostních důvodů.

Error4×xPresenter jsem odvodil z Nette\Application\UI\Presenter, závislost pro vykreslení menu v layout.latte jsem předal metodou inject<component>() a problematickou komponentu logoutButton jsem zrušil úplně:

final class Error4xxPresenter extends Nette\Application\UI\Presenter  // zrušeno dědění z BasePresenteru
{
    private App\Model\SectionModel $sectionModel;

    public function injectSectionModel(App\Model\SectionModel $sectionModel): void  // získání závislosti pro layout.latte
    {
        $this->sectionModel = $sectionModel;    // pro @layout.latte
    }
	public function renderDefault( ... ): void
    {
        $this->template->sections = $this->sectionModel->getSectionList();  // předání závislosti do layout.latte
	    .......
	}
}

Neexistenci komponenty logoutButton v layout.latte při volání ErrrorPresenteru jsem ošetřil takto:

{if isset($presenter['logoutButton'])}{control logoutButton}{/if}