merged branch aharonp/master (PR #4842)

Commits
-------

6def8d1 Refactored Filesystem::makePathRelative function to correctly handle more use-cases

Discussion
----------

Refactored the makePathRelative function

The function was failing in a number of different use cases because the function was incorrectly using a character offset comparison to determine where the common path stops.

I've fixed this by splitting up the paths into their individual directories and then comparing the directory names.

If the paths match then the function will return `./` and not an empty string. This is for consistency sake, to ensure all returned paths end with `/`.
This commit is contained in:
Fabien Potencier 2012-07-11 08:24:17 +02:00
commit bfda8a3c29
2 changed files with 30 additions and 7 deletions

View File

@ -302,21 +302,28 @@ class Filesystem
$startPath = strtr($startPath, '\\', '/');
}
// Find for which character the the common path stops
$offset = 0;
while (isset($startPath[$offset]) && isset($endPath[$offset]) && $startPath[$offset] === $endPath[$offset]) {
$offset++;
// Split the paths into arrays
$startPathArr = explode('/', trim($startPath, '/'));
$endPathArr = explode('/', trim($endPath, '/'));
// Find for which directory the common path stops
$index = 0;
while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
$index++;
}
// Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
$diffPath = trim(substr($startPath, $offset), '/');
$depth = strlen($diffPath) > 0 ? substr_count($diffPath, '/') + 1 : 0;
$depth = count($startPathArr) - $index;
// Repeated "../" for each level need to reach the common path
$traverser = str_repeat('../', $depth);
$endPathRemainder = implode('/', array_slice($endPathArr, $index));
// Construct $endPath from traversing to the common path, then to the remaining $endPath
return $traverser.substr($endPath, $offset);
$relativePath = $traverser . (strlen($endPathRemainder) > 0 ? $endPathRemainder . '/' : '');
return (strlen($relativePath) === 0) ? './' : $relativePath;
}
/**

View File

@ -733,6 +733,22 @@ class FilesystemTest extends \PHPUnit_Framework_TestCase
array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
array('/aa/bb', '/aa/bb', './'),
array('/aa/bb', '/aa/bb/', './'),
array('/aa/bb/', '/aa/bb', './'),
array('/aa/bb/', '/aa/bb/', './'),
array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
array('/aa/bb/cc', '/aa', 'bb/cc/'),
array('/aa/bb/cc', '/aa/', 'bb/cc/'),
array('/aa/bb/cc/', '/aa', 'bb/cc/'),
array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
array('/a/aab/bb', '/a/aa', '../aab/bb/'),
array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
);
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {