Skip to content

Commit fcc6eaa

Browse files
committed
add Filesystem::joinPath
1 parent bcc6d31 commit fcc6eaa

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

src/Symfony/Component/Filesystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* support for passing a `null` value to `Filesystem::isAbsolutePath()` is deprecated and will be removed in 5.0
8+
* `Filesystem::joinPaths()` added
89

910
4.3.0
1011
-----

src/Symfony/Component/Filesystem/Filesystem.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,30 @@ class Filesystem
2424
{
2525
private static $lastError;
2626

27+
/**
28+
* @param string[] $pathSegments
29+
*/
30+
public static function joinPaths(...$pathSegments): string
31+
{
32+
// remove empty segments
33+
$pathSegments = array_filter($pathSegments);
34+
35+
$potentialDirectorySeparators = '/\\';
36+
// keep leading separator
37+
$first = rtrim(array_shift($pathSegments), $potentialDirectorySeparators);
38+
// keep trailing separator
39+
$last = ltrim(array_pop($pathSegments), $potentialDirectorySeparators);
40+
// trim separators in between
41+
$pathSegments = array_map(function ($item) use ($potentialDirectorySeparators) {
42+
return trim($item, $potentialDirectorySeparators);
43+
}, $pathSegments);
44+
45+
array_push($pathSegments, $last);
46+
array_unshift($pathSegments, $first);
47+
48+
return implode('/', $pathSegments);
49+
}
50+
2751
/**
2852
* Copies a file.
2953
*

src/Symfony/Component/Filesystem/Tests/FilesystemTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,44 @@ public function testCopyShouldKeepExecutionPermission()
17101710
$this->assertFilePermissions(767, $targetFilePath);
17111711
}
17121712

1713+
/**
1714+
* @dataProvider providePathSegmentsForJoin
1715+
*/
1716+
public function testJoinPath(string $expectedJoinedPath, array $pathSegments): void
1717+
{
1718+
$this->assertSame($expectedJoinedPath, \Symfony\Component\Filesystem\Filesystem::joinPaths(...$pathSegments));
1719+
}
1720+
1721+
public function providePathSegmentsForJoin(): array
1722+
{
1723+
return [
1724+
'simple join' => [
1725+
'etc/init.d',
1726+
['etc', 'init.d'],
1727+
],
1728+
'keep heading and trailing separators' => [
1729+
'/etc/init.d/',
1730+
['/etc', 'init.d/'],
1731+
],
1732+
'skip empty' => [
1733+
'etc/init.d',
1734+
['', 'etc', '', '', 'init.d', ''],
1735+
],
1736+
'does not trim heading and trailing separator if respective segments are empty' => [
1737+
'/etc/init.d/',
1738+
['', '/etc', '', '', 'init.d/', ''],
1739+
],
1740+
'trims both types of separators' => [
1741+
'etc/some/other',
1742+
['etc\\', '\\some\\', '\\other'],
1743+
],
1744+
'keeps heading and trailing backslashes' => [
1745+
'\\etc/init.d\\',
1746+
['\\etc', 'init.d\\'],
1747+
],
1748+
];
1749+
}
1750+
17131751
/**
17141752
* Normalize the given path (transform each blackslash into a real directory separator).
17151753
*/

0 commit comments

Comments
 (0)