Vyžadování typu public pro property s atributem Persistent – Trait implementace
- harvalikjan
- Člen | 2
Strávil jsem nepřiměřenou dobu :D hledáním problému v mém kódu, který by způsoboval to, že property nebyla persistentní mezi dotazy. Myslel jsem si že problém byl někde v Ajaxu ale ve skutečnosti jsem omylem nadefinoval typ property na private.
Bylo by super kdyby Nette takovou chybu automaticky hlásil :) Než to však někdo šikovný udělá, budu používat traitu, kterou jsem si na to napsal :D, vložil jsem si jí do BasePresenteru a mám od tohoto problému klid. Tak doufám že se někomu z Vás také hodí nebo někoho schopného inspiruje k řešení přímo v Nette ;)
<?php
declare(strict_types=1);
namespace App\Core;
trait RequirePublicTypeForPropertyWithPersistentAttribute
{
// Attaches a callback to the startup event of the presenter.
public function injectRequirePublicTypeForPropertyWithPersistentAttribute(): void
{
$this->onStartup[] = function () {
$reflection = new \ReflectionClass($this);
foreach ($reflection->getProperties() as $prop) {
foreach ($prop->getAttributes() as $attr) {
if($attr->getName() === 'Nette\Application\Attributes\Persistent' && !$prop->isPublic()){
throw new \Exception("Property with Persistent Attribute '" . $prop->getName() . "' is type '" . $prop->getType() . "' but type public is required");
}
}
}
};
}
}
<?php
namespace App\UI;
use App\Core\RequirePublicTypeForPropertyWithPersistentAttribute;
use Nette;
class BasePresenter extends Nette\Application\UI\Presenter
{
use RequirePublicTypeForPropertyWithPersistentAttribute;
}
- Infanticide0
- Člen | 73
Pravděpodobně je ten čas zanedbatelný, ale i tak bych to raději viděl
spuštěný jen jednou po buildu containeru (má vliv debugMode?).
Neznám Nette\DI tak dobře, abych zaručil, že je to přesně takhle správně
(funguje mi to).
Persistent properties jdou použít jen na UI\Presenter a UI\Control třídách, takže je hledám přes UI\Component předka.
class CheckPersistentPropsExtension extends Nette\DI\CompilerExtension
{
public function afterCompile(Nette\PhpGenerator\ClassType $class)
{
foreach ($this->getContainerBuilder()->findByType(Nette\Application\UI\Component::class) as $component) {
$reflection = new \ReflectionClass($component->getType());
foreach ($reflection->getProperties() as $prop) {
foreach ($prop->getAttributes() as $attr) {
if($attr->getName() === Persistent::class && !$prop->isPublic()){
throw new \Exception("Property with Persistent Attribute '" . $prop->getName() . "' is type '" . $prop->getType() . "' but type public is required");
}
}
}
}
}
}
- harvalikjan
- Člen | 2
Děkuji Infanticide0 za posunutí dále :D, potvrzuji že řešení funguje. Je super že to funguje prostě v celém projektu. Chtělo by to asi pouze ještě upravit tu chybu:
throw new \Exception("Property with Persistent Attribute '" . $prop->getName() . "' is type '" . $prop->getType() . "' but type public is required");
na
throw new \Exception("Property with Persistent Attribute '" . $prop->getName() . "' is not public which is required");
protože informace že property je například int, je naprosto irelevantní a možná i zavádějící, tam problém není.
- jiri.pudil
- Nette Blogger | 1029
Tohle zní jako skvělý kandidát na pravidlo v phpstan/phpstan-nette ;)