Passed
Push — master ( 6c3ce1...67476b )
by Fabien
07:34
created

FileFinder::findPhpFiles()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 1
1
<?php declare(strict_types = 1);
2
3
namespace Churn\File;
4
5
use const DIRECTORY_SEPARATOR;
6
use Generator;
7
use function in_array;
8
use function is_dir;
9
use function preg_match;
10
use function preg_replace;
11
use RecursiveDirectoryIterator;
12
use RecursiveIteratorIterator;
13
use SplFileInfo;
14
use function str_replace;
15
16
class FileFinder
17
{
18
    /**
19
     * List of file extensions to look for.
20
     * @var array
21
     */
22
    private $fileExtensions;
23
24
    /**
25
     * List of files to ignore.
26
     * @var array
27
     */
28
    private $filesToIgnore;
29
30
    /**
31
     * Class constructor.
32
     * @param array $fileExtensions List of file extensions to look for.
33
     * @param array $filesToIgnore  List of files to ignore.
34
     */
35
    public function __construct(array $fileExtensions, array $filesToIgnore)
36
    {
37
        $this->fileExtensions = $fileExtensions;
38
        $this->filesToIgnore = $filesToIgnore;
39
    }
40
41
    /**
42
     * Recursively finds all files with the .php extension in the provided
43
     * $paths and returns list as array.
44
     * @param array $paths Paths in which to look for .php files.
45
     * @return Generator
46
     */
47
    public function getPhpFiles(array $paths): Generator
48
    {
49
        foreach ($paths as $path) {
50
            yield from $this->getPhpFilesFromPath($path);
51
        }
52
    }
53
54
    /**
55
     * Recursively finds all files with the .php extension in the provided
56
     * $path adds them to $this->files.
57
     * @param string $path Path in which to look for .php files.
58
     * @return Generator
59
     */
60
    private function getPhpFilesFromPath(string $path): Generator
61
    {
62
        if (!is_dir($path)) {
63
            $file = new SplFileInfo($path);
64
            yield new File($file->getRealPath(), $file->getPathName());
65
            return;
66
        }
67
68
        foreach ($this->findPhpFiles($path) as $file) {
69
            yield new File($file->getRealPath(), $file->getPathName());
70
        }
71
    }
72
73
    /**
74
     * Recursively finds all PHP files in a given directory.
75
     * @param string $path Path in which to look for .php files.
76
     * @return Generator|SplFileInfo[]
77
     */
78
    private function findPhpFiles(string $path): Generator
79
    {
80
        foreach ($this->findFiles($path) as $file) {
81
            if (!in_array($file->getExtension(), $this->fileExtensions)
82
            || $this->fileShouldBeIgnored($file)) {
83
                continue;
84
            }
85
86
            yield $file;
87
        }
88
    }
89
90
    /**
91
     * Recursively finds all files in a given directory.
92
     * @param string $path Path in which to look for .php files.
93
     * @return Generator|SplFileInfo[]
94
     */
95
    private function findFiles(string $path): Generator
96
    {
97
        $directoryIterator = new RecursiveDirectoryIterator($path);
98
        foreach (new RecursiveIteratorIterator($directoryIterator) as $item) {
99
            if ($item->isDir()) {
100
                continue;
101
            }
102
103
            yield $item;
104
        }
105
    }
106
107
    /**
108
     * Determines if a file should be ignored.
109
     * @param SplFileInfo $file File.
110
     * @return boolean
111
     */
112
    private function fileShouldBeIgnored(SplFileInfo $file): bool
113
    {
114
        foreach ($this->filesToIgnore as $fileToIgnore) {
115
            $regex = $this->patternToRegex($fileToIgnore);
116
            if (preg_match("#{$regex}#", $file->getRealPath())) {
117
                return true;
118
            }
119
        }
120
121
        return false;
122
    }
123
124
    /**
125
     * Translate file path pattern to regex string.
126
     * @param string $filePattern File pattern to be ignored.
127
     * @return string
128
     */
129
    private function patternToRegex(string $filePattern): string
130
    {
131
        $regex = preg_replace("#(.*)\*([\w.]*)$#", "$1.+$2$", $filePattern);
132
        if (DIRECTORY_SEPARATOR === '\\') {
133
            $regex = str_replace('/', '\\\\', $regex);
134
        }
135
136
        return $regex;
137
    }
138
}
139