Jak na DI v modelu, dědičnost

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
bluray
Člen | 178
+
0
-

Ahoj, chci se zeptat jak používat DI v modelu. Mám například toto:

class AbstractUser{

}

class Admin extends AbstractUser{

}

class User extends AbstractUser{

}

class Guest extends User{

}

Problém je v tom, že aby všechny třídy mohli pracovat s databází, musí dostat do konstruktoru Context. Nejde to udělat tak, aby Context dostal pouze AbstractUser? Myslím že DI by to neporušilo. já přece vím, že třída Admin dědí od AbstractUser a vím, že ten přijímá Context.
Našel jsem tento článek a tam je ukázána emulace inject property. co si o tom myslíte? je to vhodné použít? Nechápu proč inject property lze v pohodě používat u Presenterů ale u modelů tato možnost úplně chybí.
Díky za radu.

Šaman
Člen | 2666
+
0
-

Tohle už se tu řešilo. David má už ve vývojové verzi připravené řešení, musíme si ale počkat na Nette 2.3.
Do té doby si můžeš buď zapnout injectováni v configu (u všech potomků), nebo použiješ extension, která je zapne za tebe. Všechny možnosti by měly být popsané v tom odkazu, včetně kritik daného řešení.

Šaman
Člen | 2666
+
0
-

Jinak property injection je podle mě nejhorší možná možnost – porušuje zapouzdření. To si raději zapni možnost klasických inject metod.

bluray
Člen | 178
+
0
-

Díky za radu. Mohl bys mi prosím tě ukázat jak to v mém konkrétním případě udělat? četl jsem ten odkaz a nějak to v tom nevidím. Díky

trejjam
Backer | 65
+
0
-

Pokud se jedná jen o přístup k databázi, zachoval bych ji v konstruktoru abstraktní třídy (chybí klíč. slovo abstract). Pokud toho bude víc zapl bych inject:

services:
    service3:
        class: App\Service3
        inject: yes

U modelů chybí proto že zhoršují čitelnost závislostí, v presenterech jsou z důvodu pohodlnosti.

bluray
Člen | 178
+
0
-

Díky, jen pro ujasnění. Ted stačí, abych dal Context jen do konstruktoru AbstractUser a u jeho potomků už můžu přistupovat k db bez toho aby i oni měli Context v konstruktoru?

bluray
Člen | 178
+
0
-

Ne, už jsem na to přišel. Funguje to. díky moc. Jenom ještě se chci zeptat, jestli vždy musím pojmenovávat v configu service. ted tam mám toto:

services:
		admin:
				class: \App\Model\Admin
				inject: yes

Jde udělat něco jako:

services:
		\App\Model\Admin
				inject: yes
David Kudera
Člen | 455
+
0
-
services:
	-
		class: App\Model\Admin
		inject: yes

	# když nepotřebuješ inject a další nastavení, tak stačí i jen toto:

	- App\Model\Admin

Editoval David Kudera (29. 11. 2014 12:56)

trejjam
Backer | 65
+
0
-

v současnosti je nejjednodušší zápis (ve 2.3 by to mělo jít přes extensions (nebo si napsat již nyní svou)):

services:
	-
		class: \App\Model\Admin
		inject: yes

ke konstruktoru:

abstract class AbstractUser {
	private $db;
	function __construct(...\Context $database) {
		$this->db=$database;
	}
}
class Admin extends AbstractUser {
	function load($id) {
		$user=$this->db->table(...)->get($id);
		if (!$user) throw new Exception("Pod tímto ID nic není");
		return $user;
	}
}
bluray
Člen | 178
+
0
-

Děkuji vám za pomoc, moc mi to pomohlo. S tím extension by to bylo tak, že bych nemusel u každé služby mít inject? Nemáte odkaz na to jak to udělat přes extension?

trejjam
Backer | 65
+
0
-

Vzhledem k tomu že 2.3 je zatím dev verze tak k ní není dokumentace (pokud vím). O tom že to půjde vím od Davida syntax neznám.

Šaman
Člen | 2666
+
0
-

Ano, s extension je každá služba v DI kontejneru automaticky nastavená jako inject: yes

V Nette 2.3 to bude trochu jinak, tohle jen zapnutí injectování v Nette 2.2

bluray
Člen | 178
+
0
-

Ještě bych se jednou rád k tomuto tématu vrátil. Mám ted něco takového:

class UserModel{

    /**
     * @var MySql\UserMySqlStorage
     */
    private $database;

    /**
     * @param \App\Model\MySql\UserMySqlStorage $database
     */
    public function __construct(MySql\UserMySqlStorage $database) {
        $this->database = $database;
    }
}

class AdminModel extends UserModel{

    /**
     * @var Xml\XmlStorage
     */
	private $xml;

	public function __construct(Xml\XmlStorage $xml){
		$this->xml = $xml;
    }

Mám třídy UserMySqlStorage a Xml\XmlStorage registrované jako služby. A AdminModel je registrován výše popsaným způsobem. Vše funguje do té doby dokud nepřidám k AdminModel konstruktor s Xml. potom mám v AdminModel pouze objekt XmlStorage a database je null. Dělám to špatně, nebo to nejde? Asi budu muset do AdminModelu přidat i ten UserMySqlStorage že?
Díky

Mysteria
Člen | 797
+
+1
-

Pokud v potomku přepíšeš konstruktor, tak pak musíš volat parent konstruktor…

class AdminModel extends UserModel{
    /**
     * @var Xml\XmlStorage
     */
    private $xml;

    public function __construct(MySql\UserMySqlStorage $database, Xml\XmlStorage $xml) {
		parent::__construct($database);
        $this->xml = $xml;
    }
bluray
Člen | 178
+
0
-

Díky, myslel jsem jestli to náhodou neumí nette doplnit samo.