Injektovanie DB to parent modelu

- Čamo
 - Člen | 798
 
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?

- Šaman
 - Člen | 2668
 
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)

- Jiří Nápravník
 - Člen | 710
 
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.

- Čamo
 - Člen | 798
 
@Š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)

- Jiří Nápravník
 - Člen | 710
 
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ě.

- Čamo
 - Člen | 798
 
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
 
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
				
- japlavaren
 - Člen | 404
 
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 | 798
 
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
 
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

- Šaman
 - Člen | 2668
 
Č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
 
Šaman napsal(a):
Takhle to nefunguje!
Jéé.. Hlavně že tu radím a vůbec si nevšimnu něčeho takovýho :-D