Vyšla první betaverze Nette DI 3.0 – pojďte ji otestovat!
- David Grudl
- Nette Core | 8227
Právě vyšla první betaverze Nette DI 3.0. Je za ní měsíc velmi intenzivní práce, obrovský refaktoring, samozřejmě se snahou maximálně zachovat zpětnou kompatibilitu. A tu bych právě potřeboval otestovat.
- Z pohledu uživatele by tato verze měla být 99.9% kompatibilní.
- Z pohledu vývojáře CompilerExtension jsou drobné změny používáte-li generované továrny
Vždycky dávám enormní úsilí do zachování zpětné kompatibility. Tam, kde to nelze, generuje Nette co nejsmysluplnější chybové hlášky, aby přechod byl co nepříjemnější. Knihovny jsou velmi pečlivě pokryty testy. Nicméně i přes tohle všechno se stává a bude stávat, že něco přestane fungovat. Že vznikne nekompatibilita, která nebyla záměrná, nebo ji lze řešit lépe. Proto existují testovací verze. Od vás chci slyšet o každém problému. Takže je to o komunikaci, když místo ní budete nadávat, že „jsem něco rozbil“, nelze to brát na zřetel :-)
Nette DI prošlo obrovským a potřebným refactoringem, který otevírá úplně nové možnosti, jak lze DI kontejner vylepšovat. Obsahuje i řadu novinek, jako je autowiring polí služeb, multi-accessory a multi-továrny, apod, hodně jich je ještě v plánu, nicméně teď se chci věnovat spíše změnám v této betě.
Změny z pohledu uživatele
Z DI jsem odstranil několik věcí, které považuju za historické
relikty, jako je podpora INI souborů, přímý zápis PHP kódu do konfigurace
pomocí otazníků a možná něco dalšího. Pokud to potřebujete zachovat,
dejte vědět. Při použití zápisu class: PDO(...)
vás
upozorní, že byste měli použít factory: PDO(...)
.
Změnou je, že nyní je vyžadována u každé služby znalost jejího typu – tj. oproti dřívějšku i u těch, co mají vypnuté autowired.
Změny z pohledu tvůrce Compiler Extensions
Tou hlavní je, že zatímco dosud interně popisoval každou službu objekt ServiceDefinition, dnes existuje definic vícero, tak například ImportedDefinition pro importované neboli dynamic služby, FactoryDefinition pro generované továrničky na základě inteface, AccessorDefinition pro generované accessory a LocatorDefinition pro multi-továrny a accessory.
Ukázka kódu pro DI 2.4:
$builder->addDefinition($this->prefix('latteFactory'))
->setImplement(Nette\Bridges\ApplicationLatte\ILatteFactory::class);
->setFactory(Latte\Engine::class)
->addSetup('setTempDirectory', [$this->tempDir])
->addSetup('setAutoRefresh', [$this->debugMode]);
Jelikož $builder->addDefinition()
vrací právě objekt
ServiceDefinition, který nelze pro generované továrničky použít, zahlásí
Nette chybu:
Nette\DI\Definitions\ServiceDefinition::setImplement() is deprecated, use $builder->addFactoryDefinition(...) or addAccessorDefinition(...)
případně
Nette\DI\Definitions\FactoryDefinition::setFactory() is deprecated, use ->getResultDefinition()->setFactory()
Řešením je mírně upravit kód extenze, tj. jednak nahradit
addDefinition()
za addFactoryDefinition()
případně
addAccessorDefinition()
, a dále protože FactoryDefinition má
trošku jiné API, ještě doplníme getResultDefinition()
před
definici vraceného objektu:
$builder->addFactoryDefinition($this->prefix('latteFactory'))
->setImplement(Nette\Bridges\ApplicationLatte\ILatteFactory::class)
->getResultDefinition()
->setFactory(Latte\Engine::class)
->addSetup('setTempDirectory', [$this->tempDir])
->addSetup('setAutoRefresh', [$this->debugMode]);
Jak vidíte, této změně neušla ani LatteFactory z nette/application.
Prosím o otestování
Díky!
- hrach
- Člen | 1838
Už se snažím upgradovat Nextras Orm a Dbal, v podstatě nepoužívam nic
krom ServiceDefinition, takže prakticky žádný problém, ale co mi přijde
strašně nepohodlné je to, že metoda addDefinition
je takový
prasopes, který vrací jiný typ v PHP, jiný typ v PhpDoc, nemluvě o tom,
že ještě něco vrací dynamicky na základě druhého argumentu.
Přimlouval bych se za to, aby se to udělalo nějak výrazně čistěji. Mj. kvůli tomu dost blbne PhpStorm, který pak neví, kterou definici metod na výsledném objektu člověk volá (Jestli na Definition, nebo na ServiceDefinition) a kvůli tomu taky zahodí deprecated příznak u metody setClass, byť je u obou.
Taky bych ocenil lepší PhpDoc – popis daných classes a metod, co je přidávají, co vlastně ty třídy dělají a umějí. U factory asi zůstal i omylem stejný popis ze service definition.
PS: najít tento thread chce taky vyšší skill. Chtělo by to někam připnout, přiznat si, že zrušené české sekce je nesmysl, …
Editoval hrach (6. 1. 2019 17:26)
- David Grudl
- Nette Core | 8227
hrach napsal(a):
Přimlouval bych se za to, aby se to udělalo nějak výrazně čistěji. Mj. kvůli tomu dost blbne PhpStorm, který pak neví, kterou definici metod na výsledném objektu člověk volá (Jestli na Definition, nebo na ServiceDefinition) a kvůli tomu taky zahodí deprecated příznak u metody setClass, byť je u obou.
Napadá tě, jak to řešit? Dynamické napovídání podle druhého parametru addDefinition() lze asi řešit přes .phpstorm.meta.php. Možnost je přidat metodu addServiceDefinition(), která vždycky vrátí ServiceDefinition (a odstranit @return u addDefinition). Ale v podstatě to znamená tlačit autory všech extensions, aby nahradili addDefinition() za addServiceDefinition()…
U factory asi zůstal i omylem stejný popis ze service definition.
Co konkrétně myslíš?
PS: najít tento thread chce taky vyšší skill. Chtělo by to někam připnout, přiznat si, že zrušené české sekce je nesmysl, …
Nějak to pořeším.
- hrach
- Člen | 1838
Cele to na mě působilo nepřehledně, no. Možná kdyby existovala
addServiceDefinition()
, nemusí se addDefinition nutně
deprecatnout.
Co konkrétně myslíš?
Snažil jsem se přijít na rozdíl mezi jednotlivýma definitions, moc jsem to nechápal, o co jde. https://github.com/…finition.php#L18
- David Grudl
- Nette Core | 8227
Nemusí, jen pak zůstane stejná jako nyní, čímž se to co jsi psal
neřeší. Nebo z ní odstraním ten @return
a vznikne problém
s napovídáním u současného kódu.
- LukasV
- Člen | 5
David Grudl napsal(a):
Nemusí, jen pak zůstane stejná jako nyní, čímž se to co jsi psal neřeší. Nebo z ní odstraním ten
@return
a vznikne problém s napovídáním u současného kódu.
A co tam nechat tu původní addDefinition()
, která by se
chovala pořád stejně a jen přidat novou addServiceDefinition()
.
addDefinition()
by byla deprecated a v nette
4
nebo nějaké jiné velké verzi by se odstranila?
A existuje nějaké doporučení, jak psát rozšíření kompatibilní jak
s nette 2.4
, tak s nette 3
? Vyhodnocovat to třeba
podle toho, jestli existuje metoda addFactoryDefinition()
nebo je
nějaký elegantnější způsob?
- Václav Pávek
- Backer | 100
Je znám termín kdy bude DI ve verzi RC?
Editoval Václav Pávek (17. 2. 2019 23:11)
- h4kuna
- Backer | 740
Je nějaká rozumná možnost podstrčit vlastní třídu, aby si to pamatovalo původní parametry, protože jsem nezměnil konstruktor?
Například chci upravit PresenterFactory. Třidu si podědím, nesáhnu na konstruktor, ale už mi nejde lehce nastavit parametry které se generují v rozšíření ApplicationExtension.
application.presenterFactory:
create: My\Application\PresenterFactory
# class: My\Application\PresenterFactory
Editoval h4kuna (19. 3. 2019 15:01)
- Mysteria
- Člen | 797
Jak se prosím v trojkové verzi dá zapsat registrace Latte filtrů přímo v configu? Na Nette 2.4 jsem používal tohle, ale to momentálně nefunguje:
services:
nette.latteFactory:
setup:
- addFilter(NULL, [@App\Model\Utils\TemplateFilters(%wwwDir%), 'loader'])
Argument 1 passed to Nette\DI\Config\Processor::updateServiceDefinition() must be an instance of Nette\DI\Definitions\ServiceDefinition, instance of Nette\DI\Definitions\FactoryDefinition given, called in /var/www/project/vendor/nette/di/src/DI/Config/Processor.php on line 75
Zkoušel jsem všechno možné, ale nepodařilo se mi vyřešit tu nekompatibilitu ServiceDefinition vs FactoryDefinition…
- forgie
- Bronze Partner | 18
Ahoj, V Nette 2.4. fungovalo napríklad toto:
public function loadConfiguration()
{
$this->compiler->addConfig([ ... parameters ....]);
$this->compiler->processParameters();
Jak toto dosáhnout pomocí DI 3.0? Není vůbec potřeba po
$this->compiler->addConfig()
volat
$this->compiler->processParameters()
? Nebo pokud ano, tak co
to nahrazuje?
Nebo to nebylo potřeba už ani v Nette 2.4. :) ? Nakolik tam se to volalo
i v \Nette\DI\Compiler::compile
.
Díky
- forgie
- Bronze Partner | 18
Účelem je přidat složky s databázovýma migracema z různých extenzí
do \Nette\DI\Container::$parameters
:
V Nette2.4 to bylo:
private function loadMigrations()
{
$this->compiler->addConfig([
'parameters' => [
'migrations' => [
$this->name => [
__DIR__ . '/../migrations',
],
],
],
]);
$this->compiler->processParameters();
}
a to se pak načetlo v extenzi určené pro migrace (hodně zjednodušený kód ale pro představu stačí):
public function loadConfiguration()
{
...
$params['groups'] += $this->getContainerBuilder()->parameters['migrations']
$builder->addDefinition($this->prefix('continueCommand'))
->setClass(Etten\Migrations\Bridges\SymfonyConsole\ContinueCommand::class)
->setArguments($params)
->addTag('kdyby.console.command');
...
Ale co jsem teď zkoušel v Nette 2.4. to funguje i bez volání
$this->compiler->processParameters()
, takže to
$this->compiler->processParameters() asi v DI 3.0 stačí jen
odmazat?
Editoval forgie (17. 4. 2019 12:40)
- sorm
- Člen | 8
Pokud došlo ke zrušení otazníků, jak teď přiřadím událost?
services:
sessionHandler: App\Handlers\Sessionhandler
user:
setup:
- "?->onLoggedIn[] = [?, 'onLoggedIn']"(@self,@sessionHandler)
- "?->onLoggedOut[] = [?, 'onLoggedOut']"(@self,@sessionHandler)
Musím si udělat do příslušné třídy nějakou metodu, která bude sloužit pro nastavování událostí a tu volat místo přiřazení?
Zatím jsem to tedy pojal takto:
services:
sessionHandler: App\Handlers\SessionHandler
user:
class: App\Security\User
setup:
- associateSessionHandler( @sessionHandler )
A uvedená metoda v přetížené třídě na uživatele prostě nastaví ty události, ale to předtím mi umožnilo nedělat třídu jen kvůli těm dvěma asociacím.
Editoval sorm (29. 4. 2019 22:27)
- Marek Bartoš
- Nette Blogger | 1274
Tyhle komplikované konfigurace s otazníky nemají v neonu co dělat, mělo by to být v CompilerExtension