Nette\Security\User – v productionMode nelze předat do konstruktoru – chyba v Nette?
- m.brecher
- Generous Backer | 871
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 | 1274
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)
- Marek Bartoš
- Nette Blogger | 1274
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.