Nette Documentation Preview

syntax
Finder: wyszukiwanie plików
***************************

.[perex]
Potrzebujesz znaleźć pliki pasujące do określonej maski? Finder Ci w tym pomoże. To wszechstronne i szybkie narzędzie do przeglądania struktury katalogów.


Instalacja:

```shell
composer require nette/utils
```

Przykłady zakładają, że utworzony został następujący alias klasy:

```php
use Nette\Utils\Finder;
```


Użycie
------

Najpierw zobaczmy, jak za pomocą [api:Nette\Utils\Finder] wypisać nazwy plików z rozszerzeniami `.txt` i `.md` w bieżącym katalogu:

```php
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
	echo $file;
}
```

Domyślnym katalogiem wyszukiwania jest katalog bieżący, ale możesz go zmienić metodami [in() albo from() |#Gdzie szukać?]. Zmienna `$file` to instancja klasy [#FileInfo], a `$name` to string ze ścieżką do pliku.

Ścieżka zwracana jest tak, jak ją zapisałeś, z zachowaniem separatorów platformy; w Windows wynik może więc mieszać `/` i `\`. Jeśli potrzebujesz jednolitej postaci, wywołaj `FileSystem::unixSlashes()`.


Czego szukać?
-------------

Oprócz metody `findFiles()` istnieje `findDirectories()`, która szuka wyłącznie katalogów, oraz `find()`, która szuka jednego i drugiego. Metody te są statyczne, można je więc wywoływać bez tworzenia instancji. Argument z maską jest opcjonalny; jeśli go pominiesz, pasuje wszystko.

```php
foreach (Finder::find() as $file) {
	echo $file; // teraz wypisywane są wszystkie pliki i katalogi
}
```

Za pomocą metod `files()` i `directories()` możesz określić kolejne rzeczy do wyszukania. Metody można wywoływać wielokrotnie, a jako argument można podać także tablicę masek:

```php
Finder::findDirectories('vendor') // wszystkie katalogi
	->files(['*.php', '*.phpt']); // plus wszystkie pliki PHP
```

Alternatywą dla metod statycznych jest utworzenie instancji przez `new Finder` (tak utworzony obiekt początkowo niczego nie szuka) i określenie, czego szukać, metodami `files()` i `directories()`:

```php
(new Finder)
	->directories()      // wszystkie katalogi
	->files('*.php');    // plus wszystkie pliki PHP
```

W masce możesz używać [symboli wieloznacznych |#Symbole wieloznaczne], takich jak `*`, `**`, `?` i `[...]`. Możesz podać nawet katalogi, na przykład `src/*.php` znajdzie wszystkie pliki PHP w katalogu `src`. Dowiązania symboliczne również traktowane są jak katalogi albo pliki.


Gdzie szukać?
-------------

Domyślnym katalogiem wyszukiwania jest katalog bieżący. Zmieniasz go metodami `in()` i `from()`:

```php
Finder::findFiles('*.php')
	->in(['src', 'tests']) // szuka bezpośrednio w src/ i tests/
	->from('vendor');      // szuka też w podkatalogach vendor/
```

Te dwie metody różnią się głębokością: `in()` szuka tylko w podanym katalogu, natomiast `from()` schodzi również do jego podkatalogów (rekurencyjnie). Aby przeszukać bieżący katalog rekurencyjnie, użyj `from('.')`.

O rekurencji nie decyduje jednak samo `from()` - napędza ją też symbol `**` w masce, więc `findFiles('**/*.php')->in('src')` również szuka rekurencyjnie. Inaczej mówiąc, `from('src')` to jedynie skrót dla `in('src')` z maską rekurencyjną. Zobacz [#Symbole wieloznaczne].

Metody te można wywoływać wielokrotnie albo przekazać kilka ścieżek jako tablicę; pliki będą wtedy wyszukiwane we wszystkich podanych katalogach. Jeśli któryś z katalogów nie istnieje, zgłaszany jest `Nette\InvalidStateException`.

Ścieżki względne odnoszą się do bieżącego katalogu, ale można używać też ścieżek bezwzględnych:

```php
Finder::findFiles('*.php')
	->in('/var/www/html');
```

W ścieżce możesz używać symboli `*`, `**` i `?`, ale **nie** `[...]`, które traktowane jest tam dosłownie. Zapobiega to niezamierzonemu zachowaniu, gdy na przykład szukasz `in(__DIR__)`, a ścieżka akurat zawiera znaki `[]`. Na przykład `src/*/*.php` szuka wszystkich plików PHP w katalogach drugiego poziomu pod `src`.

Przy rekurencyjnym wyszukiwaniu plików i katalogów (w głąb) najpierw zwracany jest katalog nadrzędny, a po nim zawarte w nim pliki. Kolejność tę można odwrócić metodą `childFirst()`.


Symbole wieloznaczne
--------------------

Maska może zawierać kilka znaków specjalnych:

- `*` - dowolna liczba znaków z wyjątkiem separatora `/` (pozostaje na jednym poziomie katalogów)
- `**` - dowolna liczba znaków, **łącznie z** `/` (obejmuje poziomy katalogów, zobacz niżej)
- `?` - dokładnie jeden znak z wyjątkiem `/`
- `[a-z]` - jeden znak z zakresu albo zbioru w nawiasach
- `[!a-z]` - jeden znak *spoza* nawiasów

Rzecz kluczowa i łatwa do przeoczenia: `**` pasuje do **zera lub więcej** poziomów katalogów. *Nie* oznacza "co najmniej jeden podkatalog". Dlatego `src/**/*.php` pasuje zarówno do pliku leżącego bezpośrednio w `src`, jak i do zakopanego kilka poziomów głębiej. Rozważ takie drzewo:

/--pre
src/
├── app.php
├── Model/
│   ├── User.php
│   └── Repository/
│       └── UserRepository.php
└── Control/
    └── SignForm.php
\--

Poniższa tabela pokazuje, do czego pasują poszczególne maski, zarówno dla plików, jak i katalogów:

|-------------------------------------------------------------------------------
| Maska | Pasuje do
|-------------------------------------------------------------------------------
| `src/*.php` | tylko `src/app.php` (bezpośrednio w `src`)
| `src/**/*.php` | `src/app.php`, `src/Model/User.php`, `src/Model/Repository/UserRepository.php` (**wszystkie poziomy, w tym bezpośrednio w `src`**)
| `src/*` | bezpośrednie dzieci `src`: `app.php`, `Model`, `Control`
| `src/**` | wszystko pod `src`, pliki i katalogi (skrót dla `src/**/*`)
| `src/*/` | bezpośrednie *podkatalogi* `src`: `Model`, `Control`
| `src/**/` | *wszystkie* podkatalogi na dowolnej głębokości: `Model`, `Model/Repository`, `Control`

Warto zapamiętać dwa skróty:

- `**`, po którym nie następuje bezpośrednio `/`, zachowuje się jak `**/` plus `*`. Zatem `src/**` to skrót dla `src/**/*`, a `**.php` dla `**/*.php`.
- Ukośnik na końcu ogranicza maskę wyłącznie do katalogów. Zatem `find('log/')` zwraca katalogi o nazwie `log`, ale nigdy pliku o tej nazwie. (`findFiles()` odrzuca końcowy ukośnik, bo szukanie pliku "katalogu" nie ma sensu.)

Kolejne przykłady użycia:

- `img/?.png` - pliki o jednoliterowej nazwie, jak `0.png`, `1.png`, `x.png`
- `logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log` - pliki logów w formacie `YYYY-MM-DD`
- `docs/**/*.md` - wszystkie pliki z rozszerzeniem `.md` w `docs` i wszystkich jego podkatalogach


Wykluczanie
-----------

Metody `exclude()` używa się do usunięcia plików i katalogów z wyniku. Argumentem jest maska, do której element **nie** może pasować. Tutaj szukamy plików `*.txt` z wyjątkiem tych, które zawierają w nazwie literę `X`:

```php
Finder::findFiles('*.txt')
	->exclude('*X*');
```

Maska wykluczająca używa dokładnie tej samej gramatyki co maski wyszukiwania - tych samych [symboli wieloznacznych |#Symbole wieloznaczne], kotwiczenia `./` i skrótu `**`. O zakresie wykluczenia decyduje jej końcowa część:

|-------------------------------------------------------------------------------
| Maska | Wyklucza
|-------------------------------------------------------------------------------
| `temp` | dowolny plik albo katalog o nazwie `temp`, na dowolnej głębokości
| `temp/` | tylko katalog `temp` (i jego zawartość); plik o nazwie `temp` zostaje zachowany
| `temp/*` | zawartość `temp`, ale zachowuje sam katalog `temp`
| `temp/**` | to samo co `temp/*`

Do wykluczonego katalogu Finder w ogóle nie wchodzi podczas przechodzenia, więc wykluczanie całych poddrzew również przyspiesza wyszukiwanie. W ten sposób pomijasz konkretne podkatalogi:

```php
Finder::findFiles('*.php')
	->from($dir)
	->exclude('temp', '.git');
```


Filtrowanie
-----------

Finder oferuje kilka metod do filtrowania wyników (czyli ich zawężania). Można je łączyć i wywoływać wielokrotnie.

Za pomocą `size()` filtrujemy według rozmiaru pliku. W ten sposób znajdziemy pliki o rozmiarze z zakresu od 100 do 200 bajtów:

```php
Finder::findFiles('*.php')
	->size('>=', 100)
	->size('<=', 200);
```

Metoda `date()` filtruje według daty ostatniej modyfikacji pliku. Wartościami mogą być daty bezwzględne albo względne wobec bieżącej daty i czasu. Na przykład to znajdzie pliki zmodyfikowane w ciągu ostatnich dwóch tygodni:

```php
Finder::findFiles('*.php')
	->date('>', '-2 weeks')
	->from($dir)
```

Obie metody rozumieją operatory `>`, `>=`, `<`, `<=`, `=`, `!=`, `<>`.

Finder pozwala też filtrować wyniki własnymi callbackami. Callback otrzymuje jako parametr obiekt `Nette\Utils\FileInfo` i musi zwrócić `true`, aby plik trafił do wyniku.

Przykład: wyszukiwanie plików PHP zawierających string `'Nette'` (bez rozróżniania wielkości liter):

```php
Finder::findFiles('*.php')
	->filter(fn($file) => str_contains(strtolower($file->read()), 'nette'));
```


Filtrowanie według głębokości
-----------------------------

Przy wyszukiwaniu rekurencyjnym możesz ustawić maksymalną głębokość przechodzenia metodą `limitDepth()`. Ustawienie `limitDepth(1)` przechodzi tylko przez pierwszy poziom podkatalogów, `limitDepth(0)` całkowicie wyłącza schodzenie w głąb, a wartość -1 usuwa ograniczenie głębokości.

Finder pozwala używać własnych callbacków do decydowania, do których katalogów wchodzić podczas przechodzenia. Callback otrzymuje obiekt `Nette\Utils\FileInfo` reprezentujący katalog i musi zwrócić `true`, aby do niego wejść:

```php
Finder::findFiles('*.php')
	->descentFilter(fn($file) => $file->getBasename() !== 'temp');
```


Katalogi nie do odczytu
-----------------------

Domyślnie Finder pomija katalogi, których nie potrafi odczytać (na przykład z powodu niewystarczających uprawnień). Jeśli wolisz, aby w takich przypadkach zgłaszał wyjątek, wywołaj `ignoreUnreadableDirs(false)`.

```php
Finder::findFiles('*.php')
	->from($dir)
	->ignoreUnreadableDirs(false);
```


Sortowanie
----------

Finder oferuje również kilka metod do sortowania wyników.

Metoda `sortByName()` sortuje wyniki według nazwy pliku. Sortowanie jest naturalne, czyli poprawnie radzi sobie z liczbami w nazwach i zwraca np. `foo1.txt` przed `foo10.txt`.

Finder pozwala też sortować własnym callbackiem. Otrzymuje on jako parametry dwa obiekty `Nette\Utils\FileInfo` i musi zwrócić wynik porównania operatorem `<=>` (czyli `-1`, `0` albo `1`). Tak na przykład posortujemy pliki według rozmiaru:

```php
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
```


Kilka różnych wyszukiwań
------------------------

Jeśli potrzebujesz znaleźć kilka zestawów plików w różnych miejscach albo spełniających różne kryteria, użyj metody `append()`. Zwraca ona nowy obiekt `Finder`, dzięki czemu możesz łańcuchowo wywoływać metody dołączonego wyszukiwania:


```php
($finder = new Finder) // pierwszy Finder zapisz do zmiennej $finder!
	->files('*.php')   // szuka plików *.php w src/
	->from('src')
	->append()
	->files('*.md')    // w docs/ szuka plików *.md
	->from('docs')
	->append()
	->files('*.json'); // w bieżącym katalogu szuka plików *.json
```

Alternatywnie metody `append()` można użyć do dodania konkretnego pliku (albo tablicy plików). W tym przypadku zwraca ten sam obiekt `Finder`:

```php
$finder = Finder::findFiles('*.txt')
	->append(__FILE__);
```


FileInfo
--------

[api:Nette\Utils\FileInfo] to klasa reprezentująca plik albo katalog znaleziony w wyniku wyszukiwania. Rozszerza klasę [php:SplFileInfo] i udostępnia informacje takie jak rozmiar pliku, data ostatniej modyfikacji, nazwa, ścieżka itd.

Ponadto udostępnia metody zwracające ścieżkę względną, co przydaje się przy przechodzeniu rekurencyjnym:

```php
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
	$absoluteFilePath = $file->getRealPath();
	$relativeFilePath = $file->getRelativePathname();
}
```

Dostępne są też metody do odczytu i zapisu zawartości pliku:

```php
foreach ($finder as $file) {
    $contents = $file->read();
    // ...
    $file->write($contents);
}
```


Zwracanie wyników jako tablicy
------------------------------

Jak widać w przykładach, Finder implementuje interfejs `IteratorAggregate`, więc do przejścia po wynikach możesz użyć `foreach`. Zaprojektowano go tak, aby wyniki wczytywały się dopiero podczas iteracji, co oznacza, że przy dużej liczbie plików nie czeka z góry na odczytanie ich wszystkich.

Wyniki możesz też pobrać jako tablicę obiektów `Nette\Utils\FileInfo` metodą `collect()`. Tablica jest indeksowana liczbowo, a nie asocjacyjnie.

```php
$array = Finder::findFiles('*.php')->collect();
```

Finder: wyszukiwanie plików

Potrzebujesz znaleźć pliki pasujące do określonej maski? Finder Ci w tym pomoże. To wszechstronne i szybkie narzędzie do przeglądania struktury katalogów.

Instalacja:

composer require nette/utils

Przykłady zakładają, że utworzony został następujący alias klasy:

use Nette\Utils\Finder;

Użycie

Najpierw zobaczmy, jak za pomocą Nette\Utils\Finder wypisać nazwy plików z rozszerzeniami .txt i .md w bieżącym katalogu:

foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
	echo $file;
}

Domyślnym katalogiem wyszukiwania jest katalog bieżący, ale możesz go zmienić metodami in() albo from(). Zmienna $file to instancja klasy FileInfo, a $name to string ze ścieżką do pliku.

Ścieżka zwracana jest tak, jak ją zapisałeś, z zachowaniem separatorów platformy; w Windows wynik może więc mieszać / i \. Jeśli potrzebujesz jednolitej postaci, wywołaj FileSystem::unixSlashes().

Czego szukać?

Oprócz metody findFiles() istnieje findDirectories(), która szuka wyłącznie katalogów, oraz find(), która szuka jednego i drugiego. Metody te są statyczne, można je więc wywoływać bez tworzenia instancji. Argument z maską jest opcjonalny; jeśli go pominiesz, pasuje wszystko.

foreach (Finder::find() as $file) {
	echo $file; // teraz wypisywane są wszystkie pliki i katalogi
}

Za pomocą metod files() i directories() możesz określić kolejne rzeczy do wyszukania. Metody można wywoływać wielokrotnie, a jako argument można podać także tablicę masek:

Finder::findDirectories('vendor') // wszystkie katalogi
	->files(['*.php', '*.phpt']); // plus wszystkie pliki PHP

Alternatywą dla metod statycznych jest utworzenie instancji przez new Finder (tak utworzony obiekt początkowo niczego nie szuka) i określenie, czego szukać, metodami files() i directories():

(new Finder)
	->directories()      // wszystkie katalogi
	->files('*.php');    // plus wszystkie pliki PHP

W masce możesz używać symboli wieloznacznych, takich jak *, **, ? i [...]. Możesz podać nawet katalogi, na przykład src/*.php znajdzie wszystkie pliki PHP w katalogu src. Dowiązania symboliczne również traktowane są jak katalogi albo pliki.

Gdzie szukać?

Domyślnym katalogiem wyszukiwania jest katalog bieżący. Zmieniasz go metodami in() i from():

Finder::findFiles('*.php')
	->in(['src', 'tests']) // szuka bezpośrednio w src/ i tests/
	->from('vendor');      // szuka też w podkatalogach vendor/

Te dwie metody różnią się głębokością: in() szuka tylko w podanym katalogu, natomiast from() schodzi również do jego podkatalogów (rekurencyjnie). Aby przeszukać bieżący katalog rekurencyjnie, użyj from('.').

O rekurencji nie decyduje jednak samo from() – napędza ją też symbol ** w masce, więc findFiles('**/*.php')->in('src') również szuka rekurencyjnie. Inaczej mówiąc, from('src') to jedynie skrót dla in('src') z maską rekurencyjną. Zobacz Symbole wieloznaczne.

Metody te można wywoływać wielokrotnie albo przekazać kilka ścieżek jako tablicę; pliki będą wtedy wyszukiwane we wszystkich podanych katalogach. Jeśli któryś z katalogów nie istnieje, zgłaszany jest Nette\InvalidStateException.

Ścieżki względne odnoszą się do bieżącego katalogu, ale można używać też ścieżek bezwzględnych:

Finder::findFiles('*.php')
	->in('/var/www/html');

W ścieżce możesz używać symboli *, ** i ?, ale nie [...], które traktowane jest tam dosłownie. Zapobiega to niezamierzonemu zachowaniu, gdy na przykład szukasz in(__DIR__), a ścieżka akurat zawiera znaki []. Na przykład src/*/*.php szuka wszystkich plików PHP w katalogach drugiego poziomu pod src.

Przy rekurencyjnym wyszukiwaniu plików i katalogów (w głąb) najpierw zwracany jest katalog nadrzędny, a po nim zawarte w nim pliki. Kolejność tę można odwrócić metodą childFirst().

Symbole wieloznaczne

Maska może zawierać kilka znaków specjalnych:

  • * – dowolna liczba znaków z wyjątkiem separatora / (pozostaje na jednym poziomie katalogów)
  • ** – dowolna liczba znaków, łącznie z / (obejmuje poziomy katalogów, zobacz niżej)
  • ? – dokładnie jeden znak z wyjątkiem /
  • [a-z] – jeden znak z zakresu albo zbioru w nawiasach
  • [!a-z] – jeden znak spoza nawiasów

Rzecz kluczowa i łatwa do przeoczenia: ** pasuje do zera lub więcej poziomów katalogów. Nie oznacza „co najmniej jeden podkatalog“. Dlatego src/**/*.php pasuje zarówno do pliku leżącego bezpośrednio w src, jak i do zakopanego kilka poziomów głębiej. Rozważ takie drzewo:

src/
├── app.php
├── Model/
│   ├── User.php
│   └── Repository/
│       └── UserRepository.php
└── Control/
    └── SignForm.php

Poniższa tabela pokazuje, do czego pasują poszczególne maski, zarówno dla plików, jak i katalogów:

Maska Pasuje do
src/*.php tylko src/app.php (bezpośrednio w src)
src/**/*.php src/app.php, src/Model/User.php, src/Model/Repository/UserRepository.php (wszystkie poziomy, w tym bezpośrednio w src)
src/* bezpośrednie dzieci src: app.php, ModelControl
src/** wszystko pod src, pliki i katalogi (skrót dla src/**/*)
src/*/ bezpośrednie podkatalogi src: ModelControl
src/**/ wszystkie podkatalogi na dowolnej głębokości: Model, Model/RepositoryControl

