Filtry#
Skladatelné podmínky nad QueryBuilderem. app/Core/Utils/Filters/.
Je to jediný způsob, jak se v tomhle systému dotazuje. Presenter ani komponenta SQL nepíší — poskládají pole filtrů a předají ho manageru.
$items = $this->newsManager->findAll(
filters: [
new EqualFilter('active', true),
new LikeFilter('name', $hledany),
],
orderBy: ['published' => false], // false = DESC!
limit: 20,
)->execute();
Katalog#
V systému je 33 filtrů (ls app/Core/Utils/Filters/*.php). Nejpoužívanější:
| Filtr | Co dělá |
|---|---|
EqualFilter, NotEqualFilter |
rovnost / nerovnost |
InFilter, NotInFilter |
hodnota (ne)patří do seznamu |
LikeFilter, NotLikeFilter |
částečná shoda |
IsNullFilter, IsNotNullFilter |
prázdná / neprázdná hodnota |
GreaterThanFilter, GreaterOrEqualFilter, LessThanFilter, LessOrEqualFilter |
porovnání |
BetweenFilter, NotBetweenFilter, RangeFilter, RangeInclusiveFilter |
rozsahy |
DateEqualFilter, DateBeforeFilter, DateAfterFilter, DateBetweenFilter, DateRangeFilter |
datumové varianty |
FulltextFilter |
fulltext nad databází |
SearchIdFilter |
id vrácená z Elasticsearch |
DistanceFilter |
geografická vzdálenost |
ParameterRelFilter, ParameterRelLikeFilter, ParameterRelRangeFilter |
dynamické parametry inzerce a katalogu firem |
Skládání a závorky#
| Filtr | Význam |
|---|---|
AndFilter |
všechny podmínky |
OrFilter |
kterákoli podmínka |
GroupFilter |
závorka |
Bez GroupFilter se OR rozlije do celého dotazu
A AND (B OR C) se bez závorky změní na A AND B OR C — a to je v SQL něco
jiného, protože AND váže silněji. Dotaz nespadne, jen vrátí víc řádků, než měl.
Tečkové cesty přes vazby#
Potřebné joiny doplní JoinHelper sám a drží si aliasy per QueryBuilder — což je
podstatné, protože jeden dotaz má vedle sebe QueryBuildery víc: hlavní, samostatný pro
computeTotalCount() a klony, které si dělá GroupFilter pro každý podfiltr.
Tečková cesta přes KOLEKCI znásobí řádky
Filtr přes ToMany vazbu udělá join, který jeden záznam vrátí vícekrát. U výpisu s počtem to zkreslí čísla — stránkování pak ukazuje „137 položek“ tam, kde jich je padesát. Nespadne to a na první stránce to vypadá správně.
Pořadí filtrů se přerovnává#
FilterSortHelper::sortFilters() před sestavením dotazu přeuspořádá filtry podle
pořadí sloupců v entitě a filtr nad víc poli rozbalí na jednotlivé. Volá se
z GetAllTrait i z TotalCountTrait, aby oba dotazy vypadaly stejně.
Není to řazení výsledků
Řazení výsledků řeší orderBy a OrderByHelper — jiná věc, jiný soubor.
Řazení výsledků#
Směr je BOOL, ne řetězec
OrderByHelper dělá doslova $dir = $direction ? 'ASC' : 'DESC'. Takže
['id' => 'DESC'] seřadí VZESTUPNĚ, protože neprázdný řetězec je truthy.
Nikde to nespadne a výpis vypadá seřazeně — jen obráceně, takže „posledních deset“
ukáže deset nejstarších.
(V DataGridu je to jinak: setDefaultOrder() bere řetězec
a převede si ho sám.)
Postup: píšu vlastní filtr#
- Nejdřív projdi katalog. Většina potřeb je pokrytá; nový filtr má smysl u domény, ne u další varianty porovnání.
- Implementuj
App\Core\Utils\Filters\Interfaces\Filter—toSql(),getBindings(),apply()a settery aliasů. - Vyjdi z nejbližšího existujícího filtru ve stejné složce; tvar je ustálený.
- Když filtr nesmí do cache, označ ho
NonCacheableFilter. - Ověř ho i v součtu. Filtr se aplikuje na hlavní dotaz i na dotaz počítající celkový počet — když se ty dva rozejdou, stránkování ukazuje nesmysly.
NonCacheableFilter je marker pro dotazy, které se nesmí cachovat
Používá ho SearchIdFilter: seznam id z Elasticsearch by v klíči cache vyrobil
unikátní záznam pro každý hledaný výraz (a zaplnil Redis), a hlavně by vznikla
druhá pravda o seznamu vedle ES indexu. Podrobně Cache.
Filtry v administraci a na frontu#
| Kde | Jak vzniknou |
|---|---|
| DataGrid | z filtrů ve sloupcích + addDefaultFilter() |
| front výpisy | z parametrů adresy přes filtrovací komponentu |
| fasety e-shopu | vlastní pravidla — počty se zužují vším kromě vlastní fasety |
Rozsahový filtr na frontu potřebuje round-trip přes adresu
Bez něj se hodnota mezi požadavky ztratí a filtr tiše nefiltruje — vrátí všechno a tváří se, že je nastavený.
Kam sáhnout#
| Chci | Kde |
|---|---|
| katalog filtrů | app/Core/Utils/Filters/ |
| rozhraní filtru | app/Core/Utils/Filters/Interfaces/Filter.php |
| marker „necachovat“ | …/Interfaces/NonCacheableFilter.php |
| doplňování joinů | app/Core/Utils/Helpers/Filters/JoinHelper.php |
| přerovnání filtrů | app/Core/Utils/Helpers/Filters/FilterSortHelper.php |
| směr řazení | app/Core/Utils/Helpers/Sqls/OrderByHelper.php |
Navazující kapitoly: Práce s tabulkami · Cache · Elasticsearch · Volání API