Nette Documentation Preview

syntax
Finder: iskanje datotek
***********************

.[perex]
Potrebujete najti datoteke, ki ustrezajo določeni maski? Finder vam bo pri tem pomagal. Je vsestransko in hitro orodje za brskanje po strukturi imenikov.


Namestitev:

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

Primeri predpostavljajo ustvarjen vzdevek:

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


Uporaba
-------

Najprej si poglejmo, kako lahko z uporabo [api:Nette\Utils\Finder] izpišete imena datotek s končnicami `.txt` in `.md` v trenutnem imeniku:

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

Privzeti imenik za iskanje je trenutni imenik, vendar ga lahko spremenite z metodama [in() ali from() |#Kje iskati]. Spremenljivka `$file` je instanca razreda [#FileInfo] z veliko uporabnimi metodami. V ključu `$name` je pot do datoteke kot niz.


Kaj iskati?
-----------

Poleg metode `findFiles()` obstaja tudi `findDirectories()`, ki išče samo imenike, in `find()`, ki išče oboje. Te metode so statične, zato jih je mogoče klicati brez ustvarjanja instance. Parameter z masko je neobvezen, če ga ne navedete, se poišče vse.

```php
foreach (Finder::find() as $file) {
	echo $file; // zdaj se izpišejo vse datoteke in imeniki
}
```

Z metodama `files()` in `directories()` lahko dodate, kaj še želite iskati. Metode je mogoče klicati večkrat in kot parameter lahko navedete tudi polje mask:

```php
Finder::findDirectories('vendor') // vsi imeniki
	->files(['*.php', '*.phpt']); // plus vse PHP datoteke
```

Alternativa statičnim metodam je ustvarjanje instance z `new Finder` (tako ustvarjen svež objekt ne išče ničesar) in navedbo, kaj iskati, z uporabo `files()` in `directories()`:

```php
(new Finder)
	->directories()      // vsi imeniki
	->files('*.php');    // plus vse PHP datoteke
```

V maski lahko uporabljate [nadomestne znake |#Nadomestni znaki] `*`, `**`, `?` in `[...]`. Lahko celo določite imenike, na primer `src/*.php` poišče vse PHP datoteke v imeniku `src`.

Simbolične povezave se prav tako štejejo za imenike ali datoteke.


Kje iskati?
-----------

Privzeti imenik za iskanje je trenutni imenik. Spremenite ga z metodama `in()` in `from()`. Kot je razvidno iz imen metod, `in()` išče samo v danem imeniku, medtem ko `from()` išče tudi v njegovih podimenikih (rekurzivno). Če želite iskati rekurzivno v trenutnem imeniku, lahko uporabite `from('.')`.

Te metode je mogoče klicati večkrat ali jim posredovati več poti kot polje, datoteke se bodo nato iskale v vseh imenikih. Če kateri od imenikov ne obstaja, se sproži izjema `Nette\UnexpectedValueException`.

```php
Finder::findFiles('*.php')
	->in(['src', 'tests']) // išče neposredno v src/ in tests/
	->from('vendor');      // išče tudi v podimenikih vendor/
```

Relativne poti so relativne glede na trenutni imenik. Seveda lahko navedete tudi absolutne poti:

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

V poti je mogoče uporabiti [nadomestne znake |#Nadomestni znaki] `*`, `**`, `?`. Tako lahko na primer s potjo `src/*/*.php` iščete vse PHP datoteke v imenikih druge ravni v imeniku `src`. Znak `**`, imenovan globstar, je močan adut, saj omogoča iskanje tudi v podimenikih: z `src/**/tests/*.php` iščete vse PHP datoteke v imeniku `tests`, ki se nahaja v `src` ali katerem koli njegovem podimeniku.

Nasprotno pa nadomestni znaki `[...]` v poti niso podprti, tj. nimajo posebnega pomena, da ne bi prišlo do nezaželenega vedenja v primeru, da bi iskali na primer `in(__DIR__)` in bi se v poti slučajno pojavili znaki `[]`.

Pri iskanju datotek in imenikov v globino se najprej vrne nadrejeni imenik in šele nato datoteke, ki jih vsebuje, kar je mogoče obrniti z uporabo `childFirst()`.


Nadomestni znaki
----------------

V maski lahko uporabljate več posebnih znakov:

- `*` - nadomešča poljubno število poljubnih znakov (razen `/`)
- `**` - nadomešča poljubno število poljubnih znakov, vključno z `/` (tj. mogoče je iskati večnivojsko)
- `?` - nadomešča en poljuben znak (razen `/`)
- `[a-z]` - nadomešča en znak s seznama znakov v oglatih oklepajih
- `[!a-z]` - nadomešča en znak izven seznama znakov v oglatih oklepajih

Primeri uporabe:

- `img/?.png` - datoteke z enočrkovnim imenom `0.png`, `1.png`, `x.png`, itd.
- `logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log` - dnevniki v formatu `YYYY-MM-DD`
- `src/**/tests/*` - datoteke v imenikih `src/tests`, `src/foo/tests`, `src/foo/bar/tests` in tako naprej.
- `docs/**.md` - vse datoteke s končnico `.md` v vseh podimenikih imenika `docs`


Izključitev
-----------

Z metodo `exclude()` je mogoče izključiti datoteke in imenike iz iskanja. Navedete masko, ki ji datoteka ne sme ustrezati. Primer iskanja datotek `*.txt`, razen tistih, ki v imenu vsebujejo črko `X`:

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

Za izpustitev pregledanih podimenikov uporabite `exclude()`:

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


Filtriranje
-----------

Finder ponuja več metod za filtriranje rezultatov (tj. njihovo zmanjšanje). Lahko jih kombinirate in kličete večkrat.

Z `size()` filtriramo glede na velikost datoteke. Tako najdemo datoteke z velikostjo v območju od 100 do 200 bajtov:

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

Metoda `date()` filtrira glede na datum zadnje spremembe datoteke. Vrednosti so lahko absolutne ali relativne glede na trenutni datum in čas, na primer, tako najdemo datoteke, spremenjene v zadnjih dveh tednih:

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

Obe funkciji razumeta operatorje `>`, `>=`, `<`, `<=`, `=`, `!=`, `<>`.

Finder omogoča tudi filtriranje rezultatov z uporabo lastnih funkcij. Funkcija prejme kot parameter objekt `Nette\Utils\FileInfo` in mora vrniti `true`, da se datoteka vključi v rezultate.

Primer: iskanje PHP datotek, ki vsebujejo niz `Nette` (ne glede na velikost črk):

```php
Finder::findFiles('*.php')
	->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
```


Globinsko filtriranje
---------------------

Pri rekurzivnem iskanju lahko nastavite največjo globino brskanja z metodo `limitDepth()`. Če nastavite `limitDepth(1)`, se preiskujejo samo prvi podimeniki, `limitDepth(0)` izklopi globinsko brskanje in vrednost -1 prekliče omejitev.

Finder omogoča z uporabo lastnih funkcij odločanje, v kateri imenik naj se vstopi med brskanjem. Funkcija prejme kot parameter objekt `Nette\Utils\FileInfo` in mora vrniti `true`, da se vstopi v imenik:

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


Razvrščanje
-----------

Finder ponuja tudi več funkcij za razvrščanje rezultatov.

Metoda `sortByName()` razvršča rezultate po imenih datotek. Razvrščanje je naravno, torej pravilno obravnava števila v imenih in vrača npr. `foo1.txt` pred `foo10.txt`.

Finder omogoča tudi razvrščanje z uporabo lastne funkcije. Ta prejme kot parameter dva objekta `Nette\Utils\FileInfo` in mora vrniti rezultat primerjave z operatorjem `<=>`, torej `-1`, `0` ali `1`. Na primer, tako razvrstimo datoteke po velikosti:

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


Več različnih iskanj
--------------------

Če morate najti več različnih datotek na različnih lokacijah ali ki izpolnjujejo druga merila, uporabite metodo `append()`. Vrne nov objekt `Finder`, zato je mogoče verižiti klice metod:


```php
($finder = new Finder) // v spremenljivko $finder shranimo prvi Finder!
	->files('*.php')   // v src/ iščemo datoteke *.php
	->from('src')
	->append()
	->files('*.md')    // v docs/ iščemo datoteke *.md
	->from('docs')
	->append()
	->files('*.json'); // v trenutni mapi iščemo datoteke *.json
```

Alternativno lahko uporabite metodo `append()` za dodajanje določene datoteke (ali polja datotek). Nato vrne isti objekt `Finder`:

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


FileInfo
--------

[Nette\Utils\FileInfo |api:] je razred, ki predstavlja datoteko ali imenik v rezultatih iskanja. Gre za razširitev razreda [SplFileInfo |php:SplFileInfo], ki zagotavlja informacije, kot so velikost datoteke, datum zadnje spremembe, ime, pot itd.

Poleg tega ponuja metode za vračanje relativne poti, kar je uporabno pri globinskem brskanju:

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

Nadalje imate na voljo metode za branje in pisanje vsebine datoteke:

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


Vračanje rezultatov kot polje
-----------------------------

Kot je bilo videti v primerih, Finder implementira vmesnik `IteratorAggregate`, zato lahko uporabite `foreach` za pregledovanje rezultatov. Programiran je tako, da se rezultati nalagajo samo med pregledovanjem, tako da če imate veliko število datotek, ni treba čakati, da se vse preberejo.

Rezultate lahko dobite tudi kot polje objektov `Nette\Utils\FileInfo` z metodo `collect()`. Polje ni asociativno, ampak numerično.

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

Finder: iskanje datotek

Potrebujete najti datoteke, ki ustrezajo določeni maski? Finder vam bo pri tem pomagal. Je vsestransko in hitro orodje za brskanje po strukturi imenikov.

Namestitev:

composer require nette/utils

Primeri predpostavljajo ustvarjen vzdevek:

use Nette\Utils\Finder;

Uporaba

Najprej si poglejmo, kako lahko z uporabo Nette\Utils\Finder izpišete imena datotek s končnicami .txt in .md v trenutnem imeniku:

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

Privzeti imenik za iskanje je trenutni imenik, vendar ga lahko spremenite z metodama in() ali from(). Spremenljivka $file je instanca razreda FileInfo z veliko uporabnimi metodami. V ključu $name je pot do datoteke kot niz.

Kaj iskati?

Poleg metode findFiles() obstaja tudi findDirectories(), ki išče samo imenike, in find(), ki išče oboje. Te metode so statične, zato jih je mogoče klicati brez ustvarjanja instance. Parameter z masko je neobvezen, če ga ne navedete, se poišče vse.

foreach (Finder::find() as $file) {
	echo $file; // zdaj se izpišejo vse datoteke in imeniki
}

Z metodama files() in directories() lahko dodate, kaj še želite iskati. Metode je mogoče klicati večkrat in kot parameter lahko navedete tudi polje mask:

Finder::findDirectories('vendor') // vsi imeniki
	->files(['*.php', '*.phpt']); // plus vse PHP datoteke

Alternativa statičnim metodam je ustvarjanje instance z new Finder (tako ustvarjen svež objekt ne išče ničesar) in navedbo, kaj iskati, z uporabo files() in directories():

(new Finder)
	->directories()      // vsi imeniki
	->files('*.php');    // plus vse PHP datoteke

V maski lahko uporabljate nadomestne znake *, **, ? in [...]. Lahko celo določite imenike, na primer src/*.php poišče vse PHP datoteke v imeniku src.

Simbolične povezave se prav tako štejejo za imenike ali datoteke.

Kje iskati?

Privzeti imenik za iskanje je trenutni imenik. Spremenite ga z metodama in() in from(). Kot je razvidno iz imen metod, in() išče samo v danem imeniku, medtem ko from() išče tudi v njegovih podimenikih (rekurzivno). Če želite iskati rekurzivno v trenutnem imeniku, lahko uporabite from('.').

Te metode je mogoče klicati večkrat ali jim posredovati več poti kot polje, datoteke se bodo nato iskale v vseh imenikih. Če kateri od imenikov ne obstaja, se sproži izjema Nette\UnexpectedValueException.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // išče neposredno v src/ in tests/
	->from('vendor');      // išče tudi v podimenikih vendor/

Relativne poti so relativne glede na trenutni imenik. Seveda lahko navedete tudi absolutne poti:

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

V poti je mogoče uporabiti nadomestne znake *, **, ?. Tako lahko na primer s potjo src/*/*.php iščete vse PHP datoteke v imenikih druge ravni v imeniku src. Znak **, imenovan globstar, je močan adut, saj omogoča iskanje tudi v podimenikih: z src/**/tests/*.php iščete vse PHP datoteke v imeniku tests, ki se nahaja v src ali katerem koli njegovem podimeniku.

Nasprotno pa nadomestni znaki [...] v poti niso podprti, tj. nimajo posebnega pomena, da ne bi prišlo do nezaželenega vedenja v primeru, da bi iskali na primer in(__DIR__) in bi se v poti slučajno pojavili znaki [].

Pri iskanju datotek in imenikov v globino se najprej vrne nadrejeni imenik in šele nato datoteke, ki jih vsebuje, kar je mogoče obrniti z uporabo childFirst().

Nadomestni znaki

V maski lahko uporabljate več posebnih znakov:

  • * – nadomešča poljubno število poljubnih znakov (razen /)
  • ** – nadomešča poljubno število poljubnih znakov, vključno z / (tj. mogoče je iskati večnivojsko)
  • ? – nadomešča en poljuben znak (razen /)
  • [a-z] – nadomešča en znak s seznama znakov v oglatih oklepajih
  • [!a-z] – nadomešča en znak izven seznama znakov v oglatih oklepajih

Primeri uporabe:

  • img/?.png – datoteke z enočrkovnim imenom 0.png, 1.png, x.png, itd.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – dnevniki v formatu YYYY-MM-DD
  • src/**/tests/* – datoteke v imenikih src/tests, src/foo/tests, src/foo/bar/tests in tako naprej.
  • docs/**.md – vse datoteke s končnico .md v vseh podimenikih imenika docs

Izključitev

Z metodo exclude() je mogoče izključiti datoteke in imenike iz iskanja. Navedete masko, ki ji datoteka ne sme ustrezati. Primer iskanja datotek *.txt, razen tistih, ki v imenu vsebujejo črko X:

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

Za izpustitev pregledanih podimenikov uporabite exclude():

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

Filtriranje

Finder ponuja več metod za filtriranje rezultatov (tj. njihovo zmanjšanje). Lahko jih kombinirate in kličete večkrat.

Z size() filtriramo glede na velikost datoteke. Tako najdemo datoteke z velikostjo v območju od 100 do 200 bajtov:

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

Metoda date() filtrira glede na datum zadnje spremembe datoteke. Vrednosti so lahko absolutne ali relativne glede na trenutni datum in čas, na primer, tako najdemo datoteke, spremenjene v zadnjih dveh tednih:

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

Obe funkciji razumeta operatorje >, >=, <, <=, =, !=, <>.

Finder omogoča tudi filtriranje rezultatov z uporabo lastnih funkcij. Funkcija prejme kot parameter objekt Nette\Utils\FileInfo in mora vrniti true, da se datoteka vključi v rezultate.

Primer: iskanje PHP datotek, ki vsebujejo niz Nette (ne glede na velikost črk):

Finder::findFiles('*.php')
	->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);

Globinsko filtriranje

Pri rekurzivnem iskanju lahko nastavite največjo globino brskanja z metodo limitDepth(). Če nastavite limitDepth(1), se preiskujejo samo prvi podimeniki, limitDepth(0) izklopi globinsko brskanje in vrednost –1 prekliče omejitev.

Finder omogoča z uporabo lastnih funkcij odločanje, v kateri imenik naj se vstopi med brskanjem. Funkcija prejme kot parameter objekt Nette\Utils\FileInfo in mora vrniti true, da se vstopi v imenik:

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

Razvrščanje

Finder ponuja tudi več funkcij za razvrščanje rezultatov.

Metoda sortByName() razvršča rezultate po imenih datotek. Razvrščanje je naravno, torej pravilno obravnava števila v imenih in vrača npr. foo1.txt pred foo10.txt.

Finder omogoča tudi razvrščanje z uporabo lastne funkcije. Ta prejme kot parameter dva objekta Nette\Utils\FileInfo in mora vrniti rezultat primerjave z operatorjem <=>, torej -1, 0 ali 1. Na primer, tako razvrstimo datoteke po velikosti:

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

Več različnih iskanj

Če morate najti več različnih datotek na različnih lokacijah ali ki izpolnjujejo druga merila, uporabite metodo append(). Vrne nov objekt Finder, zato je mogoče verižiti klice metod:

($finder = new Finder) // v spremenljivko $finder shranimo prvi Finder!
	->files('*.php')   // v src/ iščemo datoteke *.php
	->from('src')
	->append()
	->files('*.md')    // v docs/ iščemo datoteke *.md
	->from('docs')
	->append()
	->files('*.json'); // v trenutni mapi iščemo datoteke *.json

Alternativno lahko uporabite metodo append() za dodajanje določene datoteke (ali polja datotek). Nato vrne isti objekt Finder:

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

FileInfo

Nette\Utils\FileInfo je razred, ki predstavlja datoteko ali imenik v rezultatih iskanja. Gre za razširitev razreda SplFileInfo, ki zagotavlja informacije, kot so velikost datoteke, datum zadnje spremembe, ime, pot itd.

Poleg tega ponuja metode za vračanje relativne poti, kar je uporabno pri globinskem brskanju:

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

Nadalje imate na voljo metode za branje in pisanje vsebine datoteke:

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

Vračanje rezultatov kot polje

Kot je bilo videti v primerih, Finder implementira vmesnik IteratorAggregate, zato lahko uporabite foreach za pregledovanje rezultatov. Programiran je tako, da se rezultati nalagajo samo med pregledovanjem, tako da če imate veliko število datotek, ni treba čakati, da se vse preberejo.

Rezultate lahko dobite tudi kot polje objektov Nette\Utils\FileInfo z metodo collect(). Polje ni asociativno, ampak numerično.

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