contributte / planette-site

💀 [DISCONTINUED] All the roads go through the Planette
https://planette.vercel.app
MIT License
9 stars 3 forks source link

2015-04-24: inject-autowire #33

Open paveljanda opened 7 years ago

paveljanda commented 7 years ago

Pokud se budeme řídit pravidlem „>>Zapomeňte, že existuje nějaký $this->context,<<“ budeme si muset do presenterů předávat závislosti jiným způsobem.

Jednou z novinek v Nette 2.0.5 je autowire pomocí inject metod v presenteru. Ve své podstatě se jedná o setter injection s jedním rozdílem oproti běžnému setteru -- bežný setter je možné volat opakovaně. Inject metody se naopak smí volat pouze jednou (v opačném případě by mohlo dojít k nečekanému chování) a metoda sama by v případě opakovaného volání měla vyhazovat výjimku.

Ukázka

abstract class BasePresenter extends \Nette\Application\UI\Presenter
{
        /** @var Settings */
        protected $settings;

        /**
         * @param Settings
         */
        public function injectSettings(Settings $settings)
        {
                if ($this->settings) {
                        throw new Nette\InvalidStateException('Settings has already been set');
                }
                $this->settings = $settings;
        }

        protected function beforeRender()
        {
                $this->template->appName = $this->settings->get('appName');
        }
}

class ArticlesPresenter extends BasePresenter
{
        /** @var Articles */
        protected $articles;

        /**
         * @param Articles
         */
        public function injectArticles(Articles $articles)
        {
                if ($this->articles) {
                        throw new Nette\InvalidStateException('Articles has already been set');
                }
                $this->articles = $articles;
        }

        public function renderDetail($id = 0)
        {
                // pochopitelně zde by nejprve měla být kontrola, zda vůbec článek existuje atd.
                $this->template->article = $this->articles->find($id);
        }
}

Nette nám automaticky do Articles presenteru předá námi očekávané služby, tj. službu, jež je typu Articles (skrze volání metody injectArticles) a službu typu Settings (již potřebuje BasePresenter).

Problémy

Autowire je automatizace a žádná automatizace není zcela dokonalá. I autowiring pomocí inject metod má své mouchy.

Více instancí nebo implementací požadovaného typu

Uvažujme, že máme takovouto inject metodu:

public function injectFoo(IFoo $foo) { ... }

Zároveň předpokládejme, že v DI containeru máme více služeb implementujících námi žádané rozhraní IFoo. V tento moment nastává situace, kdy autowiring není technicky možný -- Nette není schopno rozpoznat, kterou z možných instancí požadujeme a vyhodí výjimku.

Podívejte se na potenciální budoucí řešení tohoto problému na fóru.

Parametry a továrničky

Skrze inject metody lze předávat pouze služby (objekty). Nelze takto automaticky předávat továrničky, ani parametry.

Budoucnost

V aktuální vývojové verzi Nette (2.1-dev) jsou inject metody automaticky volány i na všech službách a továrničkách v DI containeru. Tuto funkcionalitu je možné u jednotlivých služeb nebo továrniček vypnout:

services:
        foo:
                class: Foo
                inject: no # vypne volání inject
paveljanda commented 7 years ago

author: 1639 ()