Injektovanie DB to parent modelu

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

No nazdar zase,
Môže mi niekto prosím vysvetliť toto:
Mám triedu BaseModel, ktorá je parentom ostatných tried v modely. Chcel som do nej injektnuť databázu, ale píše mi to: „Argument 1 passed to App\Model\BaseModel::__construct() must be an instance of Nette\Database\Context, none given“
Vyzerá to takto:

class BaseModel
{
	/** @var Nette\Database\Context */
	public $database;

	public function __construct(Nette\Database\Context $db)
	{
		$this->database = $db;
	}
}
a childModel

class UserModel extends BaseModel
{

	public function __construct()
	{
		// create database connection
		parent::__construct();

	}
...

Ako to mám napísať, aby to fungovalo? Injektovanie funguje len pri inštancovaní, či prečo to nerobí čo chcem?

CZechBoY
Člen | 3608
+
0
-

V dědících modelech to tahej z toho baseModelu klasicky přes $this->database…

Editoval CZechBoY (6. 8. 2014 22:25)

Šaman
Člen | 2635
+
+1
-

V potomkovi vůbec konstruktor nepiš. Pokud ho potřebuješ, musíš takto:

<?php
class UserModel extends BaseModel
{
	public function __construct(Nette\Database\Context $db, $somethingElse)
	{
		parent::__construct($db);
		# ...
	}
}
?>

P.S.
Pokud by $somethingElse nešlo autowirovat (chtěl bys ho předávat v configu ručně), tak je dobré napsat ho jako první parametr. V configu bys pak měl:

services:
	- NS\UserModel(%somethingElse%) # databáze jako druhý parametr se aurowiruje sama
	- NS\UserModel(..., %somethingElse%) # teď bys to musel dělat takhle

Editoval Šaman (6. 8. 2014 22:29)

Čamo
Člen | 786
+
0
-

@Šaman
To neni moc praktické. Ale asi mi nič iné neostáva, čo?
Díky.

Editoval Čamo (6. 8. 2014 22:44)

Šaman
Člen | 2635
+
0
-

Ne. Jak jsem psal, základní řešení je v potomkovi vůbec konstruktor nepsat.

Anebo přesvědčit Davida, aby inject metody povolil všude. Mě by se to občas hodilo, ale nechci to používat, když by to vyžadovalo hack Nette.

Čamo
Člen | 786
+
0
-

Akurát nad tým rozmýšľam, prečo je to v modeli zakázané. Kôli výkonu, či?

Jiří Nápravník
Člen | 710
+
+3
-

BaseModel je podle mě pěkná prasárna. Pokud to používáš jen proto, že jsi líný autowirovat si databázi vždycky, tak to není dle mě dobrý přístup a znásilňuje to dědičnost + si pak zavařuješ na ten problém s konstruktory.

Base třídy jsou vhodné u presenteru (tam je to skoro až nevyhnutelné) a hodí se i u komponent, ale do modelu bych je teda nedával.

Šaman
Člen | 2635
+
+2
-

BaseModel je trochu nešťastně zvolený název, ale abstraktní Repository a poděděné UserRepository, BookRepository,… jsou přece běžná praxe. Většinou se do nich ale už nic dalšího nepředává.

Čamo
Člen | 786
+
0
-

@Šaman
tým „do nich ale už nic dalšího nepridáva“ myslíš, tých potomkov. Teda, že nepotrebujú prepisovať konštruktor.

@JiříNápravník
Podľa mňa to má presne ten istý význam ako v presenteroch. To že je problém s konštruktorom je podľa mňa iná vec.
Asi by to vyriešilo, keby mal BaseModel metódu database()(dá sa injectovať do metódy?).

Editoval Čamo (7. 8. 2014 12:46)

Šaman
Člen | 2635
+
0
-

Jj, v modelech není časté, že by potomek Repository přepisoval konstruktor. U servisní vrstvy je to něco jiného, ale ta zase většinou nemá parenta.

Jiří Nápravník
Člen | 710
+
0
-

Pokud je to Repository, tak by tam nějaká Base třída být mohla, protože tam pak pravděpodobně budou i nějaký metody jako findBy apod.

Nicméně já to pochopil spíše tak, že to je spíše fasádní/servisní třída a tam tedy base třídy nepatří dle mě.

Šaman
Člen | 2635
+
0
-

On to má zatím všechno dohromady a říká tomu FooModel, spíš se to blíží chytřejšímu FooRepository.

Čamo
Člen | 786
+
0
-

A čo injektnúť to do toho BaseModelu cez metódu injectDatabase()?
Našiel som v dokumentácii ako sa to robí
ale u seba to neviem rozchodiť. Nerozumiem tej syntaxy v NEONe
U mňa Neon vyzerý takto:

services:
	- App\RouterFactory
	router: @App\RouterFactory::createRouter
	- \App\Model\UserModel
	- \App\Model\GeneralModel
	- \App\Model\BaseModel
	inject: yes	# nefunguje ani s odsadením píše "expects to be callable or stdClass or null, boolean given"

V dokumentácii je zápis:

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

čo je úplne iná syntax. Prečo tam ja mám pomlčky a prečo sa v docu tie services pomenovávajú… nechápem.

David Kudera
Člen | 455
+
-1
-

Pokud má mít služba nějaké další nastavení, tak je potřeba ji pojmenovat a zbytek odsadit pod ni. A nebo třeba takhle bez pojmenování:

services:
	-
		class: App\Service3
		inject: yes
Čamo
Člen | 786
+
0
-

@DavidKudera
Díky, funguje to.

A je to dobrý nápad, takto to injektovať?

EDIT:
omyl nefunguje, len ešte neviem prečo…

Editoval Čamo (7. 8. 2014 15:25)

David Kudera
Člen | 455
+
0
-

No třeba mě osobně se to vůbec nelíbí, ale některým zase jo.. Takže než znovu rozebírat to stejné, tak si počti tady a tady ;-)

