Nette\Security\User – v productionMode nelze předat do konstruktoru – chyba v Nette?

m.brecher
Generous Backer | 863
+
0
-

Ahoj,

narazil jsem na zajímavou chybu při ladění ErrorPresenteru.

Chci aby ErrorPresenter zvládnul vypsat elegantní chybová hlášení 404 a 403 do 3 typů chybových stránek:

a) 404 ve front modulu do @layout-front.latte
b) 404 v admin modulu do @layout-admin.latte – administrace včetně základního menu
c) 403 v admin modulu do @layout-admin-base.latte – administrace jen záhlaví, bez menu

404 v admin modulu je někdy vyhozena presenterem (neexistující záznam), někdy routerem (chyba v url)
403 vyhazuje presenter ve startupu po ověření autorizace

Po delším zkoušení jsem nakonec došel k řešení, kdy ErrorPresenter, který se po výjimce spustí jako první ověří zda je uživatel přihlášen a pokud ne tak forwarduje na speciální error-presenter pro 403.

Do ErrorPresenteru tedy potřebuji předat Nette\Security\User.

Zkoušel jsem získat $user poděděním ErrorPresenteru ze standardní třídy Nette\Application\UI\Presenter:


final class ErrorPresenter extends Nette\Application\UI\Presenter
{
	use Nette\SmartObject;

    public function __construct(
        .......
    )
    {}

	public function run(Nette\Application\Request $request): Nette\Application\Response
	{
		......
		$xxx = $this->user->isLoggedIn();
		.......
     }
}

Tohle vyhodí výjimku, zřejmě po výjimce nefunguje automatické nastavení služby $user v presenteru

Nette\InvalidStateException
Service User has not been set.

Ponechal jsem tedy ErrorPresenter implementovat Nette\Application\IPresenter (sandbox nette projektu) a zkusil předat $user autowiringem:


final class ErrorPresenter implements Nette\Application\IPresenter
{
	use Nette\SmartObject;

    public function __construct(
       .....
       private Nette\Security\User $user,
    )
    {}

	public function run(Nette\Application\Request $request): Nette\Application\Response
	{
		......
		$xxx = $this->user->isLoggedIn();
		.......
     }
}

Huráá – tohle funguje, Nette\Security\User se autowiruje do error-presenteru, celé řešení jsem tedy odladil a funguje přesně podle zadání 100%.

Bohužel jenom v debugMode s nastavením common.neon: application: catchExceptions: true;

Po přepnutí funkčního odladěného řešení se objeví 500 a v /log/exception.log je chyba:

ArgumentCountError: Too few arguments to function App\Presenters\ErrorPresenter::__construct(),
    3 passed in C:\www\cli\karban\temp\cache\nette.configurator\Container_9cee513d85.php on line 364
    and exactly 4 expected in C:\www\cli\karban\app\Presenters\ErrorPresenter.php:18
    @  http://localhost/cli/karban/www/admin/--
    @@  exception--2022-02-21--12-19--fcafa6d16a.html

Ověřil jsem, že chybějící argument pro vytváření App\Presenters\ErrorPresenter je právě Nette\Security\User.

V sekundárních error-presenterech je služba $user v Nette\Application\UI\Presenter plně funkčí v debug i productionMode

Závěr:

a) Standardně přítomná služba $user v potomcích Nette\Application\UI\Presenter v případě výjimky přítomná není (debag i production)
b) $user lze konstruktorem autowirovat do ErrorPresenteru v debugMódu, v productionMódu nikoliv

Kladu otázku, zda je žádoucí, aby nešlo v primárním ErrorPresenteru autowirovat Nette\Security\User, zatímco v sekundárních error-presenterech je $user k dispozici? Zda se nejedná o chybu v Nette, která by se měla opravit?

Určitě není dobré chování Nette, kdy v production módu něco funguje, člověk to odladí a pak v produkčním to nefunguje. Pokud jsou důvody (security?), aby autowiring služby $user nebyl v ErrorPresenteru funkční, mělo by to platit v debugMode i productionMode.

Editoval m.brecher (21. 2. 2022 15:05)

Marek Bartoš
Nette Blogger | 1260
+
0
-

Pokaždý když chceš testovat produkční mód, tak je třeba smazat cache. Není důvod, proč by to v produkčním módu mělo fungovat jinak, než při debugu – jen se ti nepřegeneroval DIC, protože se v produkci nekontrolují změny souborů

Důvod proč nemáš v error presenteru User je, že jen implementuješ IPresenter, zatímco ostatní presentery dědí UI\Presenter. Do UI\Presenter je User předávaný skrze injectPrimary()

Editoval Marek Bartoš (21. 2. 2022 15:48)

m.brecher
Generous Backer | 863
+
0
-

Ahoj, díky, ano je to tím, stačilo promazat cache. Psal jsem ke konci jenom kód v presenteru, ten se necachuje, ale neuvědomil jsem si, že jsem přitom měnil catchException – proto se DIC měnil.

Marek Bartoš
Nette Blogger | 1260
+
0
-

DIC se mění i když měníš závislosti. Obecně vzato se mění, když se změní monitorovaný soubor, což zahrnuje mimo jiné všechny configy a služby. Některá rozšíření mohou například číst statické properties a metody.