Static vs. non-static method v modelech

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

Snažím se využívat Nette\Database a mám nejnovější beta verzi. Připojení k databázi jsem vyřešil, ale teď řeším jestli to vůbec jde. Do teď mi to šlo jednoduše jen, když jsem data za databáze tahal přímo v presenteru, ale to je potom složitý na správu a je to docela prasácký.

Presenter:

$this->conf = BaseModel::getConfig();

Model:

public static function getConfig() {
	return $this->database->table('config')->fetch();
}

jenže ve statické metodě nebere argument $this->
a v non-static to píše
Non-static method BaseModel::getConfig() should not be called statically, assuming $this from incompatible context
Chtěl jsem to řešit jako když jsem používal dibi, ale pořád se mi to nedaří
a nerad bych používal modelLoader

Michal Vyšinský
Člen | 608
+
0
-

Tady vidím dvě řešení a to ta, že instanci (službu) Nette\Database předáš metodě jako parametr:

public static function getConfig($database) {
        return $database->table('config')->fetch();
}

Pak ale u každého použití metody modelu musíš použít ten parametr.

A nebo ještě si udělat statickou property toho modelu a pak volat self::$database->table…
To bude ale potřeba nějak ošetřit, aby BaseModel::$database bylo nastaveno.

Ot@s
Backer | 476
+
0
-
  1. Koukni se na quickstart (jak správně napasovat/používat model do/v presenteru, viz. souvislosti kolem DI z config.neon)
  2. V modelu lze provést to, co chceš – není to ale hygienické
public static function getConfig() {
        return Nette\Environment::getApplication()->context->database->table('config')->fetch();
}

Editoval Ot@s (6. 1. 2012 15:20)

kashpi
Člen | 48
+
0
-

asi jsem to špatně popsal, takto vypadá celej model

class BaseModel extends \Nette\Object {

	/** @var Nette\Database\Connection */
	private $database;

	public function __construct(Nette\Database\Connection $database) {
		$this->database = $database;
	}


	public function getConfig() {
		return $this->database->table('config')->fetch();
	}
}

Jde o to, že připojení je OK, ale nevím jak toto dostat do presenteru

edit: Protože když dám

$this->conf = BaseModel::getConfig();

tak mi napíše, že potřebuje statickou metodu

Editoval kashpi (6. 1. 2012 15:26)

Michal Vyšinský
Člen | 608
+
0
-

Aha,
tak v tom případě je to jednoduché:
v presenteru:

$model = new BaseModel($this->context->getService("database"));

$model->getConfig();

EDIT: A nebo máš v config.neon registrovaný BaseModel jako službu? V tom případě stačí volat v presenteru:

$this->context->getService("jmenotvesluzby")->getConfig();

Editoval CherryBoss (6. 1. 2012 15:34)

kashpi
Člen | 48
+
0
-

Tak to jsem právě doufal, že se tomu vyhnu, ale asi ne. Každopádně díky :)

edit: Ne nemám v configu mám jen

services:
		database:
			class: Nette\Database\Connection
			arguments: ['%database.driver%:host=%database.host%;dbname=%database.dbname%', %database.user%, %database.password%, ..., Nette\Database\Reflection\DiscoveredReflection()]
			setup:
				- setCacheStorage()

		authenticator: Authenticator(@database)

		authorizator:
			class: Acl

		conn:
			factory: @database

Editoval kashpi (6. 1. 2012 15:39)

Michal Vyšinský
Člen | 608
+
0
-

Tak do service přidej službu basemodel a předej jí jako argument službu database. Myslím že syntax je takto:
(v sekci services)

basemodel:
		class: BaseModel
		arguments: %database

A pak v presenteru používáš model tak jak jsem psal

$this->conf = $this->context->getService("basemodel")->getConfig();

Myslím si, že to bude nejčistší řešení. Ale možná někdo ještě poradí lépe. DI není moje silná stránka ;)

kashpi
Člen | 48
+
0
-

No to jsem prave moc nechtěl všechno řešit přeš config. Protože čím víc bude modelu, tak tím víc jich budu muset přidávat do configu (pokud se nepletu).
Takže to asi udělám tak jak to je nahoře s tím že budu muset vytvořit novou instanci třídy v každe metodě kterou udělám a nebo to budu postaru cpat všechno do presentru jako dřív.

$this->database->table('config')->fetch();
Michal Vyšinský
Člen | 608
+
0
-

Do presenteru to necpi. Komunikaci z databází má zajišťovat model. Pak by MVP[C] architektura ztrácela význam. Ještě se kdyžtak mrkni na toto

Editoval CherryBoss (6. 1. 2012 15:52)

kashpi
Člen | 48
+
0
-

Právě vím, že by to ztratilo význam, ale modelLoderu se chci vyhnout, protože s ním jsem zápasil už dřív a neúspěšně. Ale je pravda, že to bylo u nějaké starší verze Nette 2. V téhle nové už by to mohlo jít líp. Vyzkouším, popřemýšlím co a jak a pak kdyžtak napíšu :)
Je tady toho dost, co bych mohl použí, co jste mi poradili :) jen teď najít tu, která bude ta správná

kashpi
Člen | 48
+
0
-

Tak nakonec jsem využil metodu

$this->baseModel = new BaseModel($this->database);
$this->fooModel = new FooModel($this->database);

s tím, že to v BasePresenteru v metodě startup() tahám do globálních proměnných. Jak jen ten model. A pak už to jen v příslušných metodách používám

$this->template->foo = $this->baseModel->getConfig();

Je doufám, že to není moc prasácký, a že se nebudou zbytečně ty modely tahat (což asi budou) ale že to nebude nijak negativně ovliňovat výkon aplikace

To uvidím až to budu používat dál

Editoval kashpi (6. 1. 2012 17:37)

bojovyletoun
Člen | 667
+
0
-

pokud chceš mít ultra-cool-moderní řešení a využít DI v plné síle, podívej se na příklad – presenterfactory pro vytvoření presenteru volá setcontext, a vloží do něj autovwířené argumenty. Takže bude v configu stačit si jen nadefinovat názvy služeb, v přidat property služby do presenteru, přiřadit ji v setcontext, do konstruktoru Base a foomodel určit typ 1 argumentu na Connection( případně Selection)