Make relative

master
Anton Smirnov 1 year ago
parent 3fdcb89162
commit 6ddb3955af

@ -7,8 +7,7 @@ namespace Arokettu\Path;
interface AbsolutePathInterface extends PathInterface
{
/**
* @param static|string $path
* @return static
* @param static $targetPath
*/
public function makeRelative($path, bool $strict = false): self;
public function makeRelative(self $targetPath): RelativePathInterface;
}

@ -4,18 +4,60 @@ declare(strict_types=1);
namespace Arokettu\Path;
use Arokettu\Path\Helpers\DataTypeHelper;
/**
* @internal
*/
abstract class AbstractAbsolutePath extends AbstractPath implements AbsolutePathInterface
{
/**
* @param static|string $path
* @param bool $strict
* @return static
* @param static $targetPath
*/
public function makeRelative($path, bool $strict = false): self
public function makeRelative(AbsolutePathInterface $targetPath): RelativePathInterface
{
throw new \BadMethodCallException('not implemented');
if (\get_class($this) !== \get_class($targetPath) || $this->prefix !== $targetPath->prefix) {
throw new \InvalidArgumentException(
'You can only make relative path from paths of same type and same prefix'
);
}
// optimize if the same instance
if ($this === $targetPath || $this->components === $targetPath->components) {
return $this->buildRelative(DataTypeHelper::iterableToNewListInstance(['.']));
}
$length = min($this->components->count(), $targetPath->components->count());
for ($i = 0; $i < $length; $i++) {
if ($this->components[$i] !== $targetPath->components[$i]) {
break;
}
}
$relativeComponents = clone $targetPath->components;
// delete $i components from the beginning (common prefix)
for ($j = 0; $j < $i; $j++) {
$relativeComponents->shift();
}
// add (baseLen - $i) .. elements
$numBaseDiff = $this->components->count() - $i;
for ($j = 0; $j < $numBaseDiff; $j++) {
$relativeComponents->unshift('..');
}
$relativeComponents->unshift('.');
return $this->buildRelative($relativeComponents);
}
protected function buildRelative(\SplDoublyLinkedList $components): RelativePathInterface
{
$path = new RelativePath('.');
$path->components = $components;
return $path;
}
}

@ -6,6 +6,7 @@ namespace Arokettu\Path\Tests;
use Arokettu\Path\RelativePath;
use Arokettu\Path\UnixPath;
use Arokettu\Path\WindowsPath;
use PHPUnit\Framework\TestCase;
class UnixPathTest extends TestCase
@ -123,4 +124,57 @@ class UnixPathTest extends TestCase
$rp4 = new RelativePath('../../../../../../../../i/am/test/relative/path');
$path->resolveRelative($rp4, true);
}
public function testMakeRelative(): void
{
$paths = [
UnixPath::parse('/i/am/test/unix/path'),
UnixPath::parse('/i/am/another/unix/test/path'),
UnixPath::parse('/i/am'),
UnixPath::parse('/i/am/test/unix/path'), // different instance, same path
];
$matrix = [
[
'.',
'../../../another/unix/test/path',
'../../..',
'.',
],
[
'../../../../test/unix/path',
'.',
'../../../..',
'../../../../test/unix/path',
],
[
'test/unix/path',
'another/unix/test/path',
'.',
'test/unix/path',
],
[
'.',
'../../../another/unix/test/path',
'../../..',
'.',
],
];
foreach ($paths as $bpi => $bp) {
foreach ($paths as $tpi => $tp) {
$result = $matrix[$bpi][$tpi];
self::assertEquals($result, $bp->makeRelative($tp));
}
}
}
public function testMakeRelativeWrongType(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('You can only make relative path from paths of same type and same prefix');
UnixPath::parse('/i/am/test/unix/path')->makeRelative(WindowsPath::parse('C:\\Windows'));
}
}

Loading…
Cancel
Save