Nette Documentation Preview

syntax
Finder: procurando arquivos
***************************

.[perex]
Precisa encontrar arquivos que correspondam a uma determinada máscara? O Finder pode ajudá-lo com isso. É uma ferramenta versátil e rápida para navegar na estrutura de diretórios.


Instalação:

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

Os exemplos pressupõem a criação de um alias:

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


Uso
---

Primeiro, vamos mostrar como você pode usar [api:Nette\Utils\Finder] para listar os nomes dos arquivos com as extensões `.txt` e `.md` no diretório atual:

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

O diretório padrão para busca é o diretório atual, mas você pode alterá-lo usando os métodos [in() ou from() |#Onde procurar]. A variável `$file` é uma instância da classe [#FileInfo] com muitos métodos úteis. A chave `$name` contém o caminho para o arquivo como uma string.


O que procurar?
---------------

Além do método `findFiles()`, existem também `findDirectories()`, que busca apenas diretórios, e `find()`, que busca ambos. Esses métodos são estáticos, portanto, podem ser chamados sem criar uma instância. O parâmetro com a máscara é opcional; se você não o fornecer, tudo será pesquisado.

```php
foreach (Finder::find() as $file) {
	echo $file; // agora todos os arquivos e diretórios serão listados
}
```

Usando os métodos `files()` e `directories()`, você pode especificar o que mais procurar. Os métodos podem ser chamados repetidamente, e um array de máscaras também pode ser fornecido como parâmetro:

```php
Finder::findDirectories('vendor') // todos os diretórios
	->files(['*.php', '*.phpt']); // mais todos os arquivos PHP
```

Uma alternativa aos métodos estáticos é criar uma instância usando `new Finder` (um objeto recém-criado assim não procura nada) e especificar o que procurar usando `files()` e `directories()`:

```php
(new Finder)
	->directories()      // todos os diretórios
	->files('*.php');    // mais todos os arquivos PHP
```

Na máscara, você pode usar [#caracteres curinga] `*`, `**`, `?` e `[...]`. Você pode até especificar diretórios, por exemplo, `src/*.php` encontrará todos os arquivos PHP no diretório `src`.

Links simbólicos também são considerados diretórios ou arquivos.


Onde procurar?
--------------

O diretório padrão para busca é o diretório atual. Você pode alterá-lo usando os métodos `in()` e `from()`. Como os nomes dos métodos sugerem, `in()` busca apenas no diretório especificado, enquanto `from()` busca também em seus subdiretórios (recursivamente). Se você quiser buscar recursivamente no diretório atual, pode usar `from('.')`.

Esses métodos podem ser chamados várias vezes ou podem receber vários caminhos como um array; os arquivos serão então pesquisados em todos os diretórios. Se algum dos diretórios não existir, uma exceção `Nette\UnexpectedValueException` será lançada.

```php
Finder::findFiles('*.php')
	->in(['src', 'tests']) // busca diretamente em src/ e tests/
	->from('vendor');      // busca também nos subdiretórios de vendor/
```

Caminhos relativos são relativos ao diretório atual. Claro, caminhos absolutos também podem ser fornecidos:

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

É possível usar [#caracteres curinga] `*`, `**`, `?` no caminho. Por exemplo, com o caminho `src/*/*.php`, você pode procurar todos os arquivos PHP nos diretórios de segundo nível dentro do diretório `src`. O caractere `**`, chamado globstar, é um trunfo poderoso, pois permite buscar também em subdiretórios: com `src/**/tests/*.php`, você procura todos os arquivos PHP no diretório `tests` localizado em `src` ou em qualquer um de seus subdiretórios.

Por outro lado, os caracteres curinga `[...]` não são suportados no caminho, ou seja, não têm significado especial, para evitar comportamento indesejado caso você procure, por exemplo, `in(__DIR__)` e os caracteres `[]` apareçam acidentalmente no caminho.

Ao buscar arquivos e diretórios em profundidade, o diretório pai é retornado primeiro, seguido pelos arquivos contidos nele. Isso pode ser invertido usando `childFirst()`.


Caracteres curinga
------------------

Na máscara, você pode usar vários caracteres especiais:

- `*` - substitui qualquer número de caracteres (exceto `/`)
- `**` - substitui qualquer número de caracteres, incluindo `/` (ou seja, permite busca multinível)
- `?` - substitui um único caractere qualquer (exceto `/`)
- `[a-z]` - substitui um único caractere da lista de caracteres entre colchetes
- `[!a-z]` - substitui um único caractere fora da lista de caracteres entre colchetes

Exemplos de uso:

- `img/?.png` - arquivos com nomes de uma letra `0.png`, `1.png`, `x.png`, etc.
- `logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log` - logs no formato `YYYY-MM-DD`
- `src/**/tests/*` - arquivos no diretório `src/tests`, `src/foo/tests`, `src/foo/bar/tests`, e assim por diante.
- `docs/**.md` - todos os arquivos com a extensão `.md` em todos os subdiretórios do diretório `docs`


Exclusão
--------

Usando o método `exclude()`, você pode excluir arquivos e diretórios da busca. Você fornece uma máscara que o arquivo não deve corresponder. Exemplo de busca por arquivos `*.txt`, exceto aqueles que contêm a letra `X` no nome:

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

Para pular a travessia de subdiretórios, use `exclude()`:

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


Filtragem
---------

O Finder oferece vários métodos para filtrar os resultados (ou seja, reduzi-los). Você pode combiná-los e chamá-los repetidamente.

Usando `size()`, filtramos pelo tamanho do arquivo. Desta forma, encontramos arquivos com tamanho entre 100 e 200 bytes:

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

O método `date()` filtra pela data da última modificação do arquivo. Os valores podem ser absolutos ou relativos à data e hora atuais; por exemplo, desta forma encontramos arquivos modificados nas últimas duas semanas:

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

Ambas as funções entendem os operadores `>`, `>=`, `<`, `<=`, `=`, `!=`, `<>`.

O Finder também permite filtrar resultados usando funções personalizadas. A função recebe um objeto `Nette\Utils\FileInfo` como parâmetro e deve retornar `true` para que o arquivo seja incluído nos resultados.

Exemplo: busca por arquivos PHP que contêm a string `Nette` (sem diferenciar maiúsculas de minúsculas):

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


Filtragem em profundidade
-------------------------

Ao buscar recursivamente, você pode definir a profundidade máxima de travessia usando o método `limitDepth()`. Se você definir `limitDepth(1)`, apenas os primeiros subdiretórios são percorridos; `limitDepth(0)` desativa a travessia em profundidade, e um valor de -1 remove o limite.

O Finder permite decidir em qual diretório entrar durante a travessia usando funções personalizadas. A função recebe um objeto `Nette\Utils\FileInfo` como parâmetro e deve retornar `true` para entrar no diretório:

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


Ordenação
---------

O Finder também oferece várias funções para ordenar os resultados.

O método `sortByName()` ordena os resultados pelos nomes dos arquivos. A ordenação é natural, o que significa que lida corretamente com números nos nomes e retorna, por exemplo, `foo1.txt` antes de `foo10.txt`.

O Finder também permite ordenar usando uma função personalizada. Ela recebe dois objetos `Nette\Utils\FileInfo` como parâmetros e deve retornar o resultado da comparação usando o operador `<=>`, ou seja, `-1`, `0` ou `1`. Por exemplo, desta forma ordenamos os arquivos por tamanho:

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


Múltiplas buscas diferentes
---------------------------

Se você precisa encontrar vários arquivos diferentes em locais diferentes ou que atendam a critérios diferentes, use o método `append()`. Ele retorna um novo objeto `Finder`, permitindo encadear chamadas de método:


```php
($finder = new Finder) // armazenamos o primeiro Finder na variável $finder!
	->files('*.php')   // em src/ procuramos arquivos *.php
	->from('src')
	->append()
	->files('*.md')    // em docs/ procuramos arquivos *.md
	->from('docs')
	->append()
	->files('*.json'); // na pasta atual procuramos arquivos *.json
```

Alternativamente, o método `append()` pode ser usado para adicionar um arquivo específico (ou um array de arquivos). Ele então retorna o mesmo objeto `Finder`:

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


FileInfo
--------

[Nette\Utils\FileInfo |api:] é uma classe que representa um arquivo ou diretório nos resultados da busca. É uma extensão da classe [SplFileInfo |php:SplFileInfo], que fornece informações como tamanho do arquivo, data da última modificação, nome, caminho, etc.

Além disso, fornece métodos para retornar o caminho relativo, o que é útil ao percorrer em profundidade:

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

Você também tem métodos disponíveis para ler e escrever o conteúdo do arquivo:

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


Retornando resultados como um array
-----------------------------------

Como visto nos exemplos, o Finder implementa a interface `IteratorAggregate`, então você pode usar `foreach` para percorrer os resultados. Ele é programado de forma que os resultados sejam carregados apenas durante a iteração, então, se você tiver um grande número de arquivos, não há espera até que todos sejam lidos.

Você também pode ter os resultados retornados como um array de objetos `Nette\Utils\FileInfo` usando o método `collect()`. O array não é associativo, mas numérico.

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

Finder: procurando arquivos

Precisa encontrar arquivos que correspondam a uma determinada máscara? O Finder pode ajudá-lo com isso. É uma ferramenta versátil e rápida para navegar na estrutura de diretórios.

Instalação:

composer require nette/utils

Os exemplos pressupõem a criação de um alias:

use Nette\Utils\Finder;

Uso

Primeiro, vamos mostrar como você pode usar Nette\Utils\Finder para listar os nomes dos arquivos com as extensões .txt e .md no diretório atual:

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

O diretório padrão para busca é o diretório atual, mas você pode alterá-lo usando os métodos in() ou from(). A variável $file é uma instância da classe FileInfo com muitos métodos úteis. A chave $name contém o caminho para o arquivo como uma string.

O que procurar?

Além do método findFiles(), existem também findDirectories(), que busca apenas diretórios, e find(), que busca ambos. Esses métodos são estáticos, portanto, podem ser chamados sem criar uma instância. O parâmetro com a máscara é opcional; se você não o fornecer, tudo será pesquisado.

foreach (Finder::find() as $file) {
	echo $file; // agora todos os arquivos e diretórios serão listados
}

Usando os métodos files() e directories(), você pode especificar o que mais procurar. Os métodos podem ser chamados repetidamente, e um array de máscaras também pode ser fornecido como parâmetro:

Finder::findDirectories('vendor') // todos os diretórios
	->files(['*.php', '*.phpt']); // mais todos os arquivos PHP

Uma alternativa aos métodos estáticos é criar uma instância usando new Finder (um objeto recém-criado assim não procura nada) e especificar o que procurar usando files() e directories():

(new Finder)
	->directories()      // todos os diretórios
	->files('*.php');    // mais todos os arquivos PHP

Na máscara, você pode usar caracteres curinga *, **, ? e [...]. Você pode até especificar diretórios, por exemplo, src/*.php encontrará todos os arquivos PHP no diretório src.

Links simbólicos também são considerados diretórios ou arquivos.

Onde procurar?

O diretório padrão para busca é o diretório atual. Você pode alterá-lo usando os métodos in() e from(). Como os nomes dos métodos sugerem, in() busca apenas no diretório especificado, enquanto from() busca também em seus subdiretórios (recursivamente). Se você quiser buscar recursivamente no diretório atual, pode usar from('.').

Esses métodos podem ser chamados várias vezes ou podem receber vários caminhos como um array; os arquivos serão então pesquisados em todos os diretórios. Se algum dos diretórios não existir, uma exceção Nette\UnexpectedValueException será lançada.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // busca diretamente em src/ e tests/
	->from('vendor');      // busca também nos subdiretórios de vendor/

Caminhos relativos são relativos ao diretório atual. Claro, caminhos absolutos também podem ser fornecidos:

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

É possível usar caracteres curinga *, **, ? no caminho. Por exemplo, com o caminho src/*/*.php, você pode procurar todos os arquivos PHP nos diretórios de segundo nível dentro do diretório src. O caractere **, chamado globstar, é um trunfo poderoso, pois permite buscar também em subdiretórios: com src/**/tests/*.php, você procura todos os arquivos PHP no diretório tests localizado em src ou em qualquer um de seus subdiretórios.

Por outro lado, os caracteres curinga [...] não são suportados no caminho, ou seja, não têm significado especial, para evitar comportamento indesejado caso você procure, por exemplo, in(__DIR__) e os caracteres [] apareçam acidentalmente no caminho.

Ao buscar arquivos e diretórios em profundidade, o diretório pai é retornado primeiro, seguido pelos arquivos contidos nele. Isso pode ser invertido usando childFirst().

Caracteres curinga

Na máscara, você pode usar vários caracteres especiais:

  • * – substitui qualquer número de caracteres (exceto /)
  • ** – substitui qualquer número de caracteres, incluindo / (ou seja, permite busca multinível)
  • ? – substitui um único caractere qualquer (exceto /)
  • [a-z] – substitui um único caractere da lista de caracteres entre colchetes
  • [!a-z] – substitui um único caractere fora da lista de caracteres entre colchetes

Exemplos de uso:

  • img/?.png – arquivos com nomes de uma letra 0.png, 1.png, x.png, etc.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – logs no formato YYYY-MM-DD
  • src/**/tests/* – arquivos no diretório src/tests, src/foo/tests, src/foo/bar/tests, e assim por diante.
  • docs/**.md – todos os arquivos com a extensão .md em todos os subdiretórios do diretório docs

Exclusão

Usando o método exclude(), você pode excluir arquivos e diretórios da busca. Você fornece uma máscara que o arquivo não deve corresponder. Exemplo de busca por arquivos *.txt, exceto aqueles que contêm a letra X no nome:

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

Para pular a travessia de subdiretórios, use exclude():

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

Filtragem

O Finder oferece vários métodos para filtrar os resultados (ou seja, reduzi-los). Você pode combiná-los e chamá-los repetidamente.

Usando size(), filtramos pelo tamanho do arquivo. Desta forma, encontramos arquivos com tamanho entre 100 e 200 bytes:

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

O método date() filtra pela data da última modificação do arquivo. Os valores podem ser absolutos ou relativos à data e hora atuais; por exemplo, desta forma encontramos arquivos modificados nas últimas duas semanas:

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

Ambas as funções entendem os operadores >, >=, <, <=, =, !=, <>.

O Finder também permite filtrar resultados usando funções personalizadas. A função recebe um objeto Nette\Utils\FileInfo como parâmetro e deve retornar true para que o arquivo seja incluído nos resultados.

Exemplo: busca por arquivos PHP que contêm a string Nette (sem diferenciar maiúsculas de minúsculas):

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

Filtragem em profundidade

Ao buscar recursivamente, você pode definir a profundidade máxima de travessia usando o método limitDepth(). Se você definir limitDepth(1), apenas os primeiros subdiretórios são percorridos; limitDepth(0) desativa a travessia em profundidade, e um valor de –1 remove o limite.

O Finder permite decidir em qual diretório entrar durante a travessia usando funções personalizadas. A função recebe um objeto Nette\Utils\FileInfo como parâmetro e deve retornar true para entrar no diretório:

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

Ordenação

O Finder também oferece várias funções para ordenar os resultados.

O método sortByName() ordena os resultados pelos nomes dos arquivos. A ordenação é natural, o que significa que lida corretamente com números nos nomes e retorna, por exemplo, foo1.txt antes de foo10.txt.

O Finder também permite ordenar usando uma função personalizada. Ela recebe dois objetos Nette\Utils\FileInfo como parâmetros e deve retornar o resultado da comparação usando o operador <=>, ou seja, -1, 0 ou 1. Por exemplo, desta forma ordenamos os arquivos por tamanho:

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

Múltiplas buscas diferentes

Se você precisa encontrar vários arquivos diferentes em locais diferentes ou que atendam a critérios diferentes, use o método append(). Ele retorna um novo objeto Finder, permitindo encadear chamadas de método:

($finder = new Finder) // armazenamos o primeiro Finder na variável $finder!
	->files('*.php')   // em src/ procuramos arquivos *.php
	->from('src')
	->append()
	->files('*.md')    // em docs/ procuramos arquivos *.md
	->from('docs')
	->append()
	->files('*.json'); // na pasta atual procuramos arquivos *.json

Alternativamente, o método append() pode ser usado para adicionar um arquivo específico (ou um array de arquivos). Ele então retorna o mesmo objeto Finder:

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

FileInfo

Nette\Utils\FileInfo é uma classe que representa um arquivo ou diretório nos resultados da busca. É uma extensão da classe SplFileInfo, que fornece informações como tamanho do arquivo, data da última modificação, nome, caminho, etc.

Além disso, fornece métodos para retornar o caminho relativo, o que é útil ao percorrer em profundidade:

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

Você também tem métodos disponíveis para ler e escrever o conteúdo do arquivo:

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

Retornando resultados como um array

Como visto nos exemplos, o Finder implementa a interface IteratorAggregate, então você pode usar foreach para percorrer os resultados. Ele é programado de forma que os resultados sejam carregados apenas durante a iteração, então, se você tiver um grande número de arquivos, não há espera até que todos sejam lidos.

Você também pode ter os resultados retornados como um array de objetos Nette\Utils\FileInfo usando o método collect(). O array não é associativo, mas numérico.

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