Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
|
bbef65aff7 | 3 months ago |
|
976596f4f0 | 3 months ago |
|
90e26f935e | 6 months ago |
|
21956c0788 | 9 months ago |
|
624ff1fa26 | 11 months ago |
|
02acd99856 | 2 years ago |
|
9b7d03c546 | 2 years ago |
|
c512bc3114 | 2 years ago |
|
0283f79c7b | 2 years ago |
|
844d094d49 | 2 years ago |
|
ca67c164fe | 2 years ago |
|
a49fd421d0 | 2 years ago |
|
b70f1fb0de | 2 years ago |
|
3279992be7 | 2 years ago |
|
f2e6216765 | 2 years ago |
|
bbddefc0de | 2 years ago |
|
deb4524b8f | 2 years ago |
|
9e438c2a2c | 2 years ago |
|
dce3a58477 | 2 years ago |
|
58fe768a21 | 2 years ago |
@ -1,4 +1,8 @@
|
||||
/tests export-ignore
|
||||
/.git* export-ignore
|
||||
/*.yml export-ignore
|
||||
/*.xml export-ignore
|
||||
/docs/*.py export-ignore
|
||||
/docs/*.txt export-ignore
|
||||
/docs/_* export-ignore
|
||||
/tests export-ignore
|
||||
/.git* export-ignore
|
||||
/*.yml export-ignore
|
||||
/*.xml export-ignore
|
||||
/*.xml.dist export-ignore
|
||||
|
@ -0,0 +1,63 @@
|
||||
stages:
|
||||
- test
|
||||
- report
|
||||
|
||||
cache:
|
||||
key: composer-cache
|
||||
paths:
|
||||
- .composer-cache/
|
||||
|
||||
.test:
|
||||
before_script:
|
||||
- php -v
|
||||
# install system packages
|
||||
- apt-get update && apt-get install -y git unzip
|
||||
# install extensions
|
||||
- if [ "$INSTALL_XDEBUG" -eq 1 ]; then curl --location https://github.com/FriendsOfPHP/pickle/releases/latest/download/pickle.phar --output pickle.phar; php pickle.phar install --defaults xdebug; docker-php-ext-enable xdebug; fi
|
||||
# install composer
|
||||
- php -r "copy('https://composer.github.io/installer.sig', '/tmp/composer.sig');"
|
||||
- php -r "copy('https://getcomposer.org/installer', '/tmp/composer-setup.php');"
|
||||
- php -r '$expected = file_get_contents("/tmp/composer.sig"); $actual = hash_file("sha384", "/tmp/composer-setup.php"); exit(intval(!hash_equals($expected, $actual)));'
|
||||
- php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
||||
- chmod +x /usr/local/bin/composer
|
||||
- rm /tmp/composer-setup.php /tmp/composer.sig
|
||||
# cache dependencies
|
||||
- composer config -g cache-dir "$(pwd)/.composer-cache"
|
||||
script:
|
||||
- composer update
|
||||
- vendor/bin/phpunit
|
||||
|
||||
# lowest version with lowest dependencies
|
||||
test-7.4-lowest:
|
||||
extends: .test
|
||||
stage: test
|
||||
image: php:7.4
|
||||
script:
|
||||
- composer update --prefer-lowest
|
||||
- vendor/bin/phpunit
|
||||
|
||||
# lowest version
|
||||
test-7.4:
|
||||
extends: .test
|
||||
stage: test
|
||||
image: php:7.4
|
||||
|
||||
## latest 8
|
||||
test-8:
|
||||
extends: .test
|
||||
stage: test
|
||||
image: php:8
|
||||
|
||||
# coverage
|
||||
coverage:
|
||||
variables:
|
||||
INSTALL_XDEBUG: 1
|
||||
extends: .test
|
||||
stage: report
|
||||
only:
|
||||
- master
|
||||
image: php:8.0
|
||||
script:
|
||||
- composer update
|
||||
- XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-clover coverage.xml
|
||||
- bash <(curl -s https://codecov.io/bash)
|
@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.0
|
||||
|
||||
*Nov 6, 2021*
|
||||
|
||||
Initial release
|
@ -0,0 +1,25 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © 2021 Anton Smirnov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,55 @@
|
||||
# PHP Path Library
|
||||
|
||||
[](https://packagist.org/packages/arokettu/path)
|
||||
[](https://packagist.org/packages/arokettu/path)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://gitlab.com/sandfox/php-path/-/pipelines)
|
||||
[](https://codecov.io/gl/sandfox/php-path/)
|
||||
|
||||
A PHP library to work with absolute and relative paths.
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Arokettu\Path\PathUtils;
|
||||
use Arokettu\Path\RelativePath;
|
||||
use Arokettu\Path\UrlPath;
|
||||
|
||||
// simple interface
|
||||
|
||||
PathUtils::resolveRelativePath('/some/path', '../other/path');
|
||||
// => /some/other/path
|
||||
PathUtils::makeRelativePath('/some/path', '/some/other/path');
|
||||
// => ../other/path
|
||||
|
||||
// OOP interface, more control
|
||||
|
||||
$url = UrlPath::parse('https://example.com/some/path');
|
||||
$rel = RelativePath::unix('../other/path');
|
||||
$url->resolveRelative($rel)->toString();
|
||||
// => https://example.com/some/other/path
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require arokettu/path
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Read full documentation here: <https://sandfox.dev/php/path.html>
|
||||
|
||||
Also on Read the Docs: <https://php-path.readthedocs.io/>
|
||||
|
||||
## Support
|
||||
|
||||
Please file issues on our main repo at GitLab: <https://gitlab.com/sandfox/path/-/issues>
|
||||
|
||||
## License
|
||||
|
||||
The library is available as open source under the terms of the [MIT License].
|
||||
|
||||
[MIT License]: https://opensource.org/licenses/MIT
|
@ -0,0 +1,22 @@
|
||||
<a class="sidebar-brand{% if logo %} centered{% endif %}" href="{{ pathto(master_doc) }}">
|
||||
{% block brand_content %}
|
||||
{%- if logo %}
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- if theme_light_logo and theme_dark_logo %}
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo only-light" src="{{ pathto('_static/' + theme_light_logo, 1) }}" alt="Light Logo"/>
|
||||
<img class="sidebar-logo only-dark" src="{{ pathto('_static/' + theme_dark_logo, 1) }}" alt="Dark Logo"/>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{% if not theme_sidebar_hide_name %}
|
||||
<span class="sidebar-brand-text">{{ docstitle }}</span>
|
||||
{%- endif %}
|
||||
{% endblock brand_content %}
|
||||
</a>
|
||||
|
||||
{%- if current_version -%}
|
||||
<div class="sidebar-brand">{{ current_version }}</div>
|
||||
{%- endif -%}
|
@ -0,0 +1,10 @@
|
||||
from datetime import datetime
|
||||
|
||||
project = 'Path Library'
|
||||
author = 'Anton Smirnov'
|
||||
copyright = '{} {}'.format(datetime.now().year, author)
|
||||
language = 'en'
|
||||
|
||||
html_title = project
|
||||
html_theme = 'furo'
|
||||
templates_path = ["_templates"]
|
@ -0,0 +1,73 @@
|
||||
Helper Classes
|
||||
##############
|
||||
|
||||
PathFactory
|
||||
===========
|
||||
|
||||
``parse()``
|
||||
-----------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
PathFactory::parse(
|
||||
string $path,
|
||||
array $urlSchemes = [],
|
||||
array $streamSchemes = []
|
||||
): PathInterface;
|
||||
|
||||
The ``parse`` function tries to detect the type of the given string path in the following order:
|
||||
|
||||
* Unix path
|
||||
* Windows path
|
||||
* Url/Scheme paths:
|
||||
|
||||
* If both ``$urlSchemes`` and ``$streamSchemes`` are empty, all scheme prefixed paths are parsed as URLs.
|
||||
* If at least one of the lists is non-empty, all unknown schemes throw an exception.
|
||||
* Known schemes are parsed according to which list they belong.
|
||||
* Relative path of the current OS type.
|
||||
|
||||
* Since there is no way to separate root relative path from Unix path, root relative paths are never returned.
|
||||
|
||||
All paths are returned by the ``parse()`` constructor in a non strict mode.
|
||||
|
||||
PathUtils
|
||||
=========
|
||||
|
||||
``resolveRelativePath()``
|
||||
-------------------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
PathUtils::resolveRelativePath(
|
||||
string|PathInterface $basePath,
|
||||
string|PathInterface $relativePath
|
||||
): string;
|
||||
|
||||
Resolves relative path from the base path.
|
||||
|
||||
If a string is passed: it goes through ``PathFactory::parse()``.
|
||||
|
||||
If ``relativePath`` is an absolute path, it is converted to string and returned.
|
||||
|
||||
Otherwise ``$basePath->resolveRelative($relativePath)->toString()`` is returned.
|
||||
|
||||
``makeRelativePath()``
|
||||
----------------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
PathUtils::makeRelativePath(
|
||||
string|AbsolutePathInterface $basePath,
|
||||
string|AbsolutePathInterface $targetPath
|
||||
): string;
|
||||
|
||||
Makes relative path from two absolute paths.
|
||||
|
||||
If a string is passed: it goes through ``PathFactory::parse()``.
|
||||
|
||||
If any of the paths is a relative path, an exception is thrown.
|
||||
|
||||
Otherwise ``$basePath->makeRelative($targetPath)->toString()`` is returned.
|
@ -0,0 +1,41 @@
|
||||
Path Library
|
||||
############
|
||||
|
||||
|Packagist| |GitLab| |GitHub| |Bitbucket| |Gitea|
|
||||
|
||||
A PHP library to work with absolute and relative paths.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
composer require arokettu/path
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
path_interfaces
|
||||
path_classes
|
||||
helper_classes
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
The library is available as open source under the terms of the `MIT License`_.
|
||||
|
||||
.. _MIT License: https://opensource.org/licenses/MIT
|
||||
|
||||
.. |Packagist| image:: https://img.shields.io/packagist/v/arokettu/path.svg?style=flat-square
|
||||
:target: https://packagist.org/packages/arokettu/path
|
||||
.. |GitHub| image:: https://img.shields.io/badge/get%20on-GitHub-informational.svg?style=flat-square&logo=github
|
||||
:target: https://github.com/arokettu/php-path
|
||||
.. |GitLab| image:: https://img.shields.io/badge/get%20on-GitLab-informational.svg?style=flat-square&logo=gitlab
|
||||
:target: https://gitlab.com/sandfox/php-path
|
||||
.. |Bitbucket| image:: https://img.shields.io/badge/get%20on-Bitbucket-informational.svg?style=flat-square&logo=bitbucket
|
||||
:target: https://bitbucket.org/sandfox/php-path
|
||||
.. |Gitea| image:: https://img.shields.io/badge/get%20on-Gitea-informational.svg?style=flat-square&logo=gitea
|
||||
:target: https://sandfox.org/sandfox/php-path
|
@ -0,0 +1,159 @@
|
||||
Path Classes
|
||||
############
|
||||
|
||||
RelativePath
|
||||
============
|
||||
|
||||
The only concrete implementation of ``RelativePathInterface``.
|
||||
In non-root relative paths first component returned by ``getComponents()`` is either ``'.'`` or ``'..'``.
|
||||
|
||||
When resolving relative, windows-ness of the resulting relative will be inherited from the base path.
|
||||
|
||||
Available constructors:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
new RelativePath(string $path, bool $windows = false);
|
||||
|
||||
``$windows = false``: Unix-like path. Path separators are slashes.
|
||||
|
||||
``$windows = true``: Windows-like path. Path separators are both slashes and backslashes.
|
||||
When exporting a string, backslashes are used.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
RelativePath::unix(string $path): self;
|
||||
|
||||
Same as ``new RelativePath($path, windows: false)``
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
RelativePath::windows(string $path): self;
|
||||
|
||||
Same as ``new RelativePath($path, windows: true)``
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
RelativePath::currentOS(string $path): self;
|
||||
|
||||
If Windows is detected, create a Windows-like path, otherwise create Unix-like path.
|
||||
|
||||
.. note:: Windows is detected by the ``DIRECTORY_SEPARATOR`` constant.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
RelativePath::parse(string $path): self;
|
||||
|
||||
Alias of ``currentOS()``.
|
||||
|
||||
FilesystemPath
|
||||
==============
|
||||
|
||||
A base class for ``UnixPath`` and ``WindowsPath``.
|
||||
|
||||
No default constructor, only a named constructor is available:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
FilesystemPath::parse(string $path, bool $strict = false): self;
|
||||
|
||||
If Windows is detected, create a Windows path, otherwise create a Unix path.
|
||||
Strict mode does not allow to have relative components that traverse beyond root.
|
||||
|
||||
.. note:: Windows is detected by the ``DIRECTORY_SEPARATOR`` constant.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Arokettu\Path\FilesystemPath;
|
||||
|
||||
// on windows
|
||||
FilesystemPath::parse('C:\Windows\..\..\..\Users'); // C:\Users
|
||||
FilesystemPath::parse('C:\Windows\..\..\..\Users' strict: true); // exception
|
||||
|
||||
UnixPath
|
||||
--------
|
||||
|
||||
A class for Unix paths.
|
||||
The prefix is ``'/'``
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// these are equal
|
||||
new UnixPath(string $path, bool $strict = false);
|
||||
UnixPath::parse(string $path, bool $strict = false): self;
|
||||
|
||||
WindowsPath
|
||||
-----------
|
||||
|
||||
.. warning::
|
||||
Windows usually have much more restrictions on file path than unix-like operating systems
|
||||
like forbidding characters like ``|`` and ``:``.
|
||||
The library doesn't check for that even in strict mode.
|
||||
|
||||
A class for Windows paths.
|
||||
``makeRelative()`` returns relatives of the Windows-like type.
|
||||
|
||||
Supported paths:
|
||||
|
||||
* DOS-like paths.
|
||||
The classic paths with a drive letter: ``C:\Path``.
|
||||
Both slashes and backslashes are supported as component separators.
|
||||
Relative components are resolved on creation like in most other classes here.
|
||||
The prefix here is a drive letter.
|
||||
* UNC paths.
|
||||
Examples:
|
||||
|
||||
* Local paths like ``\\*\C:\Path``. The prefix here is ``\\*\C:\``.
|
||||
* Network paths like ``\\AROKETTUPC\c$``. The prefix here is ``\\AROKETTUPC\``.
|
||||
|
||||
UNC paths do not allow forward slashes and relative components.
|
||||
|
||||
.. note::
|
||||
Relative paths with drive letter like ``C:Path\Path`` are valid in Windows
|
||||
but are not supported by the library in any way.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// these are equal
|
||||
new WindowsPath(string $path, bool $strict = false);
|
||||
WindowsPath::parse(string $path, bool $strict = false): self;
|
||||
|
||||
UrlPath
|
||||
=======
|
||||
|
||||
A class for URL paths.
|
||||
The prefix is scheme + hostname.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// these are equal
|
||||
new UrlPath(string $path, bool $strict = false);
|
||||
UrlPath::parse(string $path, bool $strict = false): self;
|
||||
|
||||
StreamPath
|
||||
==========
|
||||
|
||||
A class for PHP stream like paths.
|
||||
Examples include php streams like ``php://temp``.
|
||||
It can be useful with libraries that create virtual file systems like `adlawson/vfs`_ and `mikey179/vfsstream`_.
|
||||
The prefix is scheme.
|
||||
|
||||
.. _adlawson/vfs: https://packagist.org/packages/adlawson/vfs
|
||||
.. _mikey179/vfsstream: https://packagist.org/packages/mikey179/vfsstream
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// these are equal
|
||||
new StreamPath(string $path, bool $strict = false);
|
||||
StreamPath::parse(string $path, bool $strict = false): self;
|
@ -0,0 +1,131 @@
|
||||
Path Interfaces
|
||||
###############
|
||||
|
||||
PathInterface
|
||||
=============
|
||||
|
||||
``resolveRelative()``
|
||||
---------------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
public function resolveRelative(RelativePathInterface $path, bool $strict = false): self;
|
||||
|
||||
Convert relative path to absolute or combine two relative paths using the caller object as base.
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Arokettu\Path\RelativePath;
|
||||
use Arokettu\Path\UnixPath;
|
||||
|
||||
$path = UnixPath::parse('/some/path');
|
||||
$rel1 = RelativePath::parse('../other/path');
|
||||
// trailing slashes are preserved
|
||||
$rel2 = RelativePath::parse('../diff/path/');
|
||||
|
||||
$path->resolveRelative($rel1); // /some/other/path
|
||||
// trailing slash will be present if target path has it
|
||||
$rel1->resolveRelative($rel2); // ../other/diff/path/
|
||||
|
||||
Strict mode throws exception if traversal happens beyond root (no effect if the base path is relative):
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Arokettu\Path\RelativePath;
|
||||
use Arokettu\Path\UnixPath;
|
||||
|
||||
$path = UnixPath::parse('/some/path');
|
||||
$rel = RelativePath::parse('../../../../etc/passwd');
|
||||
|
||||
$path->resolveRelative($rel); // /etc/passwd
|
||||
$path->resolveRelative($rel, strict: true); // exception
|
||||
|
||||
``getPrefix()``
|
||||
---------------
|
||||
|
||||
Path prefix that you can't traverse beyond like root unix path, windows drive path (C:\\), and url hostname.
|
||||
|
||||
``getComponents()``
|
||||
-------------------
|
||||
|
||||
An array of path components excluding prefix.
|
||||
The last component of the path is empty string if path has trailing (back)slash
|
||||
|
||||
``isAbsolute()``
|
||||
----------------
|
||||
|
||||
``true`` for instances of ``AbsolutePathInterface``.
|
||||
``false`` for instances of ``RelativePathInterface``.
|
||||
|
||||
``isRelative()``
|
||||
----------------
|
||||
|
||||
``false`` for instances of ``AbsolutePathInterface``.
|
||||
``true`` for instances of ``RelativePathInterface``.
|
||||
|
||||
``toString()`` & ``__toString()``
|
||||
---------------------------------
|
||||
|
||||
Get string value of the path.
|
||||
|
||||
AbsolutePathInterface
|
||||
=====================
|
||||
|
||||
``makeRelative()``
|
||||
------------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
public function makeRelative(self $targetPath, ?\Closure $equals = null): RelativePathInterface;
|
||||
|
||||
Make relative path from base path and target path of the same type having equal prefixes.
|
||||
The paths are treated as case sensitive unless ``$equals`` callback is provided.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Arokettu\Path\UnixPath;
|
||||
use Arokettu\Path\UrlPath;
|
||||
use Arokettu\Path\WindowsPath;
|
||||
|
||||
$path1 = UnixPath::parse('/home/arokettu');
|
||||
$path2 = UnixPath::parse('/home/sandfox/');
|
||||
// there will be a trailing slash if target path has it
|
||||
$path1->makeRelative($path2); // ../sandfox/
|
||||
|
||||
// ignore case on Windows
|
||||
$path1 = WindowsPath::parse('c:\users\arokettu');
|
||||
$path2 = WindowsPath::parse('C:\Users\SandFox');
|
||||
$path1->makeRelative(
|
||||
$path2,
|
||||
fn ($a, $b) => strtoupper($a) === strtoupper($b)
|
||||
); // ..\SandFox
|
||||
|
||||
// resolve urlencoded url path
|
||||
$path1 = UrlPath::parse('https://example.com/some%20path/child%20dir');
|
||||
$path2 = UrlPath::parse('https://example.com/some path/child dir');
|
||||
$path1->makeRelative(
|
||||
$path2,
|
||||
fn ($a, $b) => urldecode($a) === urldecode($b)
|
||||
); // .
|
||||
|
||||
RelativePathInterface
|
||||
=====================
|
||||
|
||||
``isRoot()``
|
||||
------------
|
||||
|
||||
``true`` if the relative path is 'root path', i.e. full path excluding prefix.
|
||||
Examples:
|
||||
|
||||
* ``\Users\SandFox`` for Windows path ``C:\Users\SandFox``
|
||||
* ``/some path/child dir`` for UrlPath ``https://example.com/some path/child dir``
|
||||
* Functionally equal to Unix path
|
||||
|
||||
When applying root path in ``resolveRelative()``, it replaces the whole path excluding prefix.
|
@ -0,0 +1 @@
|
||||
furo
|
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Arokettu\Path;
|
||||
|
||||
final class PathUtils
|
||||
{
|
||||
/**
|
||||
* @param string|PathInterface $basePath
|
||||
* @param string|PathInterface $relativePath
|
||||
* @return string
|
||||
*/
|
||||
public static function resolveRelativePath($basePath, $relativePath): string
|
||||
{
|
||||
if (\is_string($basePath)) {
|
||||
$basePath = PathFactory::parse($basePath);
|
||||
}
|
||||
|
||||
if (\is_string($relativePath)) {
|
||||
$relativePath = PathFactory::parse($relativePath);
|
||||
}
|
||||
|
||||
if (!($basePath instanceof PathInterface)) {
|
||||
throw new \InvalidArgumentException('basePath must be a string or an instance of PathInterface');
|
||||
}
|
||||
|
||||
if ($relativePath instanceof RelativePathInterface) {
|
||||
return $basePath->resolveRelative($relativePath)->toString();
|
||||
} elseif ($relativePath instanceof AbsolutePathInterface) {
|
||||
return $relativePath->toString();
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('relativePath must be a string or an instance of PathInterface');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|AbsolutePathInterface $basePath
|
||||
* @param string|AbsolutePathInterface $targetPath
|
||||
* @return string
|
||||
*/
|
||||
public static function makeRelativePath($basePath, $targetPath): string
|
||||
{
|
||||
if (\is_string($basePath)) {
|
||||
$basePath = PathFactory::parse($basePath);
|
||||
}
|
||||
|
||||
if (\is_string($targetPath)) {
|
||||
$targetPath = PathFactory::parse($targetPath);
|
||||
}
|
||||
|
||||
if (!($basePath instanceof AbsolutePathInterface) || !$basePath->isAbsolute()) {
|
||||
throw new \InvalidArgumentException(
|
||||
'basePath must be a string containing absolute path or an instance of AbsolutePathInterface'
|
||||
);
|
||||
}
|
||||
|
||||
if (!($targetPath instanceof AbsolutePathInterface) || !$targetPath->isAbsolute()) {
|
||||
throw new \InvalidArgumentException(
|
||||
'targetPath must be a string containing absolute path or an instance of AbsolutePathInterface'
|
||||
);
|
||||
}
|
||||
|
||||
return $basePath->makeRelative($targetPath)->toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Arokettu\Path\Tests;
|
||||
|
||||
use Arokettu\Path\PathUtils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PathUtilsTest extends TestCase
|
||||
{
|
||||
public function testMakeRelative(): void
|
||||
{
|
||||
self::assertEquals(
|
||||
'../../.config/composer',
|
||||
PathUtils::makeRelativePath(
|
||||
'/home/arokettu/tmp/test',
|
||||
'/home/arokettu/.config/composer',
|
||||
),
|
||||
);
|
||||
|
||||
self::assertEquals(
|
||||
'..\..\AppData\Roaming',
|
||||
PathUtils::makeRelativePath(
|
||||
'C:\Users\Arokettu\tmp\test',
|
||||
'C:\Users\Arokettu\AppData\Roaming',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function testResolveRelative(): void
|
||||
{
|
||||
// any, absolute
|
||||
self::assertEquals(
|
||||
'/home/arokettu/.config/composer',
|
||||
PathUtils::resolveRelativePath(
|
||||
'/home/arokettu/tmp/test',
|
||||
'/home/arokettu/.config/composer',
|
||||
),
|
||||
);
|
||||
|
||||
// absolute, relative
|
||||
self::assertEquals(
|
||||
'/home/arokettu/.config/composer',
|
||||
PathUtils::resolveRelativePath(
|
||||
'/home/arokettu/tmp/test',
|
||||
'../../.config/composer',
|
||||
),
|
||||
);
|
||||
|
||||
// relative, relative
|
||||
self::assertEquals(
|
||||
'.config/composer',
|
||||
PathUtils::resolveRelativePath(
|
||||
'./tmp/test',
|
||||
'../../.config/composer',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue