You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
2.9 KiB
PHP
122 lines
2.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Arokettu\Path;
|
|
|
|
final class RelativePath extends AbstractPath implements RelativePathInterface
|
|
{
|
|
private bool $windows;
|
|
|
|
public function __construct(string $path, bool $windows = false)
|
|
{
|
|
$this->windows = $windows;
|
|
|
|
parent::__construct($path);
|
|
}
|
|
|
|
public static function unix(string $path): self
|
|
{
|
|
return new self($path, false);
|
|
}
|
|
|
|
public static function windows(string $path): self
|
|
{
|
|
return new self($path, true);
|
|
}
|
|
|
|
/**
|
|
* @codeCoverageIgnore OS specific
|
|
*/
|
|
public static function currentOS(string $path): self
|
|
{
|
|
return new self($path, DIRECTORY_SEPARATOR === '\\');
|
|
}
|
|
|
|
/**
|
|
* @codeCoverageIgnore OS specific
|
|
*/
|
|
public static function parse(string $path): self
|
|
{
|
|
return self::currentOS($path);
|
|
}
|
|
|
|
public function isAbsolute(): bool
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public function isRelative(): bool
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected function parsePath(string $path, bool $strict): void
|
|
{
|
|
$components = explode('/', $path);
|
|
|
|
// forward slash is also a valid path separator on Windows
|
|
// just also parse backslashes
|
|
if ($this->windows) {
|
|
$components = array_merge(
|
|
...array_map(fn ($a) => explode('\\', $a), $components)
|
|
);
|
|
}
|
|
|
|
$parsedComponents = $this->normalize($components);
|
|
|
|
// absolute-ish relative path
|
|
$isRoot = \strlen($path) > 0 && ($path[0] === '/' || $this->windows && $path[0] === '\\');
|
|
if (!$isRoot) {
|
|
$parsedComponents->unshift('.');
|
|
}
|
|
|
|
$this->prefix = '';
|
|
$this->components = $parsedComponents;
|
|
}
|
|
|
|
public function isRoot(): bool
|
|
{
|
|
return $this->components->count() === 0 || $this->components[0] !== '.' && $this->components[0] !== '..';
|
|
}
|
|
|
|
public function toString(): string
|
|
{
|
|
$directorySeparator = $this->windows ? '\\' : '/';
|
|
$components = $this->components;
|
|
|
|
if ($components->count() > 1 && $components[0] === '.' && $components[1] !== '') {
|
|
$components = clone $components;
|
|
$components->shift();
|
|
}
|
|
|
|
$path = \iter\join($directorySeparator, $components);
|
|
|
|
if ($this->isRoot()) {
|
|
$path = $directorySeparator . $path;
|
|
}
|
|
|
|
return $path;
|
|
}
|
|
|
|
protected function normalizeHead(\SplDoublyLinkedList $components, bool $strict): \SplDoublyLinkedList
|
|
{
|
|
if ($this->isRoot()) {
|
|
return parent::normalizeHead($components, $strict);
|
|
}
|
|
|
|
while (!$components->isEmpty()) {
|
|
if ($components[0] === '.') {
|
|
$components->shift();
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
$components->unshift('.');
|
|
|
|
return $components;
|
|
}
|
|
}
|