Warto zapamiętać dwa skróty:

  • **, po którym nie następuje bezpośrednio /, zachowuje się jak **/ plus *. Zatem src/** to skrót dla src/**/*, a **.php dla **/*.php.
  • Ukośnik na końcu ogranicza maskę wyłącznie do katalogów. Zatem find('log/') zwraca katalogi o nazwie log, ale nigdy pliku o tej nazwie. (findFiles() odrzuca końcowy ukośnik, bo szukanie pliku „katalogu“ nie ma sensu.)

Kolejne przykłady użycia:

  • img/?.png – pliki o jednoliterowej nazwie, jak 0.png, 1.pngx.png
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – pliki logów w formacie YYYY-MM-DD
  • docs/**/*.md – wszystkie pliki z rozszerzeniem .md w docs i wszystkich jego podkatalogach

Wykluczanie

Metody exclude() używa się do usunięcia plików i katalogów z wyniku. Argumentem jest maska, do której element nie może pasować. Tutaj szukamy plików *.txt z wyjątkiem tych, które zawierają w nazwie literę X:

Finder::findFiles('*.txt')
	->exclude('*X*');

Maska wykluczająca używa dokładnie tej samej gramatyki co maski wyszukiwania – tych samych symboli wieloznacznych, kotwiczenia ./ i skrótu **. O zakresie wykluczenia decyduje jej końcowa część:

