ublaboo/datagrid: mocný, rychlý, rozšiřitelný, hezký, anglicky dokumentovaný datagrid
- matous.radek
- Člen | 2
Ahoj lidi,
tak řešení zdá se býti naprosto jednoduché. Pomohlo mi až bádání
přímo v kódu.
Tedy místo:
$grid->setItemsDetail($detail = TRUE, $primary_where_column = $grid->getPrimaryKey());
dát:
$grid->setItemsDetail($detail = TRUE, $primary_where_column = "table.column");
Editoval matous.radek (5. 11. 2016 11:19)
- Pavel Janda
- Člen | 977
@matous.radek Ahoj, nestihl jsem ti přes den odpovědět, ale již správné řešení znáš, takže thumbs up! Pokud to není v docu, napravím to.
- Pavel Janda
- Člen | 977
@JardaH Ale původní hodnota, která by ti tam přišla, by byla stejně původní a ne vytažená z databáze… Tak si ji vytáhni. :)
- ondrusu
- Člen | 118
Ahojte, měl bych dotaz jak se dá v tomhle datagridu řadit podle
cizího klíče
?
Mám výpis článků a každý článek má svoji kategorii a já to chci
seřadit podle kategorie.
Samozřejmě nejlépe podle názvu kategorie nebo podle idčka.
No ale nevím jak to mám udělat. V entitě Article mám kategorii
definovanou takhle
/**
* Sloupec Kategorie.
* @ORM\ManyToOne(targetEntity="category", inversedBy="ac_category", fetch="EAGER")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*
*/
protected $category;
A když definuji pouze
$grid->addColumnText('category', 'Kategorie')
->setSortable()
Tak to píše chybu že category_id
neexistuje v dotazu
SELECT DISTINCT id_0
FROM (
SELECT ... sloupce
FROM category
) dctrn_result
ORDER BY c0_.category_id ASC
LIMIT 10 OFFSET 0
Ten dotaz je samozřejmě špatně, ale nechápu proč to rve až do toho co
je za tím druhým FROM.
Můžete mi teda poradit jak to mám udělat správně?
Zkusil jsem metodu setSortableCallback
(kterou jsem našel zde na
nette foru), ale fakt asi dělám něco špatně. Protože nastal ten samý
problém.
Děkuji.
- Pavel Janda
- Člen | 977
@ondrusu Ahoj.
Mohl bys sem dát i to, jak skládáš dotaz přes QueryBuilder? Pravděpodobně tam bude chybět join.
- ondrusu
- Člen | 118
Tak to viš, že tam chybí join, ten join už by měl být součástí
entity né? Nebo ten datagrid si to nevezme z toho?
takhle vypadá ta metoda.
$qb = $this->em->createQueryBuilder();
$qb->select('a')
->from(Article::class, 'a');
return $qb;
A když tam přidám ten join tak např.
LEFT JOIN category c ON c.id = a.category_id
už bude blbě protože v entitě už to je jako array_collection
je to tak že?? Tak to si asi budu muset vytvořit ručně sql že??
Nebo se pletu a lze to jinak?? Díky.
- Pavel Janda
- Člen | 977
@ondrusu Nemáš to správně. Ten join píšeš na propetry entity, ne na sloupce v tabulce. Předpokládám, že žádné category_id v entitě nemáš.
Zkus něco jako LEFT JOIN category c ON c = a.categories
.
- ondrusu
- Člen | 118
Pavel Janda napsal(a):
@ondrusu Nemáš to správně. Ten join píšeš na propetry entity, ne na sloupce v tabulce. Předpokládám, že žádné category_id v entitě nemáš.
Zkus něco jako
LEFT JOIN category c ON c = a.categories
.
díky, vyzkouším to a dám vědět (ale až večer)
Ale rozhodně to vypadá logicky.. díky
EDITOVÁNO 8.11. 21:25
funguje, díky
respekt++;
Editoval ondrusu (8. 11. 2016 21:24)
- Pavel Janda
- Člen | 977
@pitr82 V master větvi je to již fixnuto. Příští verze (zanedlouho vydáváme) bude fix obsahovat. :)
- Pavel Janda
- Člen | 977
@pitr82 Pardon, přehlédnul jsem to
$grid->setRememberState(FALSE);
. Bohužel v takovou chvíli
nemá datagrid šanci zjistit, zda uživatel již sortoval nebo ne.
Pravděpodobně v takové kombinaci začnu vyhazovat exception, pokud mě
nenapadne nějaký spásný nápad.
Nebo máš nějaký?
- Pavel Janda
- Člen | 977
@pitr82 Ano.
Pokud nastavíš default sort == DESC
, tak další krok je
NULL
, pokud klikneš na sort, tak se v datagridu sort projeví
jako NULL
a to může znamenat buď kliknutí na
DESC
– další krok, nebo nic, žádné řazení. DataGrid si
tedy řekne, že nic ještě nebylo řazeno a tak vrátí DESC
,
protože je to defaultní sort. Proto tam figuruje ta session – do ní se
uloží, že již uživatel použil řazení a pokud ano, nebere se v potaz
default sort.
Dává to smysl?
Editoval Pavel Janda (10. 11. 2016 11:49)
- flamengo
- Člen | 135
Ahoj, snažím se přinutit datagrid, aby mi srovnal záznamy takto:
"...ORDER BY priority ASC, name ASC"
Tedy aby se zobrazilo dle nastavené priority a pokud je priorita stejná, tak abecedně dle názvu.
Očekával bych, že vyřeším takto:
$grid->setDefaultSort(['priority' => 'ASC', 'name' => 'ASC']);
Ale bohužel se mi to nedaří. Výsledek je řazen pouze dle
name
. Verzi mám v4.4.9.
Další dotaz: lze nějak nastavit i sloupci pro prioritu tento způsob řazení? Něco jako:
$tr = $grid->addColumnNumber('priority', 'Pořadí')
->setSortable('priority ASC, name ASC')
Předem díky moc za odpověď či nakopnutí.
- Pavel Janda
- Člen | 977
@flamengo Když počkáš ještě pár dní, tak vyjde verze 5, která bude obsahovat multisort. Zatím v dev-master.
- Pavel Janda
- Člen | 977
@iguana007 Jakou používáš DB? A jaké používáš collation
v tom kterém sloupci? Například utf8_general_ci
bude
Case-Insensitive, zato utf8_bin
bude Case-Sensitive.
- ondrusu
- Člen | 118
Ahojte, měl bych dotaz. Definuji pomocí datagridu date sloupec a chci na
něj filter.
Soupec mám definovaný takto:
$grid->addColumnDateTime('created','Vytvořeno')
->setSortable()
->setFilterDate();
a v latte to mám takhle (je to kvůli formátu, ale třeba se to dá udělat jinak
{define col-created}
{$item->getCreated()|date:'%d.%m.%Y %H:%M:%S'}
{/define}
A když kliknu do toho políčka tak by se teoreticky měl zobrazit takový
kalendář pod tím labelem a to se nezobrazí, ani žádná chyba v conzili
není.
Nevíte co mám nastaveno špatně??
Díky.
- abc
- Člen | 92
@iguana007 normálně převedeš ten string na lowercase v DB dotazu
i parametr
Nevím, jak se to dělá v tomhle gridu, ale v Grido cca takto (určitě tam
jsou chyby, ale návod to snad dodá):
->setWhere(function($value, $qb){
return $qb->addAndWhere("LOWER(column) = :param", ["param" => Strings::lower($value),]);
})
- iguana007
- Člen | 970
abc napsal(a):
@iguana007 normálně převedeš ten string na lowercase v DB dotazu i parametr
Nevím, jak se to dělá v tomhle gridu, ale v Grido cca takto (určitě tam jsou chyby, ale návod to snad dodá):->setWhere(function($value, $qb){ return $qb->addAndWhere("LOWER(column) = :param", ["param" => Strings::lower($value),]); })
tomu rozumim, vim jak to udelat pri klasickem dotazu, ale nevim, jak toto zakomponovat do datagridu – k cemu pripojim to volani ->setWhere atd., k datasource? Takto mám definici datagridu nyní:
$grid = new DataGrid($this, $name);
$userRepository = $this->getEm()->getRepository(User::CLASSNAME);
$dataSource = $userRepository->createQueryBuilder('er');
$dataSource->leftJoin('er.supplier', 'supplier');
$grid->setDataSource($dataSource);
$grid->addColumnText('username', 'Username')
->setSortable('username')
->setFilterText(['er.username']);
$grid->addColumnLink('fname', 'First Name', 'detail')
->setSortable('fname')
->setFilterText(['er.fname']);
$grid->addColumnLink('sname', 'Last Name', 'detail')
->setSortable('sname')
->setFilterText(['er.sname']);
$grid->addColumnLink('supplier', 'Supplier', 'Suppliers:detail', 'supplier.name', ['id' => 'supplier.id'])
->setSortable()
->setOpenInNewTab(true);
$grid->addFilterText('supplier', 'Supplier', 'supplier.name');
- abc
- Člen | 92
@iguana007 v dokumentaci (ten grid fakt neznám a nikdy jsem ho nepoužil) píšou toto, tak asi tam…
$grid->addFilterText('custom', 'Custom search:', 'name')
->setCondition(function($fluent, $value) {
/**
* The data source is here DibiFluent
* No matter what data source you are using,
* prepared data source will be passed as the first parameter of your callback function
*/
$fluent->where('id > ?', strlen($value));
});
- ondrusu
- Člen | 118
Ahojte, připomínám se se svým dotazem (viz výše) a také mám dvě připomínky
Teď jsem aktualizoval všechny komponenty pomocí composeru a datagrid mi hlásí:
Trait 'Nette\SmartObject' not found search►
vendor\ublaboo\datagrid\src\DataModel.php:29
když to zakomentuju tak další chyba:
Call to undefined method Ublaboo\DataGrid\DataModel::onBeforeFilter() search►
vendor\ublaboo\datagrid\src\DataModel.php:132
když to zakomentuju, další chyba:
Call to undefined method Ublaboo\DataGrid\DataModel::onAfterFilter() search►
vendor\ublaboo\datagrid\src\DataModel.php:136
Call to undefined method Ublaboo\DataGrid\DataModel::onAfterPaginated() search►
vendor\ublaboo\datagrid\src\DataModel.php:150
Používám Nette 2.4.
- tam není na tlačítku per_page_submit ve value nic.
pak se to zdá být ok.
Co to jsou za chyby? Je to něco, co bude oprava na dlouho?
- Pavel Janda
- Člen | 977
@ondrusu
1, Nezakázal jsi si nějak nette v composeru? Můžeš sem hodit
composer.lock?
2, Upraveno zatím v masteru!
- ondrusu
- Člen | 118
Možné to je.
Příznám se že jsem sám docela překvapen, hlavně celý projekt mám v gitu a teď jsem zjistil, že v .gitignore je složka /vendor (v .gitignore v root projektu), takže nemám ani zálohu v repositáři, abych to vrátil zpět.
- Pavel Janda
- Člen | 977
@ondrusu Pokud pro to nemáš nějaký superdůvod, je vhodné
přidávat do .gitignore adresář vendor
. Na cílové mašině pak
jen zavoláš composer install
.
Nemůže to být tím? Nehází ti tu exception tracy na jiném kompu, než tvém?
- Pavel Janda
- Člen | 977
@ondrusu Aha,ty používáš nette 2.3. My fault, změním použití traity Nette\SmartObject na extend třídy Nette\Object.
- Pavel Janda
- Člen | 977
@ondrusu Ne. ublaboo/datagrid musí fungovat i s nette 2.3. Zkus master, pushnul jsem tam úpravu, mělo by to jet.
- ondrusu
- Člen | 118
To je zajímavý. Dneska jsem na jiným PC, nainstaloval jsem si composer
(protože jsem ho tu neměl) přes flashku jsem si přetáhl ten adresář. Teď
jsem dal zase composer update a vypsalo mi to tohle .
Ale včera to tohle nepsalo. Tak nevim co dělám špatně.
Teď to tedy funguje. Díky moc i za dost rychlou opravu.
- iguana007
- Člen | 970
Pro referenci zde prikladam finalni/funkcni reseni case insensitive filtrovani s vyuzitim Doctrine + PostgreSQL:
$grid = new DataGrid($this, $name);
$userRepository = $this->getEm()->getRepository(User::CLASSNAME);
$dataSource = $userRepository->createQueryBuilder('er');
$dataSource->leftJoin('er.supplier', 'supplier');
$grid->setDataSource($dataSource);
$grid->addColumnText('username', 'Username')
->setSortable('username');
$grid->addColumnLink('fname', 'First Name', 'detail')
->setSortable('fname');
$grid->addColumnLink('sname', 'Last Name', 'detail')
->setSortable('sname');
$grid->addColumnLink('supplier', 'Supplier', 'Suppliers:detail', 'supplier.name', ['id' => 'supplier.id'])
->setSortable()
->setOpenInNewTab(true);
$grid->addFilterText('username', 'First Name:', 'er.username')
->setCondition(function ($dataSource, $value) {
$dataSource->andWhere("LOWER(er.username) LIKE :param")
->setParameter('param', '%' . Strings::lower($value) . '%');
});
$grid->addFilterText('fname', 'First Name:', 'er.fname')
->setCondition(function ($dataSource, $value) {
$dataSource->andWhere("LOWER(er.fname) LIKE :param")
->setParameter('param', '%' . Strings::lower($value) . '%');
});
$grid->addFilterText('sname', 'Last Name:', 'er.sname')
->setCondition(function ($dataSource, $value) {
$dataSource->andWhere("LOWER(er.sname) LIKE :param")
->setParameter('param', '%' . Strings::lower($value) . '%');
});
$grid->addFilterText('supplier', 'Supplier:', 'supplier.name')
->setCondition(function ($dataSource, $value) {
$dataSource->andWhere("LOWER(supplier.name) LIKE :param")
->setParameter('param', '%' . Strings::lower($value) . '%');
});
- ondrusu
- Člen | 118
Zdravím, mám ještě dotaz.
Mám v presenteru renderShow s id (url adresa /show/id)
public function renderShow($id) {
$this->template->id = $id;
...
}
A v createComponent pro datagrid mám toto
public function createComponentList($name) {
$grid = new DataGrid($this, $name);
$grid->setDataSource(
$this->facade->getList($this->template->id)
);
Základní výpis funguje, ale jak dám seřadit podle jména nebo něco
vyhledat tak už v template neexistuje proměnná id
a
samozřejmě skončí to chybou.
Jak bych si měl správně předat ID z view (latte) do componenty?
díky moc.
- Pavel Janda
- Člen | 977
@ondrusu Zkusil bych nastavit id presenteru jako persistentní parametr. Používáš ajaxový datagrid?
- Pavel Janda
- Člen | 977
@ondrusu Stačí takto:
/** @persistent */
public $id = 0;
public function componentList() {
$grid->setDataSource(
$this->facade->getList($this->id)
);
}
Persistentní parametry se pak ale umí chovat i trochu záludně, tak je s tím pak třeba počítat (když půjdeš na jinou stránku, to ID ti zůstane automaticky v linku).
- ondrusu
- Člen | 118
Pavel Janda napsal(a):
@ondrusu Stačí takto:
/** @persistent */ public $id = 0; public function componentList() { $grid->setDataSource( $this->facade->getList($this->id) ); }
Persistentní parametry se pak ale umí chovat i trochu záludně, tak je s tím pak třeba počítat (když půjdeš na jinou stránku, to ID ti zůstane automaticky v linku).
díky, vyzkouším.
- BuGeR
- Člen | 45
Ahoj,
při používání datagridu s doctrine query builderem jsem narazil na
problém. Potřebuji vytvořit statistickou tabulku, ve které zobrazím
přehled uživatelů s doplňujícími informaceni, které jsou i ve
vedlejších tabulkách.
Nenašel jsem žádný způsob, jak např. natáhnout do qb něco jako
sum(t.order_amount) AS soucet_objednavek
do gridu. Proto se
snažím vytvořit abstraktní entitu, kterou použiju jako přepravku pro data.
Takže potom ten qb vypadá takto:
$qb->select('NEW AbstractUser(u.id, u.email, SUM(t.order_amount))');
Všechno funguje v pořádku. Vrátí se mi entita, která obsahuje
potřebné informace, které jsou najoinované z externích tabulek. Bohužel
si s tím ale DataGrid neumí poradit. Vyhazuje to exception:
Not all identifier properties can be found in the ResultSetMapping: id
Nevíte někdo co s tím? Nebo neexistuje nějaký lepší a jednodušší
způsob, jak natáhnout data z externích tabulek do gridu?
Díky.
- Pavel Janda
- Člen | 977
@BuGeR Ahoj,
bohužel nepoužívám tolik doctrine, ale zeptám se kolegy.
Co ale určitě bude fungovat, bude lazy načítání entit při výpisu dat.
Používám to třeba u gridu objednávek. Pokud otevřu detail objednávky,
donačtou se (lazy)
položky objednávky..
/**
* @ORM\OneToMany(targetEntity="OrderItem", mappedBy="order", fetch="EXTRA_LAZY")
*/
protected $lasyOrderItems;
Pak v detailu položky (v šabloně) normálně nad položkami iteruji. Určitě bude existovat podobný způsob zapsání nějaké agregace. Ale to musí poradit někdo jiný.
Pokud bys ale toužil čistě po agregaci, tohle vhodný způsob nebude. Říkám, ještě se zeptám, pokud tu někdo nenapoví dříve.
- iNviNho
- Člen | 352
Chalani nenarazili ste niekto na problém sortovania podľa joinnutej entity?
Mám v gride
<?php
$grid->addColumnText("invoiceNumericalScheme.companyName", "Názov firmy")
->setSortable();
?>
Po stlačení tlačídla sort mi vyhodí v konzoli error a následne ked refreshnem stránku tak dostávam chybu a problém je v DQLku
<?php
SELECT i
FROM InvoiceModule\Entities\Invoice i
ORDER BY invoiceNumericalScheme.companyName ASC
?>
chýba tam left join/inner join …
Nie je to bug? Ak sortujem podľa joinnutej entity tak by tam mal byť check či naozaj je v QueryBuildery táto entita joinnutá a ak nie je, čo je moj prípad, tak by tam mal ešte byť inner join
Editoval iNviNho (1. 12. 2016 18:50)
- Pavel Janda
- Člen | 977
Nová verze – v5.0.0
- Přibyla možnost řadit data podle více sloupců :)
- Přibyl nový typ sloupce – MultiAction
- Přibyla možnost skrývat animovaně outer filter – collapsible filters
- Přibyla možnost zobrazovat item detail pouze pro některé řádky
- Přibyla možnost zobrazit text sloupců, které nejsou editováni při inline editaci
- Přibyla možnost zresetovat filtr jednoho sloupce přes malou ikonku v záhlaví cloupce
- Pár dalších drobností && bugfixů
kompletní changelog: https://github.com/…s/tag/v5.0.0
Díky všem za reporty a PR!
Editoval Pavel Janda (4. 12. 2016 13:47)
- iNviNho
- Člen | 352
@PavelJanda na stránke http://ublaboo.org/datagrid/column?… dostávam Server error 500 ked som zoradil podľa name, potom podľa ID a už bol error.