Vyšla první betaverze Nette DI 3.0 – pojďte ji otestovat!

před 11 měsíci

David Grudl
Nette Core | 6871
+
+31
-

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!

před 8 měsíci

hrach
Člen | 1818
+
+9
-

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. 17:26)

před 8 měsíci

Nick
Člen | 4
+
0
-

Chtěl bych se zeptat, jak to vypadá s vydáním Nette 3.0? Co jsem pochopil, tak 3.0 existuje teď pouze jako betaverze.
Nyní pracuji na 2.3 a chystám se na upgrade.
Vyplatí se teď upgradovat na 2.4 a potom později na 3.0, nebo si počkat?
Díky.

před 8 měsíci

David Grudl
Nette Core | 6871
+
0
-

Určitě nejprve updatuj na 2.4.

před 8 měsíci

David Grudl
Nette Core | 6871
+
0
-

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.

před 8 měsíci

hrach
Člen | 1818
+
0
-

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

před 8 měsíci

David Grudl
Nette Core | 6871
+
0
-

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.

před 8 měsíci

LukasV
Člen | 5
+
+1
-

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?

před 7 měsíci

Václav Pávek
Backer | 59
+
0
-

Je znám termín kdy bude DI ve verzi RC?

Editoval Václav Pávek (17. 2. 23:11)

před 7 měsíci

David Grudl
Nette Core | 6871
+
+6
-

Měla by vyjít zítra.

před 6 měsíci

h4kuna
Backer | 705
+
0
-

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:
    factory: My\Application\PresenterFactory
#   class: My\Application\PresenterFactory

Editoval h4kuna (19. 3. 15:01)

před 6 měsíci

Mysteria
Člen | 748
+
0
-

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…

před 6 měsíci

Matey
Člen | 142
+
0
-

Ahoj, akurát sa to riešilo na slacku. Je to bug. David Grudl už pripravuje fix.

před 5 měsíci

forgie
Bronze Partner | 12
+
0
-

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

před 5 měsíci

David Grudl
Nette Core | 6871
+
0
-

Co je cílem toho kódu?

před 5 měsíci

forgie
Bronze Partner | 12
+
0
-

Úč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. 12:40)

před 5 měsíci

sorm
Člen | 8
+
0
-

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. 22:27)

před 24 dny

stanley89
Člen | 4
+
0
-

@sorm funguje mi toto:

services:
    someService: App\Services\SomeService
    user:
        setup:
            - '$onLoggedIn[]' = [@someService, onLoggedIn]

Je to vhodné řešení?

před 23 dny

Mabar
Člen | 99
+
0
-

Tyhle komplikované konfigurace s otazníky nemají v neonu co dělat, mělo by to být v CompilerExtension

před 23 dny

Felix
Nette Core | 948
+
0
-

Mabar napsal(a):

Tyhle komplikované konfigurace s otazníky nemají v neonu co dělat, mělo by to být v CompilerExtension

Osobne bych to nezatracoval. Za me uplne v poradku zapis.