Skip to content

Commit 8813d31

Browse files
committed
Draft documentation for the Path class
1 parent 7de7194 commit 8813d31

File tree

1 file changed

+205
-4
lines changed

1 file changed

+205
-4
lines changed

components/filesystem.rst

Lines changed: 205 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
The Filesystem Component
55
========================
66

7-
The Filesystem component provides basic utilities for the filesystem.
7+
The Filesystem component provides basic utilities for the filesystem and
8+
paths manipulation.
89

910
Installation
1011
------------
@@ -18,16 +19,23 @@ Installation
1819
Usage
1920
-----
2021

21-
The :class:`Symfony\\Component\\Filesystem\\Filesystem` class is the unique
22-
endpoint for filesystem operations::
22+
The component contains two classes:
23+
24+
- The :class:`Symfony\\Component\\Filesystem\\Filesystem` which provides utilities
25+
for filesystem write operations.
26+
- The :class:`Symfony\\Component\\Filesystem\\Path` which provides utilities
27+
for paths manipulation.::
2328

2429
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
2530
use Symfony\Component\Filesystem\Filesystem;
31+
use Symfony\Component\Filesystem\Path;
2632

2733
$filesystem = new Filesystem();
2834

2935
try {
30-
$filesystem->mkdir(sys_get_temp_dir().'/'.random_int(0, 1000));
36+
$filesystem->mkdir(
37+
Path::normalize(sys_get_temp_dir().'/'.random_int(0, 1000)),
38+
);
3139
} catch (IOExceptionInterface $exception) {
3240
echo "An error occurred while creating your directory at ".$exception->getPath();
3341
}
@@ -44,6 +52,9 @@ endpoint for filesystem operations::
4452
string, an array or any object implementing :phpclass:`Traversable` as
4553
the target argument.
4654

55+
Filesystem
56+
----------
57+
4758
``mkdir``
4859
~~~~~~~~~
4960

@@ -236,6 +247,11 @@ Its behavior is the following::
236247
* if ``$path`` does not exist, it returns null.
237248
* if ``$path`` exists, it returns its absolute fully resolved final version.
238249

250+
.. note::
251+
252+
If you wish to canonicalize the path without checking its existence, you can
253+
use :method:`Symfony\\Component\\Filesystem\\Path::canonicalize` instead.
254+
239255
``makePathRelative``
240256
~~~~~~~~~~~~~~~~~~~~
241257

@@ -315,6 +331,191 @@ contents at the end of some file::
315331
If either the file or its containing directory doesn't exist, this method
316332
creates them before appending the contents.
317333

