mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
450 lines
14 KiB
ReStructuredText
450 lines
14 KiB
ReStructuredText
The Finder Component
|
|
====================
|
|
|
|
The Finder component finds files and directories based on different criteria
|
|
(name, file size, modification time, etc.) via an intuitive fluent interface.
|
|
|
|
Installation
|
|
------------
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/finder
|
|
|
|
.. include:: /components/require_autoload.rst.inc
|
|
|
|
Usage
|
|
-----
|
|
|
|
The :class:`Symfony\\Component\\Finder\\Finder` class finds files and/or
|
|
directories::
|
|
|
|
use Symfony\Component\Finder\Finder;
|
|
|
|
$finder = new Finder();
|
|
// find all files in the current directory
|
|
$finder->files()->in(__DIR__);
|
|
|
|
// check if there are any search results
|
|
if ($finder->hasResults()) {
|
|
// ...
|
|
}
|
|
|
|
foreach ($finder as $file) {
|
|
$absoluteFilePath = $file->getRealPath();
|
|
$fileNameWithExtension = $file->getRelativePathname();
|
|
|
|
// ...
|
|
}
|
|
|
|
The ``$file`` variable is an instance of
|
|
:class:`Symfony\\Component\\Finder\\SplFileInfo` which extends PHP's own
|
|
:phpclass:`SplFileInfo` to provide methods to work with relative paths.
|
|
|
|
.. warning::
|
|
|
|
The ``Finder`` object doesn't reset its internal state automatically.
|
|
This means that you need to create a new instance if you do not want
|
|
to get mixed results.
|
|
|
|
Searching for Files and Directories
|
|
-----------------------------------
|
|
|
|
The component provides lots of methods to define the search criteria. They all
|
|
can be chained because they implement a `fluent interface`_.
|
|
|
|
Location
|
|
~~~~~~~~
|
|
|
|
The location is the only mandatory criteria. It tells the finder which
|
|
directory to use for the search::
|
|
|
|
$finder->in(__DIR__);
|
|
|
|
Search in several locations by chaining calls to
|
|
:method:`Symfony\\Component\\Finder\\Finder::in`::
|
|
|
|
// search inside *both* directories
|
|
$finder->in([__DIR__, '/elsewhere']);
|
|
|
|
// same as above
|
|
$finder->in(__DIR__)->in('/elsewhere');
|
|
|
|
Use ``*`` as a wildcard character to search in the directories matching a
|
|
pattern (each pattern has to resolve to at least one directory path)::
|
|
|
|
$finder->in('src/Symfony/*/*/Resources');
|
|
|
|
Exclude directories from matching with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::exclude` method::
|
|
|
|
// directories passed as argument must be relative to the ones defined with the in() method
|
|
$finder->in(__DIR__)->exclude('ruby');
|
|
|
|
It's also possible to ignore directories that you don't have permission to read::
|
|
|
|
$finder->ignoreUnreadableDirs()->in(__DIR__);
|
|
|
|
As the Finder uses PHP iterators, you can pass any URL with a supported
|
|
`PHP wrapper for URL-style protocols`_ (``ftp://``, ``zlib://``, etc.)::
|
|
|
|
// always add a trailing slash when looking for in the FTP root dir
|
|
$finder->in('ftp://example.com/');
|
|
|
|
// you can also look for in a FTP directory
|
|
$finder->in('ftp://example.com/pub/');
|
|
|
|
And it also works with user-defined streams::
|
|
|
|
use Symfony\Component\Finder\Finder;
|
|
|
|
// register a 's3://' wrapper with the official AWS SDK
|
|
$s3Client = new Aws\S3\S3Client([/* config options */]);
|
|
$s3Client->registerStreamWrapper();
|
|
|
|
$finder = new Finder();
|
|
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
|
|
foreach ($finder->in('s3://bucket-name') as $file) {
|
|
// ... do something with the file
|
|
}
|
|
|
|
.. seealso::
|
|
|
|
Read the `PHP streams`_ documentation to learn how to create your own streams.
|
|
|
|
Files or Directories
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
By default, the Finder returns both files and directories. If you need to find either files or directories only, use the :method:`Symfony\\Component\\Finder\\Finder::files` and :method:`Symfony\\Component\\Finder\\Finder::directories` methods::
|
|
|
|
// look for files only; ignore directories
|
|
$finder->files();
|
|
|
|
// look for directories only; ignore files
|
|
$finder->directories();
|
|
|
|
If you want to follow `symbolic links`_, use the ``followLinks()`` method::
|
|
|
|
$finder->files()->followLinks();
|
|
|
|
Note that this method follows links but it doesn't resolve them. Consider
|
|
the following structure of files of directories:
|
|
|
|
.. code-block:: text
|
|
|
|
├── folder1/
|
|
│ ├──file1.txt
|
|
│ ├── file2link (symbolic link to folder2/file2.txt file)
|
|
│ └── folder3link (symbolic link to folder3/ directory)
|
|
├── folder2/
|
|
│ └── file2.txt
|
|
└── folder3/
|
|
└── file3.txt
|
|
|
|
If you try to find all files in ``folder1/`` via ``$finder->files()->in('/path/to/folder1/')``
|
|
you'll get the following results:
|
|
|
|
* When **not** using the ``followLinks()`` method: ``file1.txt`` and ``file2link``
|
|
(this link is not resolved). The ``folder3link`` doesn't appear in the results
|
|
because it's not followed or resolved;
|
|
* When using the ``followLinks()`` method: ``file1.txt``, ``file2link`` (this link
|
|
is still not resolved) and ``folder3/file3.txt`` (this file appears in the results
|
|
because the ``folder1/folder3link`` link was followed).
|
|
|
|
Version Control Files
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
`Version Control Systems`_ (or "VCS" for short), such as Git and Mercurial,
|
|
create some special files to store their metadata. Those files are ignored by
|
|
default when looking for files and directories, but you can change this with the
|
|
``ignoreVCS()`` method::
|
|
|
|
$finder->ignoreVCS(false);
|
|
|
|
If the search directory and its subdirectories contain ``.gitignore`` files, you
|
|
can reuse those rules to exclude files and directories from the results with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored` method::
|
|
|
|
// excludes files/directories matching the .gitignore patterns
|
|
$finder->ignoreVCSIgnored(true);
|
|
|
|
The rules of a directory always override the rules of its parent directories.
|
|
|
|
.. note::
|
|
|
|
Git looks for ``.gitignore`` files starting from the repository root directory.
|
|
Symfony's Finder behavior is different and it looks for ``.gitignore`` files
|
|
starting from the directory used to search files/directories. To be consistent
|
|
with Git behavior, you should explicitly search from the Git repository root.
|
|
|
|
File Name
|
|
~~~~~~~~~
|
|
|
|
Find files by name with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::name` method::
|
|
|
|
$finder->files()->name('*.php');
|
|
|
|
The ``name()`` method accepts globs, strings, regexes or an array of globs,
|
|
strings or regexes::
|
|
|
|
$finder->files()->name('/\.php$/');
|
|
|
|
Multiple filenames can be defined by chaining calls or passing an array::
|
|
|
|
$finder->files()->name('*.php')->name('*.twig');
|
|
|
|
// same as above
|
|
$finder->files()->name(['*.php', '*.twig']);
|
|
|
|
The ``notName()`` method excludes files matching a pattern::
|
|
|
|
$finder->files()->notName('*.rb');
|
|
|
|
Multiple filenames can be excluded by chaining calls or passing an array::
|
|
|
|
$finder->files()->notName('*.rb')->notName('*.py');
|
|
|
|
// same as above
|
|
$finder->files()->notName(['*.rb', '*.py']);
|
|
|
|
File Contents
|
|
~~~~~~~~~~~~~
|
|
|
|
Find files by content with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::contains` method::
|
|
|
|
$finder->files()->contains('lorem ipsum');
|
|
|
|
The ``contains()`` method accepts strings or regexes::
|
|
|
|
$finder->files()->contains('/lorem\s+ipsum$/i');
|
|
|
|
The ``notContains()`` method excludes files containing given pattern::
|
|
|
|
$finder->files()->notContains('dolor sit amet');
|
|
|
|
Path
|
|
~~~~
|
|
|
|
Find files and directories by path with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::path` method::
|
|
|
|
// matches files that contain "data" anywhere in their paths (files or directories)
|
|
$finder->path('data');
|
|
// for example this will match data/*.xml and data.xml if they exist
|
|
$finder->path('data')->name('*.xml');
|
|
|
|
Use the forward slash (i.e. ``/``) as the directory separator on all platforms,
|
|
including Windows. The component makes the necessary conversion internally.
|
|
|
|
The ``path()`` method accepts a string, a regular expression or an array of
|
|
strings or regular expressions::
|
|
|
|
$finder->path('foo/bar');
|
|
$finder->path('/^foo\/bar/');
|
|
|
|
Multiple paths can be defined by chaining calls or passing an array::
|
|
|
|
$finder->path('data')->path('foo/bar');
|
|
|
|
// same as above
|
|
$finder->path(['data', 'foo/bar']);
|
|
|
|
Internally, strings are converted into regular expressions by escaping slashes
|
|
and adding delimiters:
|
|
|
|
===================== =======================
|
|
Original Given String Regular Expression Used
|
|
===================== =======================
|
|
``dirname`` ``/dirname/``
|
|
``a/b/c`` ``/a\/b\/c/``
|
|
===================== =======================
|
|
|
|
The :method:`Symfony\\Component\\Finder\\Finder::notPath` method excludes files
|
|
by path::
|
|
|
|
$finder->notPath('other/dir');
|
|
|
|
Multiple paths can be excluded by chaining calls or passing an array::
|
|
|
|
$finder->notPath('first/dir')->notPath('other/dir');
|
|
|
|
// same as above
|
|
$finder->notPath(['first/dir', 'other/dir']);
|
|
|
|
File Size
|
|
~~~~~~~~~
|
|
|
|
Find files by size with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::size` method::
|
|
|
|
$finder->files()->size('< 1.5K');
|
|
|
|
Restrict by a size range by chaining calls or passing an array::
|
|
|
|
$finder->files()->size('>= 1K')->size('<= 2K');
|
|
|
|
// same as above
|
|
$finder->files()->size(['>= 1K', '<= 2K']);
|
|
|
|
The comparison operator can be any of the following: ``>``, ``>=``, ``<``,
|
|
``<=``, ``==``, ``!=``.
|
|
|
|
The target value may use magnitudes of kilobytes (``k``, ``ki``), megabytes
|
|
(``m``, ``mi``), or gigabytes (``g``, ``gi``). Those suffixed with an ``i`` use
|
|
the appropriate ``2**n`` version in accordance with the `IEC standard`_.
|
|
|
|
File Date
|
|
~~~~~~~~~
|
|
|
|
Find files by last modified dates with the
|
|
:method:`Symfony\\Component\\Finder\\Finder::date` method::
|
|
|
|
$finder->date('since yesterday');
|
|
|
|
Restrict by a date range by chaining calls or passing an array::
|
|
|
|
$finder->date('>= 2018-01-01')->date('<= 2018-12-31');
|
|
|
|
// same as above
|
|
$finder->date(['>= 2018-01-01', '<= 2018-12-31']);
|
|
|
|
The comparison operator can be any of the following: ``>``, ``>=``, ``<``,
|
|
``<=``, ``==``. You can also use ``since`` or ``after`` as an alias for ``>``,
|
|
and ``until`` or ``before`` as an alias for ``<``.
|
|
|
|
The target value can be any date supported by :phpfunction:`strtotime`.
|
|
|
|
Directory Depth
|
|
~~~~~~~~~~~~~~~
|
|
|
|
By default, the Finder recursively traverses directories. Restrict the depth of
|
|
traversing with :method:`Symfony\\Component\\Finder\\Finder::depth`::
|
|
|
|
// this will only consider files/directories which are direct children
|
|
$finder->depth('== 0');
|
|
$finder->depth('< 3');
|
|
|
|
Restrict by a depth range by chaining calls or passing an array::
|
|
|
|
$finder->depth('> 2')->depth('< 5');
|
|
|
|
// same as above
|
|
$finder->depth(['> 2', '< 5']);
|
|
|
|
Custom Filtering
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
To filter results with your own strategy, use
|
|
:method:`Symfony\\Component\\Finder\\Finder::filter`::
|
|
|
|
$filter = function (\SplFileInfo $file)
|
|
{
|
|
if (strlen($file) > 10) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
$finder->files()->filter($filter);
|
|
|
|
The ``filter()`` method takes a Closure as an argument. For each matching file,
|
|
it is called with the file as a :class:`Symfony\\Component\\Finder\\SplFileInfo`
|
|
instance. The file is excluded from the result set if the Closure returns
|
|
``false``.
|
|
|
|
The ``filter()`` method includes a second optional argument to prune directories.
|
|
If set to ``true``, this method completely skips the excluded directories instead
|
|
of traversing the entire file/directory structure and excluding them later. When
|
|
using a closure, return ``false`` for the directories which you want to prune.
|
|
|
|
Pruning directories early can improve performance significantly depending on the
|
|
file/directory hierarchy complexity and the number of excluded directories.
|
|
|
|
Sorting Results
|
|
---------------
|
|
|
|
Sort the results by name, extension, size or type (directories first, then files)::
|
|
|
|
$finder->sortByName();
|
|
$finder->sortByCaseInsensitiveName();
|
|
$finder->sortByExtension();
|
|
$finder->sortBySize();
|
|
$finder->sortByType();
|
|
|
|
.. tip::
|
|
|
|
By default, the ``sortByName()`` method uses the :phpfunction:`strcmp` PHP
|
|
function (e.g. ``file1.txt``, ``file10.txt``, ``file2.txt``). Pass ``true``
|
|
as its argument to use PHP's `natural sort order`_ algorithm instead (e.g.
|
|
``file1.txt``, ``file2.txt``, ``file10.txt``).
|
|
|
|
The ``sortByCaseInsensitiveName()`` method uses the case insensitive
|
|
:phpfunction:`strcasecmp` PHP function. Pass ``true`` as its argument to use
|
|
PHP's case insensitive `natural sort order`_ algorithm instead (i.e. the
|
|
:phpfunction:`strnatcasecmp` PHP function)
|
|
|
|
Sort the files and directories by the last accessed, changed or modified time::
|
|
|
|
$finder->sortByAccessedTime();
|
|
|
|
$finder->sortByChangedTime();
|
|
|
|
$finder->sortByModifiedTime();
|
|
|
|
You can also define your own sorting algorithm with the ``sort()`` method::
|
|
|
|
$finder->sort(function (\SplFileInfo $a, \SplFileInfo $b): int {
|
|
return strcmp($a->getRealPath(), $b->getRealPath());
|
|
});
|
|
|
|
You can reverse any sorting by using the ``reverseSorting()`` method::
|
|
|
|
// results will be sorted "Z to A" instead of the default "A to Z"
|
|
$finder->sortByName()->reverseSorting();
|
|
|
|
.. note::
|
|
|
|
Notice that the ``sort*`` methods need to get all matching elements to do
|
|
their jobs. For large iterators, it is slow.
|
|
|
|
Transforming Results into Arrays
|
|
--------------------------------
|
|
|
|
A Finder instance is an :phpclass:`IteratorAggregate` PHP class. So, in addition
|
|
to iterating over the Finder results with ``foreach``, you can also convert it
|
|
to an array with the :phpfunction:`iterator_to_array` function, or get the
|
|
number of items with :phpfunction:`iterator_count`.
|
|
|
|
If you call to the :method:`Symfony\\Component\\Finder\\Finder::in` method more
|
|
than once to search through multiple locations, pass ``false`` as a second
|
|
parameter to :phpfunction:`iterator_to_array` to avoid issues (a separate
|
|
iterator is created for each location and, if you don't pass ``false`` to
|
|
:phpfunction:`iterator_to_array`, keys of result sets are used and some of them
|
|
might be duplicated and their values overwritten).
|
|
|
|
Reading Contents of Returned Files
|
|
----------------------------------
|
|
|
|
The contents of returned files can be read with
|
|
:method:`Symfony\\Component\\Finder\\SplFileInfo::getContents`::
|
|
|
|
use Symfony\Component\Finder\Finder;
|
|
|
|
$finder = new Finder();
|
|
$finder->files()->in(__DIR__);
|
|
|
|
foreach ($finder as $file) {
|
|
$contents = $file->getContents();
|
|
|
|
// ...
|
|
}
|
|
|
|
.. _`fluent interface`: https://en.wikipedia.org/wiki/Fluent_interface
|
|
.. _`symbolic links`: https://en.wikipedia.org/wiki/Symbolic_link
|
|
.. _`Version Control Systems`: https://en.wikipedia.org/wiki/Version_control
|
|
.. _`PHP wrapper for URL-style protocols`: https://www.php.net/manual/en/wrappers.php
|
|
.. _`PHP streams`: https://www.php.net/streams
|
|
.. _`IEC standard`: https://physics.nist.gov/cuu/Units/binary.html
|
|
.. _`natural sort order`: https://en.wikipedia.org/wiki/Natural_sort_order
|