Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
51.85% |
28 / 54 |
CRAP | |
69.97% |
254 / 363 |
| FileFinder | |
0.00% |
0 / 1 |
|
51.85% |
28 / 54 |
1111.62 | |
69.97% |
254 / 363 |
| __construct | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| onlyFiles | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| onlyDirs | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| ignoreDotFiles | |
100.00% |
1 / 1 |
6 | |
100.00% |
13 / 13 |
|||
| followLinks | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 7 |
|||
| ignoreUnreadableDirs | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
| maxDepth | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
| minDepth | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
| nameFilter | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| notNameFilter | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| containsFilter | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| notContainsFilter | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| pathFilter | |
0.00% |
0 / 1 |
5.05 | |
87.50% |
7 / 8 |
|||
| notPathFilter | |
0.00% |
0 / 1 |
5.05 | |
87.50% |
7 / 8 |
|||
| excludeDirs | |
0.00% |
0 / 1 |
5.47 | |
73.33% |
11 / 15 |
|||
| orderByAccessedTime | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| orderByChangedTime | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| orderByModifiedTime | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| orderByName | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
| orderBySize | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| orderByType | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
| sizeFilter | |
0.00% |
0 / 1 |
87.98 | |
40.00% |
22 / 55 |
|||
| dateFilter | |
0.00% |
0 / 1 |
105.68 | |
42.31% |
22 / 52 |
|||
| in | |
100.00% |
1 / 1 |
6 | |
100.00% |
11 / 11 |
|||
| getIterator | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| where | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| limit | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| skip | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| take | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| count | |
100.00% |
1 / 1 |
3 | |
100.00% |
3 / 3 |
|||
| sum | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| any | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
| all | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| average | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| min | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| max | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| reverse | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| asEnumerable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| sort | |
100.00% |
1 / 1 |
2 | |
100.00% |
2 / 2 |
|||
| sortDesc | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
| sortKey | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
| sortKeyDesc | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
| orderBy | |
100.00% |
1 / 1 |
2 | |
100.00% |
2 / 2 |
|||
| orderByDesc | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
| firstOrNull | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
| aggregate | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
| lastOrNull | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
| normalizeDir | |
0.00% |
0 / 1 |
3.33 | |
66.67% |
4 / 6 |
|||
| appendDirIterator | |
0.00% |
0 / 1 |
5.03 | |
88.89% |
16 / 18 |
|||
| appendFileNameFilter | |
100.00% |
1 / 1 |
6 | |
100.00% |
13 / 13 |
|||
| appendPathFilter | |
100.00% |
1 / 1 |
9 | |
100.00% |
17 / 17 |
|||
| appendFileContainsFilter | |
0.00% |
0 / 1 |
9.02 | |
94.12% |
16 / 17 |
|||
| appendModeFilter | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| create | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
| <?php | |
| namespace Gek\FileFinder; | |
| use Gek\Collections\ArrayList; | |
| use Gek\Collections\Enumerable; | |
| use Gek\Collections\IEnumerable; | |
| use Gek\FileFinder\Iterators\GekRecursiveDirectoryIterator; | |
| use Gek\FileFinder\Iterators\GekRecursiveIteratorIterator; | |
| use Traversable; | |
| /** | |
| * Class FileFinder | |
| * | |
| * FileFinder, dosyaları ve dizinleri bulmak için kurallar oluşturmanıza izin verir. | |
| * | |
| * @package Gek\FileFinder | |
| */ | |
| class FileFinder implements IEnumerable | |
| { | |
| #region fields | |
| /** | |
| * İç kolleksion | |
| * | |
| * @var Enumerable|null | |
| */ | |
| protected ?Enumerable $_enumerable = null; | |
| /** | |
| * Ana Iterator | |
| * | |
| * Reqursive Iteratorleri barındıran iteratör. | |
| * | |
| * @var \AppendIterator | |
| */ | |
| protected \AppendIterator $_baseIterator; | |
| /** | |
| * Directort iteratorlerin instancelarını tutan array | |
| * | |
| * @var array|GekRecursiveDirectoryIterator[] | |
| */ | |
| protected array $dirIterators = array(); | |
| /** | |
| * RecursiveIterator Iterator instancelarını tutan array | |
| * | |
| * Max Min depth ayarları için kullanılıyor. | |
| * | |
| * @var array|GekRecursiveIteratorIterator[] | |
| */ | |
| protected array $iteratorIterators = array(); | |
| /** | |
| * .(nokta) ile başlayan dosya ve klasörleri göz ardı et. | |
| * | |
| * @var bool | |
| */ | |
| protected $ignoreDotFiles = false; | |
| /** | |
| * Dosya adı filtrelerini tutan array (eşleşen) | |
| * | |
| * Dosya adlarını filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| protected $nameFilters = []; | |
| /** | |
| * Dosya adı filtrelerini tutan array (eşleşmeyen) | |
| * | |
| * Dosya adlarını filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| protected $notNameFilters = []; | |
| /** | |
| * Dosya içeriği filtrelerini tutan array (eşleşen) | |
| * | |
| * Dosya içeriğini filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| protected $containsFilters = []; | |
| /** | |
| * Dosya içeriği filtrelerini tutan array (eşleşmeyen) | |
| * | |
| * Dosya içeriğini filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| protected $notContainsFilters = []; | |
| /** | |
| * Dosya yolu filtrelerini tutan array (eşleşen) | |
| * | |
| * Dosya yoluna göre filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| private $pathFilters = []; | |
| /** | |
| * Dosya yolu filtrelerini tutan array (eşleşmeyen) | |
| * | |
| * Dosya yoluna göre filtrelemek için kullanılan regex stringleri | |
| * | |
| * @var array|string[] | |
| */ | |
| private $notPathFilters = []; | |
| /** | |
| * Sembolik linklerin takip edilip edilmeyeceğini tutar. | |
| * | |
| * @var bool | |
| */ | |
| protected bool $followLinks = false; | |
| /** | |
| * Okunamayan dosya / dizinlerin gözardı edilip edilmeyeceğini tutar. | |
| * | |
| * @var bool | |
| */ | |
| protected bool $ignoreUnreadableDirs = false; | |
| /** | |
| * Max depth i tutar. | |
| * | |
| * @var int|null | |
| */ | |
| protected ?int $maxDepth = null; | |
| /** | |
| * Min depth i tutar. | |
| * | |
| * @var int|null | |
| */ | |
| protected ?int $minDepth = null; | |
| /** | |
| * Modu tutar. | |
| * | |
| * @see FindMode | |
| * @var int | |
| */ | |
| protected $mode = 0; | |
| #endregion fields | |
| #region ctor | |
| /** | |
| * FileFinder constructor. | |
| * @param int|null $maxDepth Max depth | |
| * @throws \Exception | |
| */ | |
| public function __construct(?int $maxDepth = null) | |
| { | |
| $this->_baseIterator = new \AppendIterator(); | |
| $this->_enumerable = Enumerable::fromIterable($this->_baseIterator); | |
| $this->maxDepth = $maxDepth; | |
| $this->ignoreDotFiles(true); | |
| } | |
| #endregion ctor | |
| #region methods | |
| /** | |
| * Sadece dosyaları arar | |
| * | |
| * @return $this | |
| */ | |
| public function onlyFiles() | |
| { | |
| $notSetFilter = $this->mode === 0; | |
| $this->mode = FindMode::ONLY_FILES; | |
| if ($notSetFilter) { | |
| $this->appendModeFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Sadece dizinleri arar | |
| * | |
| * @return $this | |
| */ | |
| public function onlyDirs() | |
| { | |
| $notSetFilter = $this->mode === 0; | |
| $this->mode = FindMode::ONLY_DIRECTORIES; | |
| if ($notSetFilter) { | |
| $this->appendModeFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * .(nokta) ile başlayan dosya/dizinleri gözardı et/etme | |
| * | |
| * @param bool $ignore Göz ardı et | |
| * @return $this | |
| */ | |
| public function ignoreDotFiles(bool $ignore = true) | |
| { | |
| if ($this->ignoreDotFiles !== $ignore) { | |
| $this->ignoreDotFiles = $ignore; | |
| $dotRegex = '#(^|/)\..+(/|$)#'; | |
| if ($this->ignoreDotFiles) { | |
| $notSetFilter = empty($this->pathFilters) && empty($this->notPathFilters); | |
| $this->notPathFilters[] = $dotRegex; | |
| if ($notSetFilter) { | |
| $this->appendPathFilter(); | |
| } | |
| } else { | |
| $tmp = new ArrayList($this->notPathFilters); | |
| if ($tmp->remove($dotRegex)) { | |
| $this->notPathFilters = $tmp->toArray(); | |
| } | |
| $tmp = null; | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Sembolik linkleri takip et | |
| * | |
| * @return $this | |
| */ | |
| public function followLinks() | |
| { | |
| if (!$this->followLinks) { | |
| $this->followLinks = true; | |
| foreach ($this->dirIterators as $dirIterator) { | |
| $flags = $dirIterator->getFlags(); | |
| $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; | |
| $dirIterator->setFlags($flags); | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Okunamayan dosya/dizinleri gözardı et/etme | |
| * | |
| * Bu seçenek varsayılan olarak etkindir. | |
| * | |
| * @param bool $ignore gözardı et | |
| * @return $this | |
| */ | |
| public function ignoreUnreadableDirs(bool $ignore = true) | |
| { | |
| if ($this->ignoreUnreadableDirs !== $ignore) { | |
| $this->ignoreUnreadableDirs = $ignore; | |
| foreach ($this->dirIterators as $dirIterator) { | |
| $dirIterator->setIgnoreUnreadableDirs($this->ignoreUnreadableDirs); | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Max derinliği ayarla (alt dizinler) | |
| * | |
| * @param int $maxDepth max depth | |
| * @return $this | |
| */ | |
| public function maxDepth(int $maxDepth) | |
| { | |
| if ($this->maxDepth !== $maxDepth) { | |
| $this->maxDepth = $maxDepth; | |
| foreach ($this->iteratorIterators as $iterator) { | |
| $iterator->setMaxDepth($this->maxDepth); | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Min derinliği ayarla (alt dizinler) | |
| * | |
| * @param int $minDepth min depth | |
| * @return $this | |
| */ | |
| public function minDepth(int $minDepth) | |
| { | |
| if ($this->minDepth !== $minDepth) { | |
| $this->minDepth = $minDepth; | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya adına göre eşleşenleri ara. | |
| * | |
| * @param string ...$names | |
| * @return $this | |
| */ | |
| public function nameFilter(string ...$names) | |
| { | |
| $notSetFilter = empty($this->nameFilters) && empty($this->notNameFilters); | |
| foreach ($names as $name) { | |
| if (!RegexHelper::isRegex($name)) { | |
| $name = RegexHelper::globToRegex($name); | |
| } | |
| $this->nameFilters[] = $name; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendFileNameFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya adına göre eşleşmeyenleri ara. | |
| * | |
| * @param string ...$names | |
| * @return $this | |
| */ | |
| public function notNameFilter(string ...$names) | |
| { | |
| $notSetFilter = empty($this->nameFilters) && empty($this->notNameFilters); | |
| foreach ($names as $name) { | |
| if (!RegexHelper::isRegex($name)) { | |
| $name = RegexHelper::globToRegex($name); | |
| } | |
| $this->notNameFilters[] = $name; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendFileNameFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya içeriğine göre eşleşenleri ara. | |
| * | |
| * @param string ...$contents | |
| * @return $this | |
| */ | |
| public function containsFilter(string ...$contents) | |
| { | |
| $notSetFilter = empty($this->containsFilters) && empty($this->notContainsFilters); | |
| foreach ($contents as $content) { | |
| if (!RegexHelper::isRegex($content)) { | |
| $content = '/' . preg_quote($content, '/') . '/'; | |
| } | |
| $this->containsFilters[] = $content; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendFileContainsFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya içeriğine göre eşleşmeyenleri ara. | |
| * | |
| * @param string ...$contents | |
| * @return $this | |
| */ | |
| public function notContainsFilter(string ...$contents) | |
| { | |
| $notSetFilter = empty($this->containsFilters) && empty($this->notContainsFilters); | |
| foreach ($contents as $content) { | |
| if (!RegexHelper::isRegex($content)) { | |
| $content = '/' . preg_quote($content, '/') . '/'; | |
| } | |
| $this->notContainsFilters[] = $content; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendFileContainsFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya yoluna göre eşleşenleri ara. | |
| * | |
| * @param string ...$paths | |
| * @return $this | |
| */ | |
| public function pathFilter(string ...$paths) | |
| { | |
| $notSetFilter = count($this->pathFilters) == 0 && count($this->notPathFilters) == 0; | |
| foreach ($paths as $path) { | |
| if (!RegexHelper::isRegex($path)) { | |
| $path = '/' . preg_quote($path, '/') . '/'; | |
| } | |
| $this->pathFilters[] = $path; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendPathFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya yoluna göre eşleşmeyenleri ara. | |
| * | |
| * @param string ...$paths | |
| * @return $this | |
| */ | |
| public function notPathFilter(string ...$paths) | |
| { | |
| $notSetFilter = count($this->pathFilters) == 0 && count($this->notPathFilters) == 0; | |
| foreach ($paths as $path) { | |
| if (!RegexHelper::isRegex($path)) { | |
| $path = '/' . preg_quote($path, '/') . '/'; | |
| } | |
| $this->notPathFilters[] = $path; | |
| } | |
| if ($notSetFilter) { | |
| $this->appendPathFilter(); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Verilen dizinleri hariç tut. | |
| * | |
| * Bağımsız değişken olarak iletilen dizinler, "in ()" yöntemiyle tanımlananlara göre olmalıdır. Örneğin: | |
| * $fileFinder->in(__DIR__)->excludeDirs('ruby'); | |
| * | |
| * @param string ...$dirs | |
| * @return $this | |
| */ | |
| public function excludeDirs(string ...$dirs) | |
| { | |
| foreach ($dirs as $dir) { | |
| $this->where(function (FileInfo $item) use ($dir) { | |
| $path = $item->isDir() ? $item->getRelativePathname() : $item->getRelativePath(); | |
| $path = str_replace('\\', '/', $path); | |
| if (RegexHelper::isRegex($dir)) { | |
| return !preg_match($dir, $path); | |
| } | |
| $dir = str_replace('\\', '/', $dir); | |
| $dir = rtrim($dir, '/'); | |
| if (false !== strpos($dir, '/')) { | |
| $pattern = preg_quote($dir, '#'); | |
| $pattern = '#(?:^|/)(?:' . $pattern . ')(?:/|$)#'; | |
| return !preg_match($pattern, $path); | |
| } else { | |
| $paths = explode("/", $path); | |
| return !in_array($dir, $paths); | |
| } | |
| }); | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri son erişilen zamana göre sıralar. | |
| * | |
| * Bu, dosyaya en son erişildiği, okunduğu veya yazıldığı zamandır. | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, | |
| * bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderByAccessedTime() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getATime(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri son inode değiştirme zamanına göre sıralar. | |
| * | |
| * Bu, inode bilgilerinin en son değiştirildiği zamandır | |
| * (izinler, sahip, grup veya diğer meta veriler). | |
| * Windows'ta, inode mevcut olmadığından, değişen zaman aslında dosya oluşturma zamanıdır. | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, | |
| * bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderByChangedTime() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getCTime(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri son değiştirilme zamanına göre sıralar. | |
| * | |
| * Bu, dosyanın gerçek içeriğinin en son değiştirildiği zamandır. | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderByModifiedTime() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getMTime(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri ada göre sıralar. | |
| * | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderByName() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getRealPath() ?: $item->getPathname(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri boyuta göre sıralar. | |
| * | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderBySize() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getSize(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosyaları ve dizinleri türe göre (dizinler, dosyalardan önce gelir ), sonra ada göre sıralar. | |
| * | |
| * Eşleşen tüm dosyaların ve dizinlerin karşılaştırma için alınması gerektiğinden, bu yavaş olabilir. | |
| * | |
| * @return $this | |
| */ | |
| public function orderByType() | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy(function (FileInfo $item) { | |
| return $item->getType() . "-" . $item->getRealPath() ?: $item->getPathname(); | |
| }); | |
| return $this; | |
| } | |
| /** | |
| * Dosya boyutları için testler ekler. | |
| * | |
| * $fileFinder->sizeFilter('> 10K'); | |
| * $fileFinder->sizeFilter('<= 1Ki'); | |
| * $fileFinder->sizeFilter(4); | |
| * $fileFinder->sizeFilter('> 10K', '< 20K') | |
| * | |
| * @param string ...$sizes Bir boyut aralığı dizesi veya bir tam sayı veya boyut aralıkları dizisi | |
| * @return $this | |
| */ | |
| public function sizeFilter(string ...$sizes) | |
| { | |
| foreach ($sizes as $size) { | |
| if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $size, $matches)) { | |
| throw new \InvalidArgumentException("size geçerli bir size girdisi değil. " . $size); | |
| } | |
| $target = $matches[2]; | |
| if (!is_numeric($target)) { | |
| throw new \InvalidArgumentException('Geçersiz sayı :.' . $target); | |
| } | |
| if (isset($matches[3])) { | |
| // magnitude | |
| switch (strtolower($matches[3])) { | |
| case 'k': | |
| $target *= 1000; | |
| break; | |
| case 'ki': | |
| $target *= 1024; | |
| break; | |
| case 'm': | |
| $target *= 1000000; | |
| break; | |
| case 'mi': | |
| $target *= 1024 * 1024; | |
| break; | |
| case 'g': | |
| $target *= 1000000000; | |
| break; | |
| case 'gi': | |
| $target *= 1024 * 1024 * 1024; | |
| break; | |
| } | |
| } | |
| $operator = $matches[1] ?? '=='; | |
| if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { | |
| throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); | |
| } | |
| switch ($operator) { | |
| case '>': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() > $target; | |
| }); | |
| break; | |
| case '>=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() >= $target; | |
| }); | |
| break; | |
| case '<': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() < $target; | |
| }); | |
| break; | |
| case '<=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() <= $target; | |
| }); | |
| break; | |
| case '!=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() != $target; | |
| }); | |
| break; | |
| case '==': | |
| default: | |
| $this->where(function (FileInfo $item) use ($target) { | |
| return $item->getSize() == $target; | |
| }); | |
| break; | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Dosya tarihleri için testler ekler (son değiştirilme). | |
| * | |
| * Tarih, strtotime () tarafından ayrıştırılabilecek bir şey olmalıdır: | |
| * | |
| * $fileFinder->dateFilter('since yesterday'); | |
| * $fileFinder->dateFilter('until 2 days ago'); | |
| * $fileFinder->dateFilter('> now - 2 hours'); | |
| * $fileFinder->dateFilter('>= 2020-10-15'); | |
| * $fileFinder->dateFilter('>= 2020-10-15', '<= 2020-05-27'); | |
| * | |
| * @param string ...$dates Bir tarih aralığı dizesi veya bir tarih aralığı dizisi | |
| * @return $this | |
| */ | |
| public function dateFilter(string ...$dates) | |
| { | |
| foreach ($dates as $date) { | |
| if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $date, $matches)) { | |
| throw new \InvalidArgumentException("date geçerli bir date girdisi değil. " . $date); | |
| } | |
| try { | |
| $dt = new \DateTime($matches[2]); | |
| $target = $dt->format('U'); | |
| } catch (\Exception $e) { | |
| throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); | |
| } | |
| $operator = $matches[1] ?? '=='; | |
| if ('since' === $operator || 'after' === $operator) { | |
| $operator = '>'; | |
| } | |
| if ('until' === $operator || 'before' === $operator) { | |
| $operator = '<'; | |
| } | |
| if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { | |
| throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); | |
| } | |
| switch ($operator) { | |
| case '>': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() > $target; | |
| }); | |
| break; | |
| case '>=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() >= $target; | |
| }); | |
| break; | |
| case '<': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() < $target; | |
| }); | |
| break; | |
| case '<=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() <= $target; | |
| }); | |
| break; | |
| case '!=': | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() != $target; | |
| }); | |
| break; | |
| case '==': | |
| default: | |
| $this->where(function (FileInfo $item) use ($target) { | |
| if (!file_exists($item->getPathname())) { | |
| return false; | |
| } | |
| return $item->getMTime() == $target; | |
| }); | |
| break; | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Tanımlanmış kurallarla eşleşen dosyaları ve dizinleri arar. | |
| * | |
| * @param string ...$dirs Bir dizin yolu veya bir dizi dizin | |
| * @return $this | |
| */ | |
| public function in(string ...$dirs) | |
| { | |
| foreach ($dirs as $dir) { | |
| if (is_dir($dir)) { | |
| $dir = $this->normalizeDir($dir); | |
| $this->appendDirIterator($dir); | |
| } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) { | |
| sort($glob); | |
| $glob = array_map([$this, 'normalizeDir'], $glob); | |
| foreach ($glob as $gDir) { | |
| $this->appendDirIterator($gDir); | |
| } | |
| } else { | |
| throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); | |
| } | |
| } | |
| return $this; | |
| } | |
| #endregion methods | |
| #region IteratorAggregate | |
| /** | |
| * Retrieve an external iterator | |
| * @link https://php.net/manual/en/iteratoraggregate.getiterator.php | |
| * @return Traversable An instance of an object implementing <b>Iterator</b> or | |
| * <b>Traversable</b> | |
| * @throws \Exception on failure. | |
| */ | |
| public function getIterator() | |
| { | |
| return $this->_enumerable->getIterator(); | |
| } | |
| #endregion IteratorAggregate | |
| #region linq | |
| /** | |
| * Yineleyiciyi anonim bir işlevle filtreler. | |
| * | |
| * Anonim işlev bir \ SplFileInfo alır ve dosyaları kaldırmak için false döndürmelidir. | |
| * | |
| * @param callable $fn Anonim işlev | |
| * @return $this | |
| */ | |
| public function where(callable $fn) | |
| { | |
| $this->_enumerable = $this->_enumerable->where($fn); | |
| return $this; | |
| } | |
| /** | |
| * Bir Yineleyicide sınırlı bir öğe alt kümesi üzerinde yinelemeye izin verir. | |
| * | |
| * @param int $skip Atlanacak öğe sayısı | |
| * @param int $take Alınacak öğe sayısı | |
| * @return $this | |
| */ | |
| public function limit(int $skip, int $take = -1) | |
| { | |
| $this->_enumerable = $this->_enumerable->limit($skip, $take); | |
| return $this; | |
| } | |
| /** | |
| * Verilen sayıda öğeyi atlar. | |
| * | |
| * @param int $count Atlanacak öğe sayısı | |
| * @return $this | |
| */ | |
| public function skip(int $count) | |
| { | |
| $this->_enumerable = $this->_enumerable->skip($count); | |
| return $this; | |
| } | |
| /** | |
| * Verilen sayıda öğeyi alır | |
| * | |
| * @param int $count Alınacak öğe sayısı | |
| * @return $this | |
| */ | |
| public function take(int $count) | |
| { | |
| $this->_enumerable = $this->_enumerable->take($count); | |
| return $this; | |
| } | |
| /** | |
| * Count elements of an object | |
| * @link https://php.net/manual/en/countable.count.php | |
| * @param callable|null $fn Filtreleme için anonim işlev | |
| * @return int The custom count as an integer. | |
| * </p> | |
| * <p> | |
| * The return value is cast to an integer. | |
| * @since 5.1.0 | |
| */ | |
| public function count(?callable $fn = null): int | |
| { | |
| return $fn == null ? | |
| iterator_count($this->_enumerable->getIterator()) : | |
| $this->_enumerable->count($fn); | |
| } | |
| /** | |
| * Verilen anaonim işlevin öğelerden döndürdüğü değerleri toplamını verir. | |
| * | |
| * @param callable|null $fn Öğeden değer alacak anonim işlev | |
| * @return int|float | |
| */ | |
| public function sum(callable $fn) | |
| { | |
| return $this->_enumerable->sum($fn); | |
| } | |
| /** | |
| * Herhangi bir sonuç bulunup bulunmadığını kontrol eder. | |
| * | |
| * Eğer bir anonim işlev verilirse işlevin şartınna uyan herhangi bir sonuç bulunup bulunmadığını kontrol eder. | |
| * | |
| * @param callable|null $fn Anonim işlev | |
| * @return bool | |
| */ | |
| public function any(?callable $fn = null): bool | |
| { | |
| return $this->_enumerable->any($fn); | |
| } | |
| /** | |
| * Bütün öğelerin, verilen anonim işlevin şartına uyup uymadığını kontrol eder. | |
| * | |
| * @param callable $fn Anonim işlev | |
| * @return bool | |
| */ | |
| public function all(callable $fn): bool | |
| { | |
| return $this->_enumerable->all($fn); | |
| } | |
| /** | |
| * Verilen anaonim işlevin öğelerden döndürdüğü değerlerin ortalamasını verir. | |
| * | |
| * @param callable $fn | |
| * @return float | |
| */ | |
| public function average(callable $fn): float | |
| { | |
| return $this->_enumerable->average($fn); | |
| } | |
| /** | |
| * Verilen anaonim işlevin öğelerden döndürdüğü değerlerden en küçüğünü verir. | |
| * | |
| * @param callable $fn | |
| * @return int|float|null | |
| */ | |
| public function min(callable $fn) | |
| { | |
| return $this->_enumerable->min($fn); | |
| } | |
| /** | |
| * Verilen anaonim işlevin öğelerden döndürdüğü değerlerden en büyüğünü verir. | |
| * | |
| * @param callable $fn | |
| * @return int|float|null | |
| */ | |
| public function max(callable $fn) | |
| { | |
| return $this->_enumerable->max($fn); | |
| } | |
| /** | |
| * Sıralamayı tersine çevirir. | |
| * | |
| * @return $this | |
| */ | |
| public function reverse() | |
| { | |
| $this->_enumerable = $this->_enumerable->reverse(); | |
| return $this; | |
| } | |
| /** | |
| * Enumerable nesnesi çevirir. | |
| * | |
| * @return Enumerable | |
| */ | |
| public function asEnumerable(): Enumerable | |
| { | |
| return $this->_enumerable->asEnumerable(); | |
| } | |
| /** | |
| * Öğeleri sıralar. | |
| * | |
| * @param callable|null $compareFn Karşılaştırma için Anonim Fonksion | |
| * @return $this | |
| */ | |
| public function sort(?callable $compareFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->sort($compareFn); | |
| return $this; | |
| } | |
| /** | |
| * Öğeleri tersine sıralar. | |
| * | |
| * @param callable|null $compareFn Karşılaştırma için Anonim Fonksion | |
| * @return $this | |
| */ | |
| public function sortDesc(?callable $compareFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->sortDesc($compareFn); | |
| return $this; | |
| } | |
| /** | |
| * öğeleri anahtara (key => ...) göre sıralar. | |
| * | |
| * @param callable|null $compareFn Karşılaştırma için Anonim Fonksion | |
| * @return $this | |
| */ | |
| public function sortKey(?callable $compareFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->sortKey($compareFn); | |
| return $this; | |
| } | |
| /** | |
| * öğeleri anahtara (key => ...) göre tersine sıralar. | |
| * | |
| * @param callable|null $compareFn Karşılaştırma için Anonim Fonksion | |
| * @return $this | |
| */ | |
| public function sortKeyDesc(?callable $compareFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->sortKeyDesc($compareFn); | |
| return $this; | |
| } | |
| /** | |
| * Öğeleri sıralar. | |
| * | |
| * @param callable|null $selectorFn Karşılaştırmaya girecek değeri veren anonim işlev. | |
| * @return $this | |
| */ | |
| public function orderBy(?callable $selectorFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->orderBy($selectorFn); | |
| return $this; | |
| } | |
| /** | |
| * Öğeleri tersine sıralar. | |
| * | |
| * @param callable|null $selectorFn Karşılaştırmaya girecek değeri veren anonim işlev. | |
| * @return $this | |
| */ | |
| public function orderByDesc(?callable $selectorFn = null) | |
| { | |
| $this->_enumerable = $this->_enumerable->orderByDesc($selectorFn); | |
| return $this; | |
| } | |
| /** | |
| * İlk öğeyi verir. | |
| * | |
| * Eğer bir anonim işlev verilmişse işlevin şartına uyan ilk öğeyi verir. | |
| * | |
| * @param callable|null $fn Anonim işlev | |
| * @return FileInfo|null | |
| */ | |
| public function firstOrNull(?callable $fn = null) | |
| { | |
| return $this->_enumerable->firstOrNull($fn); | |
| } | |
| /** | |
| * Bir dizi üzerine bir toplayıcı işlevi ($fn) uygular. | |
| * | |
| * Belirtilen çekirdek ($tart) değeri, ilk biriktirici değeri olarak kullanılır ve | |
| * belirtilen işlev($resultFn), sonuç değerini seçmek için kullanılır. | |
| * | |
| * @param callable $fn Toplayıcı işlev | |
| * @param mixed|null $start başlangıç değeri | |
| * @param callable|null $resultFn sonuç işlevi | |
| * @return mixed|null | |
| */ | |
| public function aggregate(callable $fn, $start = null, ?callable $resultFn = null) | |
| { | |
| return $this->_enumerable->aggregate($fn, $start, $resultFn); | |
| } | |
| /** | |
| * Son öğeyi verir. | |
| * | |
| * Eğer bir anonim işlev verilmişse işlevin şartına uyan son öğeyi verir. | |
| * | |
| * @param callable|null $fn Anonim işlev | |
| * @return FileInfo|null | |
| */ | |
| public function lastOrNull(?callable $fn = null) | |
| { | |
| return $this->reverse()->firstOrNull($fn); | |
| } | |
| #endregion linq | |
| #region utils | |
| /** | |
| * Sondaki eğik çizgileri kaldırarak verilen dizin adlarını normalleştirir. | |
| * | |
| */ | |
| private function normalizeDir(string $dir): string | |
| { | |
| if ('/' === $dir) { | |
| return $dir; | |
| } | |
| $dir = rtrim($dir, '/' . \DIRECTORY_SEPARATOR); | |
| if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { | |
| $dir .= '/'; | |
| } | |
| return $dir; | |
| } | |
| /** | |
| * | |
| * Yeni bir dizin iteratorü ekler. | |
| * | |
| * @param $dir Dizin | |
| */ | |
| private function appendDirIterator($dir) | |
| { | |
| $flags = \FilesystemIterator::SKIP_DOTS; | |
| if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { | |
| $flags |= \FilesystemIterator::UNIX_PATHS; | |
| } | |
| if ($this->followLinks) { | |
| $flags |= \FilesystemIterator::FOLLOW_SYMLINKS; | |
| } | |
| $iterator = new GekRecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); | |
| $this->dirIterators[] = $iterator; | |
| $iterator = new GekRecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); | |
| if ($this->maxDepth !== null) { | |
| $iterator->setMaxDepth($this->maxDepth); | |
| } | |
| $that = $this; | |
| $iterator->setDephtFilterFn(function ($depht) use ($that) { | |
| if ($that->minDepth === null) { | |
| return true; | |
| } | |
| return $depht >= $that->minDepth; | |
| }); | |
| $this->iteratorIterators[] = $iterator; | |
| $this->_baseIterator->append($iterator); | |
| } | |
| /** | |
| * Dosya adı filtre iteratorü ekler | |
| * | |
| */ | |
| protected function appendFileNameFilter() | |
| { | |
| $that = $this; | |
| $this->where(function (FileInfo $item) use ($that) { | |
| $string = $item->getFilename(); | |
| // should at least not match one rule to exclude | |
| foreach ($that->notNameFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return false; | |
| } | |
| } | |
| // should at least match one rule | |
| if ($that->nameFilters) { | |
| foreach ($that->nameFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // If there is no match rules, the file is accepted | |
| return true; | |
| }); | |
| } | |
| /** | |
| * Dosya yolu filtre iteratorü ekler | |
| * | |
| */ | |
| protected function appendPathFilter() | |
| { | |
| $that = $this; | |
| $this->where(function (FileInfo $item) use ($that) { | |
| if (count($that->notPathFilters) == 0 && count($that->pathFilters) == 0) { | |
| return true; | |
| } | |
| $string = $item->getRelativePathname(); | |
| if ('\\' === \DIRECTORY_SEPARATOR) { | |
| $string = str_replace('\\', '/', $string); | |
| } | |
| // should at least not match one rule to exclude | |
| foreach ($that->notPathFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return false; | |
| } | |
| } | |
| // should at least match one rule | |
| if ($that->pathFilters) { | |
| foreach ($that->pathFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // If there is no match rules, the file is accepted | |
| return true; | |
| }); | |
| } | |
| /** | |
| * Dosya içeriği filtre iteratorü ekler | |
| * | |
| */ | |
| protected function appendFileContainsFilter() | |
| { | |
| $that = $this; | |
| $this->where(function (FileInfo $item) use ($that) { | |
| if ($item->isDir() || !$item->isReadable()) { | |
| return false; | |
| } | |
| $string = $item->getContents(); | |
| if (!$string) { | |
| return false; | |
| } | |
| // should at least not match one rule to exclude | |
| foreach ($that->notContainsFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return false; | |
| } | |
| } | |
| // should at least match one rule | |
| if ($that->containsFilters) { | |
| foreach ($that->containsFilters as $regex) { | |
| if (preg_match($regex, $string)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // If there is no match rules, the file is accepted | |
| return true; | |
| }); | |
| } | |
| /** | |
| * Mode filtre iteratorü ekler | |
| * | |
| */ | |
| protected function appendModeFilter() | |
| { | |
| $that = $this; | |
| $this->where(function (FileInfo $item) use ($that) { | |
| if (FindMode::ONLY_DIRECTORIES === (FindMode::ONLY_DIRECTORIES & $that->mode) && $item->isFile()) { | |
| return false; | |
| } elseif (FindMode::ONLY_FILES === (FindMode::ONLY_FILES & $that->mode) && $item->isDir()) { | |
| return false; | |
| } | |
| return true; | |
| }); | |
| } | |
| #endregion utils | |
| #region statics | |
| /** | |
| * Yeni bir FileFinder oluşturur. | |
| * | |
| * @param int|null $maxDepth max derinlik | |
| * @return FileFinder | |
| */ | |
| public static function create(?int $maxDepth = null) | |
| { | |
| return new self($maxDepth); | |
| } | |
| #endregion statics | |
| } |