Společná závislost pro více tříd

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

Ahoj.

Procházel jsem fórum, ale na svou otázku jsem odpověď bohužel nenašel.

Mám několik tříd (*DAO), které jsou potomkem třídy BaseDAO a volají uložené procedury (SP) v MSSQL databázi. Každá uložená procedura potřebuje pro své volání kromě jiných také parametr param1, který se nachází v entitě přihlášeného uživatele. Pokud uživatel není přihlášený, má param1 hodnotu null.

Všechno začalo tím, že jsem si z presenteru předával param1 do volání metody příslušné *DAO služby. Tato volání jsou ale na desítkách až stovkách míst, proto mě napadlo, jestli by si hodnotu param1 nemohla řešit příslušná *DAO služba automaticky. Přidal jsem tedy závislost na \Nette\Security\User, ze kterého si vytáhnu Identity, ve které mám param1 uložený. Nicméně volání různých SP jdou také do desítek a tedy by bylo nasnadě posunout práci s param1 „výše“, tedy že by BaseDAO byla závislá na \Nette\Security\User a její potomci (služby *DAO) by se jen obrátili na svého rodiče. A tady právě narážím, protože nevím, jak to vyřešit.

Dal jsem závislost na \Nette\Security\User do konstruktoru BaseDAO, ale pak to po mně vyžaduje uvedení této závislosti ve všech konstruktorech potomků, kde volám parent::__construct. V případě přidání další podobné závislosti nastane constructor hell.

Četl jsem články tady „Získávání závislostí“, i další různě po netu, ale bohužel jsem na to nepřišel.

Snad jsem problém vylíčil dost jasně. Kdyby ne, tak určitě informace doplním.

Poradíte prosím? Má něco takové řešení, nebo na to jdu úplně špatně?

CZechBoY
Člen | 3608
+
0
-

Do těch DAO objektů si všechno převáděj přes konstruktor – tzn. ve službě (vezme si user/userstorage z DIC), která ten dao objekt vytváří.

SamuelThorn
Člen | 29
+
0
-

CZechBoY: To by ale znamenalo, že v každém z nich proběhne test, jestli je v User daná hodnota a naplnění param1 buď touto hodnotou, nebo null, a že tedy bude na mnoha místech identický kód. Tomu jsem chtěl předejít. Těch DAO objektů je nyní 14 (a patrně jich bude více).

matopeto
Člen | 395
+
0
-

Ten test moze byt kludne v tom base

SamuelThorn
Člen | 29
+
0
-

matopeto: Mohl bys to prosím trochu rozvést?

Teď je to:

<?php
class BaseDAO {

}

class JednoDAO extends BaseDAO {

	public function __construct(User $user)
	{
		$this->userData = isset($user->identity->data) ? $user->identity->data : null;
	}

}

class DruheDAO extends BaseDAO {

	public function __construct(User $user)
	{
		$this->userData = isset($user->identity->data) ? $user->identity->data : null;
	}

}
?>

a před každým voláním SP je pak:

<?php
	$params['param1'] = isset($this->userData) ? $this->userData['param1'] : null;

	//proveď SP
	...
?>

A tohle by se mi opakovalo před každým voláním. Je to tedy spousta naprosto stejného, opakujícího se kódu.

Čím víc o tom přemýšlím, bylo by asi lepší rozšířit metodu execute objektu PDO, aby si tento parametr přidávala sama. Ale to už vůbec nevím, jak udělat.

matopeto
Člen | 395
+
0
-

nejako takto som to myslel:

abstract class BaseDAO {
  protected $userData;
	protected function __construct(User $user)
	{
		$this->userData = isset($user->identity->data) ? $user->identity->data : null;
	}

   protected getParam1() {
		return isset($this->userData) ? $this->userData['param1'] : null;
	}
}

final class JednoDAO extends BaseDAO {

	public function __construct(User $user) : base($user)
	{
	}

}

final class DruheDAO extends BaseDAO {

	public function __construct(User $user) : base($user)
	{
	}

}

a před každým voláním SP je pak:

	$params['param1'] = $this->getParam1();

	//proveď SP
	...

Editoval matopeto (14. 6. 2017 16:37)

SamuelThorn
Člen | 29
+
0
-

matopeto napsal(a):

nejako takto som to myslel:

Ha, takto to funguje, děkuju.

Jen se tedy ujistím, že pokud by přibyla nějaká podobná společná závislost, je potřeba ji vepsat do konstruktorů všech potomků, je to tak?

matopeto
Člen | 395
+
0
-

Jen se tedy ujistím, že pokud by přibyla nějaká podobná společná závislost, je potřeba ji vepsat do konstruktorů všech potomků, je to tak?

Ano

SamuelThorn
Člen | 29
+
0
-

matopeto napsal(a):

Ano

Ok. Děkuju. Snažil jsem se tomu vyhnout, ale zjevně to není možné. :)

Martk
Člen | 661
+
+1
-

Využil bych dekorátor od nette, více zde

SamuelThorn
Člen | 29
+
0
-

Martk napsal(a):

Využil bych dekorátor od nette, více zde

Díky za tip. Nakonec mě to, co poradil matopeto, přivedlo na nápad, jak to celé vyřešit lépe. A zdá se, zbude jen jedno BaseDAO a ostatní nebudou potřeba.

matopeto
Člen | 395
+
0
-

Decorator by som nepouzil, je to az prilis velka „magia“ bez neho aspon @SamuelThorn viac pochopi ako funguje OOP a DI.