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.