japlavaren
Člen | 404
+
0
-

osobne to riesim tak, ze mam ModelDependencies ktory predavam base modelu a potomkom, ktore prepisuju base konstruktor

na @inject hocikde funguje jednoduchy hack

<?php
class XXX
{
	public function __construct(DI\Container $container) {
		$container->callInjects($this);
	}
}
?>

Editoval japlavaren (7. 8. 2014 16:32)

Čamo
Člen | 786
+
0
-

Prečo mi nefunguje ten inject?

services:
	- App\RouterFactory
	router: @App\RouterFactory::createRouter
	- \App\Model\UserModel
	- \App\Model\GeneralModel
	-
		class: App\Model\BaseModel
		inject: yes

Skúšal som to aj pomenovať, ale stále je $database->table() „on non object“.

class BaseModel
{
	/** @var Nette\Database\Context */
	public $database;

	public function __construct()
	{
		//$this->database = $db;
	}

	public function injectDatabase(Nette\Database\Context $db)
	{
		$this->database = $db;
	}

}

Skúšal som všetky možné kombinácie. Nevidí tam niekto nejakú chybu?

Editoval Čamo (8. 8. 2014 10:53)

David Kudera
Člen | 455
+
0
-

A kde k tomu $database->table() přistupuješ? zkus si třeba do té inject metody dát dump té databáze, jestli se to v pohodě zavolá. A kdyžtak konstruktor se volá jako první a ne inject, takže jestli máš to volání table v konstruktoru, tak to fungovat určitě nebude

Čamo
Člen | 786
+
0
-

@DavidKudera
Dumpnúť som to skúšal, ale skončilo to hláškou, problém s odoslanými hlavičkami… Dá sa to nejako obísť?

Editoval Čamo (8. 8. 2014 11:15)

Šaman
Člen | 2635
+
+1
-

Čamo napsal(a):

Prečo mi nefunguje ten inject?

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

Takhle to nefunguje! Ty přece nepoužíváš instanci BaseModelu, ale nějakého konkrétního modelu, dejme tomu UserModelu. A právě teď jsi kontejneru řekl, ať vytvoří instanci BaseModel a nainjectuje do ní nějaké závislosti. Ale pak už tuhle instanci nepoužíváš (správně by měla být ta třída abstraktní, takže nevytvořitelná).
Ty tohle musíš napsat k tomu UserModelu (a ke všem dalším potomkům BaseModelu)!
Proto je v tomto případě jednodušší řešit to konstruktorem.

Editoval Šaman (8. 8. 2014 11:27)

David Kudera
Člen | 455
+
0
-

Šaman napsal(a):

Takhle to nefunguje!

Jéé.. Hlavně že tu radím a vůbec si nevšimnu něčeho takovýho :-D

Čamo
Člen | 786
+
0
-

@Šaman
Ok tak to nechám v tom konštruktore.
Díky.

Šaman
Člen | 2635
+
0
-

David Kudera napsal(a):

Šaman napsal(a):

Takhle to nefunguje!

Jéé.. Hlavně že tu radím a vůbec si nevšimnu něčeho takovýho :-D

Já tyhle věci vidím až od té doby, co jsem zkoušel Nette učit. :)

Editoval Šaman (8. 8. 2014 11:39)