[2011–05–05] Finalizace Dependency Injection

před 7 lety

Elijen
Člen | 174
+
0
-

HosipLan napsal(a):

Neříkám, že ActiveRecord je anti-pattern sám o sobě, nechce se mi to zjišťovat, ale navzájem se vylučuje s Dependency Injection.

A tomu se také snažím oponovat. Nevidím totiž důvod, proč by ActiveRecord nemohl DI používat. V čem se tedy vylučuje s DI?

před 7 lety

Ondřej Mirtes
Člen | 1539
+
0
-
Article::findAll();

Jak tam chceš něco vstříknout?

před 7 lety

Filip Procházka
Moderator | 4692
+
0
-

Tak schválně, rád se poučím. Ukaž jak ActiveRecord využívá Dependency Injection.

před 7 lety

Yrwein
Člen | 45
+
0
-

Je problém (technický) vytvářet entity uvnitř nějaké továrny (namísto rovnou operátoru new), která se dokáže postarat o injektnutí spojení k db? (A nyní neřeším, jestli taková knihovna nyní existuje, neb to sám nevím. .])

Edit: Aneb vzor ActiveRecord imho nepředpokládá, že musí přistupovat ke svým závislostem z nějakého statického globálního kontextu.

Editoval Yrwein (14. 6. 2011 19:29)

před 7 lety

bojovyletoun
Člen | 671
+
0
-

Article::$connection=…; :)

před 7 lety

David Grudl
founder | 6735
+
0
-

Chcete vidět Active Record s DI? http://goo.gl/yZDa9

před 7 lety

Filip Procházka
Moderator | 4692
+
0
-

Nojo, ale to už není ten pure statickej ActiveRecord :) Kam se vůbec řadí Nette\Database a NotORM? K AR to má určitě blízko, tojo…

před 7 lety

JAM3SoN
Člen | 182
+
0
-

No ty woe, Davidek ma novy avatar.

před 7 lety

gofry
Člen | 6
+
0
-

David Grudl napsal(a):

Chcete vidět Active Record s DI? http://goo.gl/yZDa9

Presne na toto som sa akurát pozeral a nie je mi úplne jasné, prečo sa do konštruktoru predáva $users miesto $database. Nie je úlohou práve modelu Authenticator, aby sa o všetko postaral sám? Tj. o to, kde sú users uložení, ako ich vytiahnúť a ako ich autentikovať?

před 7 lety

Šaman
Člen | 2241
+
0
-

gofry napsal(a):

Presne na toto som sa akurát pozeral a nie je mi úplne jasné, prečo sa do konštruktoru predáva $users miesto $database. Nie je úlohou práve modelu Authenticator, aby sa o všetko postaral sám? Tj. o to, kde sú users uložení, ako ich vytiahnúť a ako ich autentikovať?

Určitě nemá. Authenticator má autentizovat, tedy rozhodnout jestli uživatel je skutečně ten, za kterého se vydává. A je mu šumák kde se ten uživatel vzal. O to se stará jiná část modelu.

A pokud budeš chtít automaticky testovat authenticator, předáš mu pole testovacích dat a víš co máš mít na výstupu. Pokud by si sám sahal do databáze, tak je špatně testovatelný. A navíc by se porušil princip jedna funkce na jednom místě (UsersModel i Authenticator by si implementovaly načítání usera.)

Editoval Šaman (16. 7. 2011 5:58)

před 7 lety

Jan Suchánek
Člen | 403
+
0
-

Zajímavý článek od Vaška Purcharta o Dependency Injection.

Editoval jenicek (18. 7. 2011 17:06)

před 7 lety

gofry
Člen | 6
+
0
-

Šaman napsal(a):

gofry napsal(a):

Presne na toto som sa akurát pozeral a nie je mi úplne jasné, prečo sa do konštruktoru predáva $users miesto $database. Nie je úlohou práve modelu Authenticator, aby sa o všetko postaral sám? Tj. o to, kde sú users uložení, ako ich vytiahnúť a ako ich autentikovať?

Určitě nemá. Authenticator má autentizovat, tedy rozhodnout jestli uživatel je skutečně ten, za kterého se vydává. A je mu šumák kde se ten uživatel vzal. O to se stará jiná část modelu.

A pokud budeš chtít automaticky testovat authenticator, předáš mu pole testovacích dat a víš co máš mít na výstupu. Pokud by si sám sahal do databáze, tak je špatně testovatelný. A navíc by se porušil princip jedna funkce na jednom místě (UsersModel i Authenticator by si implementovaly načítání usera.)

Mal by teda existovať model User s metodou getAllUsers() a jej výstup by sa predal authenticatoru? Pozeral som si totiž príklad CD Collection z dev verzie Nette a tam je len Model.php, ktorý v sebe obsahuje ako getAlbums() tak createAuthenticatorService(). Nejak sa mi nevidí, aby tieto metódy boli spolu v jednom modeli.

před 7 lety

