Improve Filesystem class

This commit is contained in:
Matias Griese
2018-12-03 13:54:40 +02:00
parent 009db01ab9
commit 48acad3e47
3 changed files with 132 additions and 61 deletions

View File

@@ -46,7 +46,7 @@ class AbstractFile implements FileInterface
*/
public function __construct(string $filepath, Filesystem $filesystem = null)
{
$this->filesystem = $filesystem ?? new Filesystem();
$this->filesystem = $filesystem ?? Filesystem::getInstance();
$this->setFilepath($filepath);
}

View File

@@ -11,59 +11,98 @@ declare(strict_types=1);
namespace Grav\Framework\Filesystem;
class Filesystem
use Grav\Framework\Filesystem\Interfaces\FilesystemInterface;
class Filesystem implements FilesystemInterface
{
/** @var bool|null */
private $normalizeNext;
private $normalize;
/** @var static */
static protected $default;
/** @var static */
static protected $unsafe;
/** @var static */
static protected $safe;
/**
* Force paths to be normalized in the next call.
*
* Note: Normalizing option will be reset after the next method call.
*
* @return $this
* @param bool|null $normalize See $this->setNormalization()
* @return Filesystem
*/
public function unsafe()
public static function getInstance(bool $normalize = null): Filesystem
{
$this->normalizeNext = true;
if ($normalize === true) {
$instance = &static::$safe;
} elseif ($normalize === false) {
$instance = &static::$unsafe;
} else {
$instance = &static::$default;
}
return $this;
if (null === $instance) {
$instance = new static($normalize);
}
return $instance;
}
/**
* Tell that all the paths are save to be used (already normalized) in the next call.
* Always use Filesystem::getInstance() instead.
*
* Note: Normalizing option will be reset after the next method call.
*
* @return $this
* @param bool|null $normalize
*/
public function safe()
protected function __construct(bool $normalize = null)
{
$this->normalizeNext = false;
return $this;
$this->normalize = $normalize;
}
/**
* Returns parent path. Empty path is returned if there are no segments remaining.
* Set path normalization.
*
* Can be used recursively to get towards the root directory.
* Default option enables normalization for the streams only, but you can force the normalization to be either
* on or off for every path. Disabling path normalization speeds up the calls, but may cause issues if paths were
* not normalized.
*
* @param string $path
* @param int $levels
* @return string
* @throws \RuntimeException
* @param bool|null $normalize
* @return Filesystem
*/
public function setNormalization(bool $normalize = null): self
{
return static::getInstance($normalize);
}
/**
* Force all paths to be normalized.
*
* @return static
*/
public function unsafe(): self
{
return static::getInstance(true);
}
/**
* Force all paths not to be normalized (speeds up the calls if given paths are known to be normalized).
*
* @return static
*/
public function safe(): self
{
return static::getInstance(false);
}
/**
* @inheritdoc
*/
public function parent(string $path, int $levels = 1): string
{
[$scheme, $path] = $this->getSchemeAndHierarchy($path);
if ($this->normalizeNext !== false) {
if ($this->normalize !== false) {
$path = $this->normalizePathPart($path);
}
$this->normalizeNext = null;
if ($path === '') {
if ($path === '' || $path === '.') {
return '';
}
@@ -73,20 +112,10 @@ class Filesystem
}
/**
* Normalize path by cleaning up \ , /./ , // and /../
*
* @param string $path
* @return string
* @throws \RuntimeException
* @inheritdoc
*/
public function normalize(string $path): string
{
if ($this->normalizeNext === false) {
$this->normalizeNext = null;
return $path;
}
[$scheme, $path] = $this->getSchemeAndHierarchy($path);
$path = $this->normalizePathPart($path);
@@ -95,23 +124,15 @@ class Filesystem
}
/**
* Stream safe dirname() replacement.
*
* @see http://php.net/manual/en/function.dirname.php
*
* @param string $path
* @param int $levels
* @return string
* @throws \RuntimeException
* @inheritdoc
*/
public function dirname(string $path, int $levels = 1): string
{
[$scheme, $path] = $this->getSchemeAndHierarchy($path);
if ($this->normalizeNext || ($scheme && null === $this->normalizeNext)) {
if ($this->normalize || ($scheme && null === $this->normalize)) {
$path = $this->normalizePathPart($path);
}
$this->normalizeNext = null;
[$scheme, $path] = $this->dirnameInternal($scheme, $path, $levels);
@@ -119,25 +140,15 @@ class Filesystem
}
/**
* Multi-byte and stream-safe pathinfo() replacement.
*
* Replacement for pathinfo(), but stream, multibyte and cross-platform safe.
*
* @see http://www.php.net/manual/en/function.pathinfo.php
*
* @param string $path A filename or path, does not need to exist as a file
* @param int|string $options Either a PATHINFO_* constant, or a string name to return only the specified piece
*
* @return array|string
* @inheritdoc
*/
public function pathinfo(string $path, int $options = null)
{
[$scheme, $path] = $this->getSchemeAndHierarchy($path);
if ($this->normalizeNext || ($scheme && null === $this->normalizeNext)) {
if ($this->normalize || ($scheme && null === $this->normalize)) {
$path = $this->normalizePathPart($path);
}
$this->normalizeNext = null;
return $this->pathinfoInternal($scheme, $path, $options);
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
/**
* @package Grav\Framework\Filesystem
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Filesystem\Interfaces;
interface FilesystemInterface
{
/**
* Returns parent path. Empty path is returned if there are no segments remaining.
*
* Can be used recursively to get towards the root directory.
*
* @param string $path A filename or path, does not need to exist as a file
* @param int $levels The number of parent directories to go up (>= 1)
* @return string
* @throws \RuntimeException
*/
public function parent(string $path, int $levels = 1): string;
/**
* Normalize path by cleaning up \ , /./ , // and /../
*
* @param string $path A filename or path, does not need to exist as a file
* @return string
* @throws \RuntimeException
*/
public function normalize(string $path): string;
/**
* Stream-safe \dirname() replacement.
*
* @see http://php.net/manual/en/function.dirname.php
*
* @param string $path A filename or path, does not need to exist as a file
* @param int $levels The number of parent directories to go up (>= 1)
* @return string
* @throws \RuntimeException
*/
public function dirname(string $path, int $levels = 1): string;
/**
* Stream-safe \pathinfo() replacement.
*
* @see http://php.net/manual/en/function.pathinfo.php
*
* @param string $path A filename or path, does not need to exist as a file
* @param int $options A PATHINFO_* constant
*
* @return array|string
*/
public function pathinfo(string $path, int $options = null);
}