mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-12 03:01:32 +00:00
Import latest app updates from streamline
An updated set of source files and initialization was provided by streamline to address issues observed during initial testing. These files have been updated in order to generate a new set of app images.
This commit is contained in:
-61
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* CustomFilterIterator filters files by applying anonymous functions.
|
||||
*
|
||||
* The anonymous function receives a \SplFileInfo and must return false
|
||||
* to remove files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends \FilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
class CustomFilterIterator extends \FilterIterator
|
||||
{
|
||||
private array $filters = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, \SplFileInfo> $iterator The Iterator to filter
|
||||
* @param callable[] $filters An array of PHP callbacks
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $filters)
|
||||
{
|
||||
foreach ($filters as $filter) {
|
||||
if (!\is_callable($filter)) {
|
||||
throw new \InvalidArgumentException('Invalid PHP callback.');
|
||||
}
|
||||
}
|
||||
$this->filters = $filters;
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
$fileinfo = $this->current();
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
if (false === $filter($fileinfo)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\Comparator\DateComparator;
|
||||
|
||||
/**
|
||||
* DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends \FilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
class DateRangeFilterIterator extends \FilterIterator
|
||||
{
|
||||
private array $comparators = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, \SplFileInfo> $iterator
|
||||
* @param DateComparator[] $comparators
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $comparators)
|
||||
{
|
||||
$this->comparators = $comparators;
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
$fileinfo = $this->current();
|
||||
|
||||
if (!file_exists($fileinfo->getPathname())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$filedate = $fileinfo->getMTime();
|
||||
foreach ($this->comparators as $compare) {
|
||||
if (!$compare->test($filedate)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* DepthRangeFilterIterator limits the directory depth.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @template-covariant TKey
|
||||
* @template-covariant TValue
|
||||
*
|
||||
* @extends \FilterIterator<TKey, TValue>
|
||||
*/
|
||||
class DepthRangeFilterIterator extends \FilterIterator
|
||||
{
|
||||
private int $minDepth = 0;
|
||||
|
||||
/**
|
||||
* @param \RecursiveIteratorIterator<\RecursiveIterator<TKey, TValue>> $iterator The Iterator to filter
|
||||
* @param int $minDepth The min depth
|
||||
* @param int $maxDepth The max depth
|
||||
*/
|
||||
public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \PHP_INT_MAX)
|
||||
{
|
||||
$this->minDepth = $minDepth;
|
||||
$iterator->setMaxDepth(\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
|
||||
}
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
/**
|
||||
* ExcludeDirectoryFilterIterator filters out directories.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends \FilterIterator<string, SplFileInfo>
|
||||
*
|
||||
* @implements \RecursiveIterator<string, SplFileInfo>
|
||||
*/
|
||||
class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
|
||||
{
|
||||
/** @var \Iterator<string, SplFileInfo> */
|
||||
private \Iterator $iterator;
|
||||
private bool $isRecursive;
|
||||
/** @var array<string, true> */
|
||||
private array $excludedDirs = [];
|
||||
private ?string $excludedPattern = null;
|
||||
/** @var list<callable(SplFileInfo):bool> */
|
||||
private array $pruneFilters = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, SplFileInfo> $iterator The Iterator to filter
|
||||
* @param list<string|callable(SplFileInfo):bool> $directories An array of directories to exclude
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $directories)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
$this->isRecursive = $iterator instanceof \RecursiveIterator;
|
||||
$patterns = [];
|
||||
foreach ($directories as $directory) {
|
||||
if (!\is_string($directory)) {
|
||||
if (!\is_callable($directory)) {
|
||||
throw new \InvalidArgumentException('Invalid PHP callback.');
|
||||
}
|
||||
|
||||
$this->pruneFilters[] = $directory;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$directory = rtrim($directory, '/');
|
||||
if (!$this->isRecursive || str_contains($directory, '/')) {
|
||||
$patterns[] = preg_quote($directory, '#');
|
||||
} else {
|
||||
$this->excludedDirs[$directory] = true;
|
||||
}
|
||||
}
|
||||
if ($patterns) {
|
||||
$this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
|
||||
}
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->excludedPattern) {
|
||||
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
return !preg_match($this->excludedPattern, $path);
|
||||
}
|
||||
|
||||
if ($this->pruneFilters && $this->hasChildren()) {
|
||||
foreach ($this->pruneFilters as $pruneFilter) {
|
||||
if (!$pruneFilter($this->current())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hasChildren(): bool
|
||||
{
|
||||
return $this->isRecursive && $this->iterator->hasChildren();
|
||||
}
|
||||
|
||||
public function getChildren(): self
|
||||
{
|
||||
$children = new self($this->iterator->getChildren(), []);
|
||||
$children->excludedDirs = $this->excludedDirs;
|
||||
$children->excludedPattern = $this->excludedPattern;
|
||||
|
||||
return $children;
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* FileTypeFilterIterator only keeps files, directories, or both.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends \FilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
class FileTypeFilterIterator extends \FilterIterator
|
||||
{
|
||||
public const ONLY_FILES = 1;
|
||||
public const ONLY_DIRECTORIES = 2;
|
||||
|
||||
private int $mode;
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, \SplFileInfo> $iterator The Iterator to filter
|
||||
* @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, int $mode)
|
||||
{
|
||||
$this->mode = $mode;
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
$fileinfo = $this->current();
|
||||
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
|
||||
return false;
|
||||
} elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
/**
|
||||
* FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
||||
*
|
||||
* @extends MultiplePcreFilterIterator<string, SplFileInfo>
|
||||
*/
|
||||
class FilecontentFilterIterator extends MultiplePcreFilterIterator
|
||||
{
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
if (!$this->matchRegexps && !$this->noMatchRegexps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fileinfo = $this->current();
|
||||
|
||||
if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $fileinfo->getContents();
|
||||
if (!$content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isAccepted($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to regexp if necessary.
|
||||
*
|
||||
* @param string $str Pattern: string or regexp
|
||||
*/
|
||||
protected function toRegex(string $str): string
|
||||
{
|
||||
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\Glob;
|
||||
|
||||
/**
|
||||
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends MultiplePcreFilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
class FilenameFilterIterator extends MultiplePcreFilterIterator
|
||||
{
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
return $this->isAccepted($this->current()->getFilename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts glob to regexp.
|
||||
*
|
||||
* PCRE patterns are left unchanged.
|
||||
* Glob strings are transformed with Glob::toRegex().
|
||||
*
|
||||
* @param string $str Pattern: glob or regexp
|
||||
*/
|
||||
protected function toRegex(string $str): string
|
||||
{
|
||||
return $this->isRegex($str) ? $str : Glob::toRegex($str);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LazyIterator implements \IteratorAggregate
|
||||
{
|
||||
private \Closure $iteratorFactory;
|
||||
|
||||
public function __construct(callable $iteratorFactory)
|
||||
{
|
||||
$this->iteratorFactory = $iteratorFactory(...);
|
||||
}
|
||||
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
yield from ($this->iteratorFactory)();
|
||||
}
|
||||
}
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @template-covariant TKey
|
||||
* @template-covariant TValue
|
||||
*
|
||||
* @extends \FilterIterator<TKey, TValue>
|
||||
*/
|
||||
abstract class MultiplePcreFilterIterator extends \FilterIterator
|
||||
{
|
||||
protected $matchRegexps = [];
|
||||
protected $noMatchRegexps = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<TKey, TValue> $iterator The Iterator to filter
|
||||
* @param string[] $matchPatterns An array of patterns that need to match
|
||||
* @param string[] $noMatchPatterns An array of patterns that need to not match
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
|
||||
{
|
||||
foreach ($matchPatterns as $pattern) {
|
||||
$this->matchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
foreach ($noMatchPatterns as $pattern) {
|
||||
$this->noMatchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the string is accepted by the regex filters.
|
||||
*
|
||||
* If there is no regexps defined in the class, this method will accept the string.
|
||||
* Such case can be handled by child classes before calling the method if they want to
|
||||
* apply a different behavior.
|
||||
*/
|
||||
protected function isAccepted(string $string): bool
|
||||
{
|
||||
// should at least not match one rule to exclude
|
||||
foreach ($this->noMatchRegexps as $regex) {
|
||||
if (preg_match($regex, $string)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// should at least match one rule
|
||||
if ($this->matchRegexps) {
|
||||
foreach ($this->matchRegexps as $regex) {
|
||||
if (preg_match($regex, $string)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no match rules, the file is accepted
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the string is a regex.
|
||||
*/
|
||||
protected function isRegex(string $str): bool
|
||||
{
|
||||
$availableModifiers = 'imsxuADU';
|
||||
|
||||
if (\PHP_VERSION_ID >= 80200) {
|
||||
$availableModifiers .= 'n';
|
||||
}
|
||||
|
||||
if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) {
|
||||
$start = substr($m[1], 0, 1);
|
||||
$end = substr($m[1], -1);
|
||||
|
||||
if ($start === $end) {
|
||||
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
|
||||
}
|
||||
|
||||
foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
|
||||
if ($start === $delimiters[0] && $end === $delimiters[1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string into regexp.
|
||||
*/
|
||||
abstract protected function toRegex(string $str): string;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
/**
|
||||
* PathFilterIterator filters files by path patterns (e.g. some/special/dir).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
||||
*
|
||||
* @extends MultiplePcreFilterIterator<string, SplFileInfo>
|
||||
*/
|
||||
class PathFilterIterator extends MultiplePcreFilterIterator
|
||||
{
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
$filename = $this->current()->getRelativePathname();
|
||||
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$filename = str_replace('\\', '/', $filename);
|
||||
}
|
||||
|
||||
return $this->isAccepted($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts strings to regexp.
|
||||
*
|
||||
* PCRE patterns are left unchanged.
|
||||
*
|
||||
* Default conversion:
|
||||
* 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
|
||||
*
|
||||
* Use only / as directory separator (on Windows also).
|
||||
*
|
||||
* @param string $str Pattern: regexp or dirname
|
||||
*/
|
||||
protected function toRegex(string $str): string
|
||||
{
|
||||
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
||||
}
|
||||
}
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
/**
|
||||
* Extends the \RecursiveDirectoryIterator to support relative paths.
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*
|
||||
* @extends \RecursiveDirectoryIterator<string, SplFileInfo>
|
||||
*/
|
||||
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||
{
|
||||
private bool $ignoreUnreadableDirs;
|
||||
private bool $ignoreFirstRewind = true;
|
||||
|
||||
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
|
||||
private string $rootPath;
|
||||
private string $subPath;
|
||||
private string $directorySeparator = '/';
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
|
||||
{
|
||||
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
|
||||
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
|
||||
}
|
||||
|
||||
parent::__construct($path, $flags);
|
||||
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
||||
$this->rootPath = $path;
|
||||
if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
|
||||
$this->directorySeparator = \DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of SplFileInfo with support for relative paths.
|
||||
*/
|
||||
public function current(): SplFileInfo
|
||||
{
|
||||
// the logic here avoids redoing the same work in all iterations
|
||||
|
||||
if (!isset($this->subPath)) {
|
||||
$this->subPath = $this->getSubPath();
|
||||
}
|
||||
$subPathname = $this->subPath;
|
||||
if ('' !== $subPathname) {
|
||||
$subPathname .= $this->directorySeparator;
|
||||
}
|
||||
$subPathname .= $this->getFilename();
|
||||
|
||||
if ('/' !== $basePath = $this->rootPath) {
|
||||
$basePath .= $this->directorySeparator;
|
||||
}
|
||||
|
||||
return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
|
||||
}
|
||||
|
||||
public function hasChildren(bool $allowLinks = false): bool
|
||||
{
|
||||
$hasChildren = parent::hasChildren($allowLinks);
|
||||
|
||||
if (!$hasChildren || !$this->ignoreUnreadableDirs) {
|
||||
return $hasChildren;
|
||||
}
|
||||
|
||||
try {
|
||||
parent::getChildren();
|
||||
|
||||
return true;
|
||||
} catch (\UnexpectedValueException) {
|
||||
// If directory is unreadable and finder is set to ignore it, skip children
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
public function getChildren(): \RecursiveDirectoryIterator
|
||||
{
|
||||
try {
|
||||
$children = parent::getChildren();
|
||||
|
||||
if ($children instanceof self) {
|
||||
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
|
||||
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
|
||||
|
||||
// performance optimization to avoid redoing the same work in all children
|
||||
$children->rootPath = $this->rootPath;
|
||||
}
|
||||
|
||||
return $children;
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function next(): void
|
||||
{
|
||||
$this->ignoreFirstRewind = false;
|
||||
|
||||
parent::next();
|
||||
}
|
||||
|
||||
public function rewind(): void
|
||||
{
|
||||
// some streams like FTP are not rewindable, ignore the first rewind after creation,
|
||||
// as newly created DirectoryIterator does not need to be rewound
|
||||
if ($this->ignoreFirstRewind) {
|
||||
$this->ignoreFirstRewind = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
parent::rewind();
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\Comparator\NumberComparator;
|
||||
|
||||
/**
|
||||
* SizeRangeFilterIterator filters out files that are not in the given size range.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @extends \FilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
class SizeRangeFilterIterator extends \FilterIterator
|
||||
{
|
||||
private array $comparators = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, \SplFileInfo> $iterator
|
||||
* @param NumberComparator[] $comparators
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $comparators)
|
||||
{
|
||||
$this->comparators = $comparators;
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*/
|
||||
public function accept(): bool
|
||||
{
|
||||
$fileinfo = $this->current();
|
||||
if (!$fileinfo->isFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$filesize = $fileinfo->getSize();
|
||||
foreach ($this->comparators as $compare) {
|
||||
if (!$compare->test($filesize)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
/**
|
||||
* SortableIterator applies a sort on a given Iterator.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @implements \IteratorAggregate<string, \SplFileInfo>
|
||||
*/
|
||||
class SortableIterator implements \IteratorAggregate
|
||||
{
|
||||
public const SORT_BY_NONE = 0;
|
||||
public const SORT_BY_NAME = 1;
|
||||
public const SORT_BY_TYPE = 2;
|
||||
public const SORT_BY_ACCESSED_TIME = 3;
|
||||
public const SORT_BY_CHANGED_TIME = 4;
|
||||
public const SORT_BY_MODIFIED_TIME = 5;
|
||||
public const SORT_BY_NAME_NATURAL = 6;
|
||||
public const SORT_BY_NAME_CASE_INSENSITIVE = 7;
|
||||
public const SORT_BY_NAME_NATURAL_CASE_INSENSITIVE = 8;
|
||||
public const SORT_BY_EXTENSION = 9;
|
||||
public const SORT_BY_SIZE = 10;
|
||||
|
||||
/** @var \Traversable<string, \SplFileInfo> */
|
||||
private \Traversable $iterator;
|
||||
private \Closure|int $sort;
|
||||
|
||||
/**
|
||||
* @param \Traversable<string, \SplFileInfo> $iterator
|
||||
* @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(\Traversable $iterator, int|callable $sort, bool $reverseOrder = false)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
$order = $reverseOrder ? -1 : 1;
|
||||
|
||||
if (self::SORT_BY_NAME === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||
} elseif (self::SORT_BY_NAME_NATURAL === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||
} elseif (self::SORT_BY_NAME_CASE_INSENSITIVE === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||
} elseif (self::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||
} elseif (self::SORT_BY_TYPE === $sort) {
|
||||
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||
if ($a->isDir() && $b->isFile()) {
|
||||
return -$order;
|
||||
} elseif ($a->isFile() && $b->isDir()) {
|
||||
return $order;
|
||||
}
|
||||
|
||||
return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||
};
|
||||
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getATime() - $b->getATime());
|
||||
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getCTime() - $b->getCTime());
|
||||
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getMTime() - $b->getMTime());
|
||||
} elseif (self::SORT_BY_EXTENSION === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcmp($a->getExtension(), $b->getExtension());
|
||||
} elseif (self::SORT_BY_SIZE === $sort) {
|
||||
$this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getSize() - $b->getSize());
|
||||
} elseif (self::SORT_BY_NONE === $sort) {
|
||||
$this->sort = $order;
|
||||
} elseif (\is_callable($sort)) {
|
||||
$this->sort = $reverseOrder ? static fn (\SplFileInfo $a, \SplFileInfo $b) => -$sort($a, $b) : $sort(...);
|
||||
} else {
|
||||
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
if (1 === $this->sort) {
|
||||
return $this->iterator;
|
||||
}
|
||||
|
||||
$array = iterator_to_array($this->iterator, true);
|
||||
|
||||
if (-1 === $this->sort) {
|
||||
$array = array_reverse($array);
|
||||
} else {
|
||||
uasort($array, $this->sort);
|
||||
}
|
||||
|
||||
return new \ArrayIterator($array);
|
||||
}
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Finder\Iterator;
|
||||
|
||||
use Symfony\Component\Finder\Gitignore;
|
||||
|
||||
/**
|
||||
* @extends \FilterIterator<string, \SplFileInfo>
|
||||
*/
|
||||
final class VcsIgnoredFilterIterator extends \FilterIterator
|
||||
{
|
||||
private string $baseDir;
|
||||
|
||||
/**
|
||||
* @var array<string, array{0: string, 1: string}|null>
|
||||
*/
|
||||
private array $gitignoreFilesCache = [];
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private array $ignoredPathsCache = [];
|
||||
|
||||
/**
|
||||
* @param \Iterator<string, \SplFileInfo> $iterator
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, string $baseDir)
|
||||
{
|
||||
$this->baseDir = $this->normalizePath($baseDir);
|
||||
|
||||
foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) {
|
||||
if (@is_dir("{$parentDirectory}/.git")) {
|
||||
$this->baseDir = $parentDirectory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
public function accept(): bool
|
||||
{
|
||||
$file = $this->current();
|
||||
|
||||
$fileRealPath = $this->normalizePath($file->getRealPath());
|
||||
|
||||
return !$this->isIgnored($fileRealPath);
|
||||
}
|
||||
|
||||
private function isIgnored(string $fileRealPath): bool
|
||||
{
|
||||
if (is_dir($fileRealPath) && !str_ends_with($fileRealPath, '/')) {
|
||||
$fileRealPath .= '/';
|
||||
}
|
||||
|
||||
if (isset($this->ignoredPathsCache[$fileRealPath])) {
|
||||
return $this->ignoredPathsCache[$fileRealPath];
|
||||
}
|
||||
|
||||
$ignored = false;
|
||||
|
||||
foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) {
|
||||
if ($this->isIgnored($parentDirectory)) {
|
||||
// rules in ignored directories are ignored, no need to check further.
|
||||
break;
|
||||
}
|
||||
|
||||
$fileRelativePath = substr($fileRealPath, \strlen($parentDirectory) + 1);
|
||||
|
||||
if (null === $regexps = $this->readGitignoreFile("{$parentDirectory}/.gitignore")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$exclusionRegex, $inclusionRegex] = $regexps;
|
||||
|
||||
if (preg_match($exclusionRegex, $fileRelativePath)) {
|
||||
$ignored = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match($inclusionRegex, $fileRelativePath)) {
|
||||
$ignored = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->ignoredPathsCache[$fileRealPath] = $ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function parentDirectoriesUpwards(string $from): array
|
||||
{
|
||||
$parentDirectories = [];
|
||||
|
||||
$parentDirectory = $from;
|
||||
|
||||
while (true) {
|
||||
$newParentDirectory = \dirname($parentDirectory);
|
||||
|
||||
// dirname('/') = '/'
|
||||
if ($newParentDirectory === $parentDirectory) {
|
||||
break;
|
||||
}
|
||||
|
||||
$parentDirectories[] = $parentDirectory = $newParentDirectory;
|
||||
}
|
||||
|
||||
return $parentDirectories;
|
||||
}
|
||||
|
||||
private function parentDirectoriesUpTo(string $from, string $upTo): array
|
||||
{
|
||||
return array_filter(
|
||||
$this->parentDirectoriesUpwards($from),
|
||||
static fn (string $directory): bool => str_starts_with($directory, $upTo)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function parentDirectoriesDownwards(string $fileRealPath): array
|
||||
{
|
||||
return array_reverse(
|
||||
$this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: string, 1: string}|null
|
||||
*/
|
||||
private function readGitignoreFile(string $path): ?array
|
||||
{
|
||||
if (\array_key_exists($path, $this->gitignoreFilesCache)) {
|
||||
return $this->gitignoreFilesCache[$path];
|
||||
}
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return $this->gitignoreFilesCache[$path] = null;
|
||||
}
|
||||
|
||||
if (!is_file($path) || !is_readable($path)) {
|
||||
throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable.");
|
||||
}
|
||||
|
||||
$gitignoreFileContent = file_get_contents($path);
|
||||
|
||||
return $this->gitignoreFilesCache[$path] = [
|
||||
Gitignore::toRegex($gitignoreFileContent),
|
||||
Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent),
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizePath(string $path): string
|
||||
{
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
return str_replace('\\', '/', $path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user