334+
Path
335+
----
336+
337+
.. versionadded:: 5.4
338+
339+
The :class:`Symfony\\Component\\Filesystem\\Path` class was introduced in Symfony 5.4.
340+
341+
Dealing with file paths usually involves some difficulties:
342+
343+
- System Heterogeneity: file paths look different on different platforms. UNIX
344+
file paths start with a slash ("/"), while Windows file paths start with a
345+
system drive ("C:"). UNIX uses forward slashes, while Windows uses backslashes
346+
by default ("").
347+
- Absolute/relative paths: web applications frequently need to deal with absolute
348+
and relative paths. Converting one to the other properly is tricky and
349+
repetitive.
350+
351+
:class:`Symfony\\Component\\Filesystem\\Path` provides utility methods to tackle
352+
those issues.
353+
354+
Canonicalization
355+
~~~~~~~~~~~~~~~~
356+
357+
*Canonicalization* is the transformation of a path into a normalized (the
358+
"canonical") format. You can canonicalize a path with :method:`Symfony\\Component\\Filesystem\\Path::canonicalize`::
359+
360+
echo Path::canonicalize('/var/www/vhost/webmozart/../config.ini');
361+
// => /var/www/vhost/config.ini
362+
363+
The following modifications happen during canonicalization:
364+
365+
- "." segments are removed;
366+
- ".." segments are resolved;
367+
- backslashes ("\") are converted into forward slashes ("/");
368+
- root paths ("/" and "C:/") always terminate with a slash;
369+
- non-root paths never terminate with a slash;
370+
- schemes (such as "phar://") are kept;
371+
- replace "~" with the user's home directory.
372+
373+
You can pass absolute paths and relative paths to :method:`Symfony\\Component\\Filesystem\\Path::canonicalize`.
374+
When a relative path is passed, ".." segments at the beginning of the path are
375+
kept::
376+
377+
echo Path::canonicalize('../uploads/../config/config.yml');
378+
// => ../config/config.yml
379+
380+
Malformed paths are returned unchanged::
381+
382+
echo Path::canonicalize('C:Programs/PHP/php.ini');
383+
// => C:Programs/PHP/php.ini
384+
385+
Converting Absolute/Relative Paths
386+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
387+
388+
Absolute/relative paths can be converted with the methods
389+
:method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute`
390+
and :method:`Symfony\\Component\\Filesystem\\Path::makeRelative`.
391+
392+
:method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute` expects a relative
393+
path and a base path to base that relative path upon::
394+
395+
echo Path::makeAbsolute('config/config.yml', '/var/www/project');
396+
// => /var/www/project/config/config.yml
397+
398+
If an absolute path is passed in the first argument, the absolute path is
399+
returned unchanged::
400+
401+
echo Path::makeAbsolute('/usr/share/lib/config.ini', '/var/www/project');
402+
// => /usr/share/lib/config.ini
403+
404+
The method resolves ".." segments, if there are any::
405+
406+
echo Path::makeAbsolute('../config/config.yml', '/var/www/project/uploads');
407+
// => /var/www/project/config/config.yml
408+
409+
This method is very useful if you want to be able to accept relative paths (for
410+
example, relative to the root directory of your project) and absolute paths at
411+
the same time.
412+
413+
:method:`Symfony\\Component\\Filesystem\\Path::makeRelative` is the inverse
414+
operation to :method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute`::
415+
416+
echo Path::makeRelative('/var/www/project/config/config.yml', '/var/www/project');
417+
// => config/config.yml
418+
419+
If the path is not within the base path, the method will prepend ".." segments
420+
as necessary::
421+
422+
echo Path::makeRelative('/var/www/project/config/config.yml', '/var/www/project/uploads');
423+
// => ../config/config.yml
424+
425+
Use :method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute` and
426+
:method:`Symfony\\Component\\Filesystem\\Path::makeRelative` to check whether a
427+
path is absolute or relative::
428+
429+
Path::isAbsolute('C:\Programs\PHP\php.ini')
430+
// => true
431+
432+
All four methods internally canonicalize the passed path.
433+
434+
Finding Longest Common Base Paths
435+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
436+
437+
When you store absolute file paths on the file system, this leads to a lot of
438+
duplicated information::
439+
440+
return array(
441+
'/var/www/vhosts/project/httpdocs/config/config.yml',
442+
'/var/www/vhosts/project/httpdocs/config/routing.yml',
443+
'/var/www/vhosts/project/httpdocs/config/services.yml',
444+
'/var/www/vhosts/project/httpdocs/images/banana.gif',
445+
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif',
446+
);
447+
448+
Especially when storing many paths, the amount of duplicated information is
449+
noticeable. You can use :method:`Symfony\\Component\\Filesystem\\Path::getLongestCommonBasePath`
450+
to check a list of paths for a common base path::
451+
452+
$paths = array(
453+
'/var/www/vhosts/project/httpdocs/config/config.yml',
454+
'/var/www/vhosts/project/httpdocs/config/routing.yml',
455+
'/var/www/vhosts/project/httpdocs/config/services.yml',
456+
'/var/www/vhosts/project/httpdocs/images/banana.gif',
457+
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif',
458+
);
459+
460+
Path::getLongestCommonBasePath($paths);
461+
// => /var/www/vhosts/project/httpdocs
462+
463+
Use this path together with :method:`Symfony\\Component\\Filesystem\\Path::makeRelative`
464+
to shorten the stored paths::
465+
466+
$bp = '/var/www/vhosts/project/httpdocs';
467+
468+
return array(
469+
$bp.'/config/config.yml',
470+
$bp.'/config/routing.yml',
471+
$bp.'/config/services.yml',
472+
$bp.'/images/banana.gif',
473+
$bp.'/uploads/images/nicer-banana.gif',
474+
);
475+
476+
:method:`Symfony\\Component\\Filesystem\\Path::getLongestCommonBasePath` always
477+
returns canonical paths.
478+
479+
Use :method:`Symfony\\Component\\Filesystem\\Path::isBasePath` to test whether a
480+
path is a base path of another path::
481+
482+
Path::isBasePath("/var/www", "/var/www/project");
483+
// => true
484+
485+
Path::isBasePath("/var/www", "/var/www/project/..");
486+
// => true
487+
488+
Path::isBasePath("/var/www", "/var/www/project/../..");
489+
// => false
490+
491+
Finding Directories/Root Directories
492+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
493+
494+
PHP offers the function :phpfunction:`dirname` to obtain the directory path of a
495+
file path. This method has a few quirks::
496+
497+
- `dirname()` does not accept backslashes on UNIX
498+
- `dirname("C:/Programs")` returns "C:", not "C:/"
499+
- `dirname("C:/")` returns ".", not "C:/"
500+
- `dirname("C:")` returns ".", not "C:/"
501+
- `dirname("Programs")` returns ".", not ""
502+
- `dirname()` does not canonicalize the result
503+
504+
:method:`Symfony\\Component\\Filesystem\\Path::getDirectory` fixes these
505+
shortcomings::
506+
507+
echo Path::getDirectory("C:\Programs");
508+
// => C:/
509+
510+
Additionally, you can use :method:`Symfony\\Component\\Filesystem\\Path::getRoot`
511+
to obtain the root of a path::
512+
513+
echo Path::getRoot("/etc/apache2/sites-available");
514+
// => /
515+
516+
echo Path::getRoot("C:\Programs\Apache\Config");
517+
// => C:/
518+
318519
Error Handling
319520
--------------
320521

0 commit comments

Comments
 (0)