Vylepšená podpora obálek nad Nette Database

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

Co bych si představoval?

Model, kde místo psaní

$user = $connection->table('user')->where('id', 25)->fetch();
$articles = $user->related('article');
foreach($acticles as $article) {
	$category = $article->ref('category');
	echo $category->title;
}

napíši

$user = $userDao->createSelection()->filterUser(25)->fetch();
$articles = $user->getArticles();
foreach($articles as $article) {
	$category = $article->getCategory();
	echo $category->getTitle();
}

a oba způsoby budou pokládat tytéž dotazy na databázi.

Jak jsem toho dosáhnul?

Upravil jsem Nette Database tak, aby byla schopna pracovat i s objekty, které nemusí od ničeho (např. Selection, ActiveRow) dědit. Toho jsem docílil použitím metody getActive(), která vrátí původní Nette Database objekt.

Mohu tak jednoduše vytvořit vlastní entity a pseudo-repozitáře (takové custom selection – viz. výše).

Naznačení:

class Entity extends \Nette\Object implements \Nette\Database\Table\IActiveRowAccessor
{

	/** @var ActiveRow $activeRow */
	private $activeRow;

	public function __construct(\Nette\Database\Table\ActiveRow $activeRow = null)
	{
		$this->activeRow = $activeRow;
	}

	public function getActive()
	{
		return $this->activeRow;
	}

}

class Selection extends \Nette\Object implements \Nette\Database\Table\ISelectionAccessor
{

	/** @var Selection */
	protected $selection;

	public function __construct(\Nette\Database\Table\Selection $selection)
	{
		$this->selection = $selection;
	}

	public function getActive()
	{
		return $this->selection;
	}

}

Implementace

Upravená verze Database v pull requestu: https://github.com/…tte/pull/946
Moji verzi obálky najdete k přezkoumání zde: https://github.com/…master/Model

Tento způsob práce mi vyhovuje a myslím si, že něco takového v Nette chybělo.

pozn.: Pokud by někdo nechtěl tento způsob používat, nemusí. Selection i ActiveRow taktéž implementují I…Accessor.

Editoval echo (1. 2. 2013 10:59)

enumag
Člen | 2118
+
0
-

Když jsem to viděl poprvé tak jsem to moc nechápal. Teď s tím RFC už ten smysl je vidět. :-) Jediné co mi zásadněji nesedí jsou ty názvy metod getActive, ještě navíc pro obě rozhraní stejné. Spíše bych zvolil getActiveRow a getSelection.

Pak se mi nelíbí v tomto RFC uvedený příklad s metodou $selection->filterUser(). Takto specifickou metodu do obecného SelectionAccessoru dávat opravdu nechci. Kromě toho ve tvé implementaci modelu by bylo lepší Selection přejmenovat na něco jiného, tenhle název je matoucí.

echo
Člen | 134
+
0
-

Názvy metod jsem neřešil, šlo o nápad, který jsem chtěl sdílet. Ve finální verzi bych je taky vyměnil.

Echo511\Model\Selection se původně jmenovalo Echo511\Model\Repository, ale pak jsem od toho upustil, protože to v klasickém pojetí Repository taktéž nedávalo smysl.

Já chci pracovat stylem:
Do presenteru injektovat DAO. Do template proměnné vložit callback, který mi po zavolání poskytne Echo511\Model\Selection (třeba už z vyfiltrovanými příspěvky na základě oprávnění). V šabloně ten callback zavolám, donastavím Selection (order, další filtrování, …) a dostanu entity, přes jejichž metody se mohu dostat k related a ref entitám. A z těch entity zase k dalším a dalším.

Mohu tak řetězit do nekonečna a v presenteru budu mít 1–2 řádky.

echo
Člen | 134
+
0
-

enumag napsal(a):
Pak se mi nelíbí v tomto RFC uvedený příklad s metodou $selection->filterUser(). Takto specifickou metodu do obecného SelectionAccessoru dávat opravdu nechci.

SelectionAccessor by právě obecný neměl být – obecná je \Nette\Database\Table\Selection. SelectionAccessor by měl implementovat metody operující nad NDBSelection a ty by měly být co nejvíce specifické.

enumag
Člen | 2118
+
0
-

echo napsal(a):

enumag napsal(a):
Pak se mi nelíbí v tomto RFC uvedený příklad s metodou $selection->filterUser(). Takto specifickou metodu do obecného SelectionAccessoru dávat opravdu nechci.

SelectionAccessor by právě obecný neměl být – obecná je \Nette\Database\Table\Selection. SelectionAccessor by měl implementovat metody operující nad NDBSelection a ty by měly být co nejvíce specifické.

To bych musel mít SelectionAccessor pro každou tabulku zvlášť.

echo
Člen | 134
+
0
-

enumag napsal(a):
To bych musel mít SelectionAccessor pro každou tabulku zvlášť.

Ano, ale několik tabulek může používat stejný SelectionAccessor, takže lze zavést určitou míru abstrakce. A pokud bude potřeba něco speciálního, stačí podědit svůj SelectionAccessor a přidat. Navíc lze do Accessoru injectnout libovolnou service, třeba DAO jiné tabulky kvůli datům closure hierarchii.

Nezbytná je pouze Entita a DAO pro každou tabulku.