[2010–09–15] Třída Nette\Finder pro procházení adresářovou strukturou
- David Grudl
- Nette Core | 8252
Snad dva roky jsem měl u metody Nette\Tools::glob()
sloužící k rekurzivnímu procházení adresářů poznámku TODO: předělat
na RecursiveDirectoryIterator. Problémem byl v návrhu API. Existuje totiž
spousta variant toho, co a jak hledat, které soubory vracet, které adresáře
vracet a které procházet rekurzivně. Nebo naopak kterým se vyhýbat. Dále
jsou tu specifické situace, jako například RobotLoader, který při
procházení adresářovou strukturou načítá soubory netterobots.txt a teprve
za chodu zjišťuje dodatečná pravidla procházení, atd. Otázkou bylo, jak
to navrhnout univerzálně, srozumitelně a bez WTF faktorů.
Výsledkem snažení je třída Nette\Finder, jejíž API není dokonalé, ale je zatím asi to nejpoužitelnější, k jakému jsem se dopracoval. Jde o DSL, takže tu neplatí standardní konvence pro pojmenování metod.
Omezit hloubku procházení lze metodou limitDepth()
.
Kromě souborů lze hledat i adresáře
Finder::findDirectories('subdir*')
nebo obojí
Finder::find('file.txt')
. V tomto případě se maska vztahuje na
soubory, nikoliv adresáře.
Adresáře, kterým se chceme zcela vyhnout, uvedeme za klauzulí „from“:
Zajímavou možností je hledat více masek nebo dokonce procházet více adresářů v rámci jedné iterace:
přičemž parametry lze zadat i ve formě polí:
Dále je možné výsledky filtrovat. Například podle velikosti:
nebo data změny
nebo použít vlastní callback:
Využít lze i extension method:
Předpokládám, že API Finderu ještě dozná změn, takže čekám na vaše podněty.
Mimochodem, Finder je první třída v Nette plně využívající closures. Nicméně udělat jsem převodník closure pro PHP 5.2, takže funguje ve všech verzích.
- Patrik Votoček
- Člen | 2221
Jestli to takhle půjde se všema novinkama v 1.0. Tak letos dooprvady ruším vánoce.
Ale bych jenom nechválil. Poslední dobou celkem hodně pracuju s obrázky. Jde něják specifikovat filter který by mě vrátil obrázek za takovýchto podmínek:
Editoval vrtak-cz (15. 9. 2010 15:29)
- westrem
- Člen | 398
vrtak-cz napsal
Tak neviem ci spravne chapem, ale nie je to co ty potrebujes a pytas sa ci bude finder vediet trochu mimo jeho kompetenciu/povodny zamer? Tebe ide primarne o zistenie, aka verzia obrazka existuje a ak ziadna neexistuje vratit blank.
Finder je podla mna urceny na zistovanie obsahu adresara, ktory splnuje nejake validacne podmienky.
Avsak aby som netaral len do vetra.
- David pise, ze je mozne pouzit vlastny filter (vid priklady)
- Na tomto riadku ma David TODO s regexpami takze ja osobne (ak teda spravne chapem tvoj poziadavok) si viem predstavit ako to napisat ako regexp.
David Grudl napsal
Uzasna vec! Sam som o nieco podobne uz raz pokusal ale padlo to na tom ako
predavat rozne filtracne podmienky. Prvotny nastrel API je podla mna hodne
dobry, chcelo by to mozno ale aj funkcie na zistovanie poctu najdenych suborov.
Tiez mi trochu nie je jasne nasledne rekurzivne iterovanie alebo iterovanie ked
pouzijem viac $dirs
.
Dalsia featuresa by mohla byt moznost pridania radenia vystupu (podla datumu
vytvorenia, zmeny, velkosti, abecedne) – mmtalne je ak som spravne pozeral
zdrojak dostupne len CHILD_FIRST
.
Trosku WTF faktor mi pride excludes
. Excluduje sa na kazdej
urovni alebo len na prvej? Viem si predstavit vyuzitie obojeho.
- westrem
- Člen | 398
vrtak-cz napsal(a):
Jestli to takhle půjde se všema novinkama v 1.0. Tak letos dooprvady ruším vánoce.
Ale bych jenom nechválil. Poslední dobou celkem hodně pracuju s obrázky. Jde něják specifikovat filter který by mě vrátil obrázek za takovýchto podmínek:
A nechcem vrtat ale toto ide podla mna napisat aj krajsie a prehladnejsie:
Ako v podstate je to jedno, len tolko vnorenych if-ov mi pride hodne neprehladnych.
- David Grudl
- Nette Core | 8252
Tohle skutečně s nástrojem pro iterování nad adresářovou strukturou nesouvisí…
- David Grudl
- Nette Core | 8252
Tak samozřejmě můžeš udělat nějaké
foreach(Finder::findFiles('foo.gif', 'foo.png', 'foo.jpg')->in(DATA_DIR . "/images")
,
ale je to kanón na vrabce.
- hason
- Člen | 23
Projekty jako Doctrine2 a Symfony2 navzájem využívají své kódy a nevymýšlejí je znovu. Škoda, že se tento trend ještě nedostal k Nette – http://fabien.potencier.org/…d-your-files
Editoval hason (16. 9. 2010 23:23)
- iguana007
- Člen | 970
Trošku jsem si s Finderem pohrál a nejsem si jist, zda-li něco dělám špatně nebo je to bug, ale pořád mi vrací to co nechci. Jde mi o to, aby mi Finder vrátil všechny soubory dané složky, které jsou starší 20ti minut a začínají názvem „cropped_“.
Tady je můj testovací kód:
Který mi vrací toto:
http://ukaz.at/vn
tj. všechny soubory, sice správně filtrované podle názvu, ale ne podle
data.
Když změním < na > v metodě date tak dostavám totožný dump.
- David Grudl
- Nette Core | 8252
hason napsal(a):
Projekty jako Doctrine2 a Symfony2 navzájem využívají své kódy a nevymýšlejí je znovu.
Jinými slovy proč programovat Nette, když je tu Symfony, že? Vůbec nerozumím, co ti vadí. Díval jsem se na ten kód v Symfony, musí být alespoň 10× pomalejší než Finder v Nette, omezení hloubky procházení funguje tak, že projde kompletní strukturu a vše, co je pod limitem, jen zahazuje. Víc to studovat nechci, ale nevyhovuje to standardu kvality Nette. Takže mám přebírat nekvalitní kód?
- David Grudl
- Nette Core | 8252
iguana007 napsal(a):
Trošku jsem si s Finderem pohrál a nejsem si jist, zda-li něco dělám špatně nebo je to bug
Ono je to takto:
takže tu podmínku „date“ uveď hned za findFiles.
- Patrik Votoček
- Člen | 2221
hason napsal(a):
Projekty jako Doctrine2 a Symfony2 navzájem využívají své kódy a nevymýšlejí je znovu.
Já jsem si třeba tu část Doctrine2 která využívá Symfony2 přepsal tak aby využívala Nette. Takže Symfony2 v Nette projektu vůbec nemám (i přes to že mám Doctrine 2)… :-)
Editoval vrtak-cz (17. 9. 2010 9:19)
- hason
- Člen | 23
David Grudl napsal:
Jinými slovy proč programovat Nette, když je tu Symfony, že? Vůbec nerozumím, co ti vadí.
Nic takového jsem neřekl. Já jsem jen poukázal na to, že už existuje stejná knihovna pro procházení adresářové struktury šířená pod licencí MIT.
Díval jsem se na ten kód v Symfony, musí být alespoň 10× pomalejší než Finder v Nette
Nemohu soudit. Nikde jsem neviděl srovnání. Prozatím to je jen tvrzení o univerzální Nette konstantě ;)
omezení hloubky procházení funguje tak, že projde kompletní strukturu a vše, co je pod limitem, jen zahazuje.
Nějak nemohu najít rozdíl mezi implementací v nette a Symfony2:
Nette: $iterator->setMaxDepth($this->maxDepth);
Symfony2:
$iterator->setMaxDepth(INF === $maxDepth ? -1 : $maxDepth);
Víc to studovat nechci, ale nevyhovuje to standardu kvality Nette. Takže mám přebírat nekvalitní kód?
Tvrdit na základě minimálního studia kódu, že je nekvalitní je odvážné tvrzení. O přebírání kódu jsem také nic nepsal. Napsal jsem, že Doctrine2 a Symfony2 využívají navzájem své kódy, ale nepřebírají (chápu jako zkopírování kódu). Proč by se to také dělalo? Vždyť tyto knihovny mohou být nainstalovány přes PEAR a vesele využívány. Stejně jako PHPUnit apod.
No a na závěr ještě ukázka, jaké výhody přináší využívání již existující kódu (Symfony2 Finder a Zend Framework Service):
Editoval hason (17. 9. 2010 9:18)
- Šaman
- Člen | 2667
hason napsal(a):
Nechci dělat Davidovi advokáta (zvlášť když ho nepotřebuje), ale
- srovnáváš syntax a nevidíš rozdíl v implementaci? Samozřejmě, rozdíl v implementaci je na úrovni zdrojových kódů. A jestli po letmém seznámení se se zdrojáky David zjistil, že Symfony vyhledává neefektivně, tak mu můžeš buď věřit, nebo to nastudovat pořádně a pak polemizovat.
- jestliže existují volně použitelné knihovny na stejné činnosti které podporuje Nette, tak super, můžeš je vesele používat. Ale vůbec nevidím důvod kritizovat, že se v Nette vynalézá kolo – ono každé to kolo je trošku jiné a to Netťácké by mělo do zbytku frameworku pasovat jak prdýlka na nočník. A jedna z výhod Nette je, že všechny kódy vychází z jedné hlavy. (Např. na Zendu se mi nelíbilo, že to byl takový slepenec všech všemožných knihoven z různých zdrojů. Chyběla tam jednotná štábní kultura už na úrovni syntaxe.)
- David Grudl
- Nette Core | 8252
S tou hloubkou máte pravdu, omlouvám se (platí to ale o ignorování adresářů, což mimochodem ani nefunguje na Windows). Rychlost jsem neměřil, jde o to, že, naskládání mnoha iterátorů na sebe zpomaluje. A to propojení s S3 předpokládám bude na Nette fungovat úplně stejně, nebo je důvod, proč by nefungovalo? Ale o hodnocení kódu nejde, že, nechám toho.
Trend využívání existujícího kódu do Nette dorazil, ať už v plánu připojit knihovnu Doctrine 2, použití knihovny pod MIT, nebo sdílení kódu s dibi. Pojmu „využívat ale nepřebírat“ nerozumím.
- pesu
- Člen | 7
Zdravím, měl bych podnět … callback modifikátory. Příklad: najdu všechny .jpg obrázky v určitém adresáři a chci je všechny zobrazit na webu. Jenže cesta na disku <> url, takže by se mi hodilo předat Finderu modifikátor, který by to pěkně upravil a Finder by vracel hotové url obrázků ;)
- Honza Marek
- Člen | 1664
Ono by možná stačilo přidat funkci toArray()
, aby se na to
daly použít array_map a array_filter funkce.
- Yrwein
- Člen | 45
Honza Marek: PHP alternativa k metodě: iterator_to_array
Editoval Yrwein (8. 11. 2010 23:28)
- Filip Procházka
- Moderator | 4668
pesu: co takhle?
hrach: tvoje řešení je samozřejmě hezčí, to je bez debaty :)
Editoval HosipLan (9. 11. 2010 11:21)
- David Grudl
- Nette Core | 8252
hrach napsal(a):
Feature request – doprogramovat filtrovani pomoci regexpu.
Maličkost, jen vymysli syntax, rozlišení skutečných regulárů od
ořezaných. (v nich lze #^\d{4}_\d{2}_\d{2}.log$#'
také zadat,
sice ukecaněji [0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9].log
, ale
pro mnohé uživatele srozumitelněji)
- pesu
- Člen | 7
HosipLan napsal(a):
pesu: co takhle?
hrach: tvoje řešení je samozřejmě hezčí, to je bez debaty :)
HosipLan: Ano, takhle se to jistě řešit dá, ale nelíbí se mi to. Drbat se pravou rukou za levým uchem je sice umění, ale rozhodně to není efektivní a už vůbec to není nic, co bych chtěl dělat každý den. Když můžu Finderu předat filtr, proč bych mu nemohl předat i modifier, v principu je to to samé, nebo se mýlím? Co takhle pro Finder definovat interface IFinderFilter a IFinderModifier? Vůbec bychom pak nebyli závislí na tom, co Finder umí nebo neumí, prostě by dostal instance filtr/modifier třídy a ty by provedly svoji práci.
- David Grudl
- Nette Core | 8252
hrach napsal(a):
Víš, v čem je zádrhel, ale stejně sem napíšeš: „Feature request – doprogramovat filtrovani pomoci regexpu.“ Vnímáš to taky jako buzeraci?
pesu napsal(a):
nepotřebuješ modifikátor, stačí
Nemá smysl API Finderu zaplácávat něčím, co má triviální řešení.
- pesu
- Člen | 7
David Grudl napsal(a):
hrach napsal(a):
Víš, v čem je zádrhel, ale stejně sem napíšeš: „Feature request – doprogramovat filtrovani pomoci regexpu.“ Vnímáš to taky jako buzeraci?
pesu napsal(a):
nepotřebuješ modifikátor, stačí
Nemá smysl API Finderu zaplácávat něčím, co má triviální řešení.
No to ano, to jistě triviální řešení má. Akorát je tam o jednu iteraci navíc a pak když to chci dostat do šablony, tak to musím někam ukládat, předávat atd. Asi nějak takto:
nebo
Modifier pak můžu mít v celém projektu jeden a používat ho můžu vícekrát, může dokonce mít na starosti víc věcí. Jinak mi není moc jasné, proč když jsou ve Finderu filtry by tam nemohly být modifiery … filtrování v extra iteraci je přece úplně stejně triviální a přesto jim to výsostné právo býti ve Finderu upřeno není.
- hrach
- Člen | 1840
David Grudl napsal(a):
Víš, v čem je zádrhel, ale stejně sem napíšeš: „Feature request – doprogramovat filtrovani pomoci regexpu.“ Vnímáš to taky jako buzeraci?
lol :) přemýšlím, kdo se blbě vyspal. nene, přečetl jsem si ve zdrojáku tvé todo, a toto mělo být takové to „+1“, jako že by se to hodilo. nic víc, nic míň. nevím co je v té větě buzeračního.
- hrach
- Člen | 1840
apropo, vzbudil můj příspěvek aspoň diskuzi nad hledáním správného řešení. Pokud se shodneme, nemám problém jej naprogramovat, ale vzhledem k tomu, že spásnou ideu nemám, bylo by zbytečné teď něco implemenovat, skončí to jako aktuální 4 pull requesty – sic dobré, ale né přímo třeba zapadající do koncepce.
jaký je názor na ten findFilesRegexp()
?
- David Grudl
- Nette Core | 8252
pesu napsal(a):
No to ano, to jistě triviální řešení má. Akorát je tam o jednu iteraci navíc a pak když to chci dostat do šablony, tak to musím někam ukládat, předávat atd. Asi nějak takto:
Modifikuj přímo v šabloně {$file|image}
hrach napsal(a):
jaký je názor na ten
findFilesRegexp()
?
Tři nové funkce findRegExp, findFilesRegexp a findDirectoriesRegExp by asi fakt skončily jako nepoužitý pull request.
- Milo
- Nette Core | 1283
David Grudl napsal(a):
hrach napsal(a):
Feature request – doprogramovat filtrovani pomoci regexpu.
Maličkost, jen vymysli syntax, rozlišení skutečných regulárů od ořezaných. (v nich lze
#^\d{4}_\d{2}_\d{2}.log$#'
také zadat, sice ukecaněji[0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9].log
, ale pro mnohé uživatele srozumitelněji)
A co třeba takto?
- Filip Procházka
- Moderator | 4668
to vypadá hrozně :)
Co by možná nebylo od věci tak udělat třídu RegExp
jako je
String
, php obdobu k javascriptové verzi.
- dalo by se to rozlišit globálně ve FW
- vyčlenily by se metody ze String
- hezčí api
- možnost udělat zkratku jako mají callbacky
Když teď nad tím tak přemýšlím,
nechce se mi mazat co už jsem napsal, ale uvědomil jsem si jak hrozně to
vypadá (především ta zkratka)
Takže pokud něco takového tak spíš asi jenom takový jednoduchý kontejner, prostě typ regulární výraz pomocí třídy