Maska Wyklucza
temp dowolny plik albo katalog o nazwie temp, na dowolnej głębokości
temp/ tylko katalog temp (i jego zawartość); plik o nazwie temp zostaje zachowany
temp/* zawartość temp, ale zachowuje sam katalog temp
temp/** to samo co temp/*

Do wykluczonego katalogu Finder w ogóle nie wchodzi podczas przechodzenia, więc wykluczanie całych poddrzew również przyspiesza wyszukiwanie. W ten sposób pomijasz konkretne podkatalogi:

Finder::findFiles('*.php')
	->from($dir)
	->exclude('temp', '.git');

Filtrowanie

Finder oferuje kilka metod do filtrowania wyników (czyli ich zawężania). Można je łączyć i wywoływać wielokrotnie.

Za pomocą size() filtrujemy według rozmiaru pliku. W ten sposób znajdziemy pliki o rozmiarze z zakresu od 100 do 200 bajtów:

Finder::findFiles('*.php')
	->size('>=', 100)
	->size('<=', 200);

Metoda date() filtruje według daty ostatniej modyfikacji pliku. Wartościami mogą być daty bezwzględne albo względne wobec bieżącej daty i czasu. Na przykład to znajdzie pliki zmodyfikowane w ciągu ostatnich dwóch tygodni:

Finder::findFiles('*.php')
	->date('>', '-2 weeks')
	->from($dir)

Obie metody rozumieją operatory >, >=, <, <=, =, !=, <>.

Finder pozwala też filtrować wyniki własnymi callbackami. Callback otrzymuje jako parametr obiekt Nette\Utils\FileInfo i musi zwrócić true, aby plik trafił do wyniku.

Przykład: wyszukiwanie plików PHP zawierających string 'Nette' (bez rozróżniania wielkości liter):

Finder::findFiles('*.php')
	->filter(fn($file) => str_contains(strtolower($file->read()), 'nette'));

Filtrowanie według głębokości

Przy wyszukiwaniu rekurencyjnym możesz ustawić maksymalną głębokość przechodzenia metodą limitDepth(). Ustawienie limitDepth(1) przechodzi tylko przez pierwszy poziom podkatalogów, limitDepth(0) całkowicie wyłącza schodzenie w głąb, a wartość –1 usuwa ograniczenie głębokości.

Finder pozwala używać własnych callbacków do decydowania, do których katalogów wchodzić podczas przechodzenia. Callback otrzymuje obiekt Nette\Utils\FileInfo reprezentujący katalog i musi zwrócić true, aby do niego wejść:

Finder::findFiles('*.php')
	->descentFilter(fn($file) => $file->getBasename() !== 'temp');

Katalogi nie do odczytu

Domyślnie Finder pomija katalogi, których nie potrafi odczytać (na przykład z powodu niewystarczających uprawnień). Jeśli wolisz, aby w takich przypadkach zgłaszał wyjątek, wywołaj ignoreUnreadableDirs(false).

Finder::findFiles('*.php')
	->from($dir)
	->ignoreUnreadableDirs(false);

Sortowanie

Finder oferuje również kilka metod do sortowania wyników.

Metoda sortByName() sortuje wyniki według nazwy pliku. Sortowanie jest naturalne, czyli poprawnie radzi sobie z liczbami w nazwach i zwraca np. foo1.txt przed foo10.txt.

Finder pozwala też sortować własnym callbackiem. Otrzymuje on jako parametry dwa obiekty Nette\Utils\FileInfo i musi zwrócić wynik porównania operatorem <=> (czyli -1, 0 albo 1). Tak na przykład posortujemy pliki według rozmiaru:

$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());

Kilka różnych wyszukiwań

Jeśli potrzebujesz znaleźć kilka zestawów plików w różnych miejscach albo spełniających różne kryteria, użyj metody append(). Zwraca ona nowy obiekt Finder, dzięki czemu możesz łańcuchowo wywoływać metody dołączonego wyszukiwania:

($finder = new Finder) // pierwszy Finder zapisz do zmiennej $finder!
	->files('*.php')   // szuka plików *.php w src/
	->from('src')
	->append()
	->files('*.md')    // w docs/ szuka plików *.md
	->from('docs')
	->append()
	->files('*.json'); // w bieżącym katalogu szuka plików *.json

Alternatywnie metody append() można użyć do dodania konkretnego pliku (albo tablicy plików). W tym przypadku zwraca ten sam obiekt Finder:

$finder = Finder::findFiles('*.txt')
	->append(__FILE__);

FileInfo

Nette\Utils\FileInfo to klasa reprezentująca plik albo katalog znaleziony w wyniku wyszukiwania. Rozszerza klasę SplFileInfo i udostępnia informacje takie jak rozmiar pliku, data ostatniej modyfikacji, nazwa, ścieżka itd.

Ponadto udostępnia metody zwracające ścieżkę względną, co przydaje się przy przechodzeniu rekurencyjnym:

foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
	$absoluteFilePath = $file->getRealPath();
	$relativeFilePath = $file->getRelativePathname();
}

Dostępne są też metody do odczytu i zapisu zawartości pliku:

foreach ($finder as $file) {
    $contents = $file->read();
    // ...
    $file->write($contents);
}

Zwracanie wyników jako tablicy

Jak widać w przykładach, Finder implementuje interfejs IteratorAggregate, więc do przejścia po wynikach możesz użyć foreach. Zaprojektowano go tak, aby wyniki wczytywały się dopiero podczas iteracji, co oznacza, że przy dużej liczbie plików nie czeka z góry na odczytanie ich wszystkich.

Wyniki możesz też pobrać jako tablicę obiektów Nette\Utils\FileInfo metodą collect(). Tablica jest indeksowana liczbowo, a nie asocjacyjnie.

$array = Finder::findFiles('*.php')->collect();