KONEČNĚ! DataGrid data source pro Nette\Database query! (pro ublaboo/datagrid)

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

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 Kravčík
Člen | 1180
+
+1
-

What kind of sorcery is this?!

Hodně hustý! Skvělá práce.

CZechBoY
Člen | 3608
+
0
-

Podmínky děláš přes zanoření dotazu, nebo? Nechce se mi hledat github :-)

edit: tak neděláš, ale parsuješ sql. Co když budu mít subquery s where?

Editoval CZechBoY (17. 3. 2016 14:01)

Pavel Janda
Člen | 977
+
+1
-

@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
+
0
-

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
+
0
-

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 | 131
+
0
-

@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
+
0
-

@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
+
0
-

@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 | 131
+
+1
-

@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
+
0
-

@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.