Vylepšená podpora obálek nad Nette Database
- echo
- Člen | 134
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
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
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
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
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
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.