KONEČNĚ! DataGrid data source pro Nette\Database query! (pro ublaboo/datagrid)
- Pavel Janda
- Člen | 977
Kdysi mi to scházelo a tuším, že to neustále chybí spoustě programátorů.
Při používání Nette\Database\Table
často nestačí NDBT
fluent – například v administraci je neustále potřeba JOINovat několik
tabulek a dělat s tím podobné kejkle. Lidé se proto uchylují ke
Context::query
a následně ::fetchAll()
. Toto pole
předají do datagridu. Ale řešení je to opravdu nehezké. Fetchovat při
každém requestu celý obsah databáze? Fujky..
Takže je tu data source, kterému předhodíte QUERY, parametry a on už si pak sql rozparsruje a upraví, aby vše fungovalo jako pořádný data source.
Dokumentace: zde.
Componette: zde.
1, Nainstaluji:
composer require ublaboo/datagrid-nette-database-data-source
2, Použiji (lehce odlišně než ostatní data sourcy – proto je balíček standalone):
public function createComponentNetteGrid($name)
{
/**
* @type Ublaboo\DataGrid\DataGrid
*/
$grid = new DataGrid($this, $name);
$query =
'SELECT p.*, GROUP_CONCAT(v.code SEPARATOR ", ") AS variants
FROM product p
LEFT JOIN product_variant p_v
ON p_v.product_id = p.id
WHERE p.deleted IS NULL
AND (product.status = ? OR product.status = ?)';
$params = [1, 2];
/**
* @var Ublaboo\NetteDatabaseDataSource\NetteDatabaseDataSource
*
* @param Nette\Database\Context
* @param $query
* @param $params|NULL
*/
$datasource = new NetteDatabaseDataSource($this->ndb, $query, $params);
$grid->setDataSource($datasource);
/**
* ...
*/
}
Editoval Pavel Janda (17. 3. 2016 13:39)
- Pavel Janda
- Člen | 977
@CZechBoY No problemo. Všechno by mělo být v cajku. Testoval jsem i poměrně rozsáhlé queries.
Používám balíček php-sql-parser
.
Pokud máš nějakou zanořenou podmínku, nebo cokoliv zanořeného, tak to zůstane zanořené a nešahá se na to. Pokud máš podmínku na konci dotazu, tak se na začátku obalí závorkami a taky se na to nešahá.
- revoke
- Člen | 36
Zkoušel jsem a našel jsem dvě chyby → issues
Jinak pokud to dobře chápu, mám
ublaboo/datagrid-nette-database-data-source
použít v případě,
kdy chci v gridu zobrazit data z další tabulky, jako např. název
kategorie, protože zápis $row->category->name
grid samotný
neumí. Používám Table\Selection
. Díky.
- Pavel Janda
- Člen | 977
S nette by default přichází dvě možnosti, jak se dotazovat databáze.
Nette\Database
a Nette\Database\Table
.
První zmíněná vypadá takto:
$this->connection->query('SELECT * FROM USER');
Nette\Database\Table
ti naopak dovolí používat fluent-zápis
dotazu:
$this->connection->table('user')->where('1');
Jsou to dvě odlišné věci a není radno je plést dohromady.
Nette\Database\Table
je fajn, ale jakmile chceš použít
nějaký zajímavější dotaz, máš bohužel smůlu, protože ti nedovolí
psát žádné složitější joiny a další věci (jako třeba dibi). Tak
člověk vetšinou sáhne k Nette\Database
. U ostatních gridů
musíš při použití Nette\Database
stáhnout rows do pole a to
předat datagridu. Tento datagrid umí použít tu celou query a nefetchuje
pokaždé všechny prvky dotazu do paměti.
To $row->category->name
by se ti ale mohlo povést přes
definici blocku položky, nebo custom rendererem. Ale zkus první ten
block
, lépe se v tom pak orientuje.
Díky za feedback, issue vyřeším o víkendu.
Editoval Pavel Janda (14. 9. 2016 14:51)
- flamengo
- Člen | 135
@PavelJanda Ahoj, jak prosím na tento data source namontuji vlastní podmínku filtru?
$grid->addFilterSelect('enabled', 'enabled', ['' => 'vše', 0 => 'ne', 1 => 'ano'])
->setCondition(function($fluent, $value){
if($value === 0){
$fluent->where('enabled IS NULL OR enabled = 0');
}
});
Proměnná fluent je string, takže mám smolíka.
Předtím jsem jako data source použil array (výsledek fetchAll()), kde
vlastně také nemohu použít podmínku.
V zásadě potřebuji nějaké řešení, kde si mohu nastavit vlastní
podmínku filtru.
Nette\Database\Table mi nevyhovuje, protože občas dělám hodně joinů
atd.
Předem díky za nakopnutí.
- Pavel Janda
- Člen | 977
@flamengo Musí se upravit ten query string a query parametry. Najdu někde příklad. Můžeš použít ten parser, který tento datagrid též využívá.
- Pavel Janda
- Člen | 977
@flamengo Viz https://github.com/…taSource.php#L156 : jako třetí argument anonymní funkce ti přijde pole parametrů, kam můžeš další přidávat.
- flamengo
- Člen | 135
@PavelJanda Díky moc. Chvíli mi to dalo, než jsem se chytil. Nakonec mi nejvíce pomohl tento tvůj příspěvek https://github.com/…rce/issues/3#…. Výsledek uvádím, kdyby to někdo potřeboval, nebo kdyby jsi mě chtěl ještě nějak usměrnit.
$grid->addFilterSelect('enabled', 'enabled', ['' => 'vše', 0 => 'ne', 1 => 'ano'])
->setCondition(function($query, $value, &$params){
if($value == 0){
$query .= ' AND (enabled IS NULL OR enabled = 0)';
}
elseif($value == 1){ // === nemůže být, je to string
$query .= ' AND enabled = ?';
$params[] = 1;
}
return $query;
});
- Pavel Janda
- Člen | 977
@flamengo Jop, takhle to jde taky. To jen kdyby to chtěl člověk dělat trošku sofistikovani, tak samozřejmě neodpadle použití nějakého SQL parseru apod.