Filip Procházka
Moderator | 4692
+
0
-

Ne, měla by existovat služba, která ti načte uživatele podle jména (nebo emailu) a tu předáš authenticatoru. Authenticator ji potom zavolá. Ta mu vrátí nějaký výsledek a on porovná heslo a popř. další detaily.

Třeba takto:

use use Nette\Security\AuthenticationException;

class Authenticator extends Nette\Object implements Nette\Security\IAuthenticator
{

    /** @var Users */
    private $users;

    /**
     * @param Users $users
     */
    public function __construct(Users $users)
    {
        $this->users = $users;
    }

    /**
     * @param array $credentials
     * @return Nette\Security\IIdentity
     */
    public function authenticate(array $credentials)
    {
        $identity = $this->users->findByNameOrEmail($credentials[self::USERNAME]);

        if (!$identity instanceof Identity) {
            throw new AuthenticationException('User not found', self::IDENTITY_NOT_FOUND);

        } elseif (!$identity->isPasswordValid($credentials[self::PASSWORD])) {
            throw new AuthenticationException('Invalid password', self::INVALID_CREDENTIAL);

        } elseif (!$identity->isApproved()) {
            throw new AuthenticationException('Account is not approved', self::NOT_APPROVED);
        }

        return $identity;
    }

}

Ty pak authenticator klasicky registruješ třeba v Configu, nebo Configuratoru. Třeba takto:

services:
    users:
        class: Users
        arguments: [@connection]

    authenticator:
        class: Authenticator
        agruments: [@users]

před 7 lety

gofry
Člen | 6
+
0
-

Hm, takže tá služba vlastne nie je nič iné ako model, akurát miesto toho, aby som nejakému inému modelu alebo presenteru apod. predával výstupy z daného modelu, tak mu predám rovno celý model.

A keď niekto využíva veľa iných modelov, tak mu predám rovno celý kontajner modelov, nech sa nemusí o každý model starať samostatne. Alebo dám rovno každému celý kontajner všetkých modelov a on si už z nich vyberie čo potrebuje. Rozumiem tomu správne?

před 7 lety

Filip Procházka
Moderator | 4692
+
0
-

gofry napsal(a):

Hm, takže tá služba vlastne nie je nič iné ako model, akurát miesto toho, aby som nejakému inému modelu alebo presenteru apod. predával výstupy z daného modelu, tak mu predám rovno celý model.

Modely můžou o sobě navzájem vědět a jeden druhý využívat.

A keď niekto využíva veľa iných modelov, tak mu predám rovno celý kontajner modelov, nech sa nemusí o každý model starať samostatne. Alebo dám rovno každému celý kontajner všetkých modelov a on si už z nich vyberie čo potrebuje. Rozumiem tomu správne?

Tohle je už není tak správně jak by se mohlo zdát. Tím že dáš každému modelu celý kontejner, tak mu v podstatě dáváš přístup i ke službám, které nepotřebuješ a trochu tím špaleš i po Dependency Injection.

Lepší je každému modelu předávat toho co nejméně. Jenom to co potřebuje.

Pokud toho model potřebuje opravdu hodně, tak je dobré mu ty služby předat v novém containeru. Jde vytvořit i v configu, ale nevypadá to pěkně. Takže třeba:

public static function createServiceUzivatele(Container $container)
{
    $context = new Container();
    $context->addService('authenticator', $container->authenticator);
    $context->addService('authorizator', $container->authorizator);
    // .. další služby nebo parametry

    return new UzivateleModel($context);
}

Tím jednotlivé služby od sebe pěkně oddělíš.

Také je potřeba se zamyslet, pokud model potřebuje moc služeb. Znamená to, že toho dělá moc a měl by jsi ho rozdělit na více tříd/služeb. Přijatelné jsou cca 3 až 4 jiné služby. Cokoliv více už může (může !== musí) znamenat, že je špatně vymyšlený.

Editoval HosipLan (22. 7. 2011 12:36)

před 7 lety

Elijen
Člen | 174
+
0
-

Zdravím,

Jestliže mám ve vlastním Containeru definované služby staticky, je možné nějak určit její typ? Zejména kvůli metodě Containeru getServiceByType. Bez typeHintu totiž metoda službu nalezne pouze v případě, že již byla vytvořena její instance.

před 7 lety

Jan Endel
Člen | 1003
+
0
-

v Netbeans určitě v jiných IDE si nejsem jist funguje:

/**
 * @property-read MyService myService
 */
class MyContainer extends \Nette\DI\Container
{
    public function createServiceMyService()
    {
        return new MyService();
    }
}

před 7 lety

Elijen
Člen | 174
+
0
-

pilec napsal(a):

v Netbeans určitě v jiných IDE si nejsem jist funguje:

Měl jsem na mysli typeHint pro Nette Container nikoliv pro IDE.

před 7 lety

Patrik Votoček
Člen | 2249
+
0
-

Na to je Nette\DI\Container::TAG_TYPEHINT aneb „speciální“ tag.

před 7 lety

Elijen
Člen | 174
+
0
-

Patrik Votoček napsal(a):

Na to je Nette\DI\Container::TAG_TYPEHINT aneb „speciální“ tag.

Toto jsem ze zdrojáků Containeru vypozoroval, ale stále nemohu zjistit, jak tento tag nastavit pro staticky vytvořenou službu (metodou createServiceXYZ ve vlastním kontajneru dědícím z Nette\DI\Container).

před 7 lety

Patrik Votoček
Člen | 2249
+
0
-

Tahle funkcionalita bohužel ve standardním Nette není

před 7 lety

Patrik Votoček
Člen | 2249
+
0
-

Odstranění DI\Container::getServiceNamesByTag() je trvalé? Nebo se objeví zpět? Mám poslat pull?

Btw: bude někde sepsáno pár slov k novinkám v kontejneru (autowire)?

před 6 lety

David Grudl
founder | 6735
+
0
-

Patrik Votoček napsal(a):

Odstranění DI\Container::getServiceNamesByTag() je trvalé? Nebo se objeví zpět? Mám poslat pull?

K čemu to používáš?

před 6 lety

Patrik Votoček
Člen | 2249
+
0
-

Ke spoustě věcí.

V systému mám například něco čemu říkáme „globální komponenty“. Zaregistruju si komponentu do DIC s tagem „component“ a na základě toho si je presenter / control vytáhne.

Nebo na listenery k Doctrine. Továrnička na EntityManager řekne DIC že chce všechny služby s tagem „listener“ a nastaví je EventManageru.

Pak taky na console commandy. (Jednotlivé příkazy pro CLI).

Těch příkladů by se našlo více…

před 6 lety

paranoiq
Člen | 388
+
0
-

tag není interface

před 6 lety

Patrik Votoček
Člen | 2249
+
0
-

paranoiq napsal(a):

tag není interface

tak nějak nevím co jsi tím chtěl říct…

před 6 lety

Filip Procházka
Moderator | 4692
+
0
-

No, kdyby ty služby měly specifický interface, nemohl by to nějak řešit nový autowire? Nedaly by se nějak v „compile-time DIC“ vytáhnout všechny služby určitého typu? Commity jsem procházel, ale je tam moc generování phpka a celkově jsem z toho krapet zmatený :)

před 6 lety

Yrwein
Člen | 45
+
0
-

Parafráze: Interface není tag. :)

Tzn. interface by neměl sloužit k označování – tagování může být „dynamické“ (pro každou aplikaci třebas budou jiné komponenty ozančené jako „globální“ nebo budou komponenty označeny jinak), kdežto interface je u třídy „natvrdo“. (Edit: Čímž neříkám, že někdy se nemůže vybírání jen dle interface hodit.)

Editoval Yrwein (25. 10. 2011 17:04)

před 6 lety

Patrik Votoček
Člen | 2249
+
0
-

Yrwein napsal(a):

… tagování může být „dynamické“ …

to je jasné od toho máme Convention over configuration :-)

A ještě jedna poznámka. Problém je pokud mám v DIC uloženo více komponent (všechny implementují Nette\ComponentModel\IComponent), ale pouze 5 z nich josou ony „globální“ dalších 9, které tam jsou, už „globální“ nejsou. Myslím si, že to je ideální ukázka využití tagů.

před 6 lety

David Grudl
founder | 6735
+
0
-

Tagování a (do jisté míry) hledání podle třídy/interface bude zachováno, jen neexistoval způsob, jak to řešit pro statické kontejnery a kvůli tomu musím pozměnit API.

Hledání podle třídy bude plnohodnotné u všech kontejnerů strojově vygenerovaných (např. z config.neon), u ostatních buď omezeně, nebo vůbec. Důvod je ten, že zjistit u dosud neinstancované/nenačtené třídy její předky a rozhraní znamená nainklůdovat všechny příslušné soubory, což představuje výkonnostní brzdu. K nějakému kešování bych přistoupil až ve chvíli, kdy se generování kontejnerů neosvědčí.

K dokončení upravené implementace DI nechybí moc, tak vydržte. Výsledek bude výrazně pohodlnější a srozumitelnější i pro začátečníky.

před 6 lety

Patrik Votoček
Člen | 2249
+
0
-

Já jsem to u statických kontejnerů řešil zavedením anotace @tags.

Tfuj se mě ulevilo že to bude zachováno… :-)

před 6 lety

Džízis Crust
Člen | 10
+
0
-

Zdravím :)

Tak jsem si to tu celé pročetl, pomačkal odkazy a myslím, že mi to pomohlo o dost vyrůst co se DI týče :) Další věc co mě potěšila je, že mám čekat na pohodlnější a srozumitelnější výsledek. Tak bych se nedočkavě zeptal, kdy to cca přijde? Nebo už jsem to prospal? :Díky

Stránky: Prev 1 2 3 4 RSS tématu