Completed
Pull Request — 2.x (#402)
by
unknown
23:55
created

Enumerator::getInPaths()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4.074

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 10
cts 12
cp 0.8333
rs 9.6333
c 0
b 0
f 0
cc 4
nc 5
nop 0
crap 4.074
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2015, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\Instrument\FileSystem;
12
13
use CallbackFilterIterator;
14
use InvalidArgumentException;
15
use LogicException;
16
use RecursiveIteratorIterator;
17
use SplFileInfo;
18
use Symfony\Component\Finder\Finder;
19
use UnexpectedValueException;
20
21
/**
22
 * Enumerates files in the concrete directory, applying filtration logic
23
 */
24
class Enumerator
25
{
26
27
    /**
28
     * Path to the root directory, where enumeration should start
29
     *
30
     * @var string
31
     */
32
    private $rootDirectory;
33
34
    /**
35
     * List of additional include paths, should be below rootDirectory
36
     *
37
     * @var array
38
     */
39
    private $includePaths;
40
41
    /**
42
     * List of additional exclude paths, should be below rootDirectory
43
     *
44
     * @var array
45
     */
46
    private $excludePaths;
47 7
48
    /**
49 7
     * Initializes an enumerator
50 7
     *
51 7
     * @param string $rootDirectory Path to the root directory
52 7
     * @param array  $includePaths  List of additional include paths
53
     * @param array  $excludePaths  List of additional exclude paths
54
     */
55
    public function __construct($rootDirectory, array $includePaths = [], array $excludePaths = [])
56
    {
57
        $this->rootDirectory = $rootDirectory;
58
        $this->includePaths = $includePaths;
59 7
        $this->excludePaths = $excludePaths;
60
    }
61 7
62 7
    /**
63 7
     * Returns an enumerator for files
64 7
     *
65
     * @return CallbackFilterIterator|RecursiveIteratorIterator|SplFileInfo[]
66
     * @throws UnexpectedValueException
67
     * @throws InvalidArgumentException
68 7
     * @throws LogicException
69 7
     */
70
    public function enumerate()
71 7
    {
72
        $finder = new Finder();
73
        $finder->files()
74
            ->name('*.php')
75
            ->in($this->getInPaths())
76
            ->notPath($this->getExcludePaths());
77
78
        return $finder->getIterator();
79 7
    }
80
81 7
    /**
82 7
     * @return array
83 7
     * @throws UnexpectedValueException
84
     */
85 7
    private function getInPaths()
86
    {
87 7
        $inPaths = [];
88
89
        foreach ($this->includePaths as $path) {
90
            if (strpos($path, $this->rootDirectory, 0) === false) {
91 7
                throw new UnexpectedValueException(sprintf('Path %s is not in %s', $path, $this->rootDirectory));
92
            }
93 7
94
            $path = str_replace('*', '', $path);
95
            $inPaths[] = $path;
96
        }
97 7
98 1
        if (empty($inPaths)) {
99 1
            $inPaths[] = $this->rootDirectory;
100 1
        }
101 1
102 1
        return $inPaths;
103
    }
104
105 1
    /**
106
     * @return array
107
     */
108
    private function getExcludePaths()
109
    {
110 7
        $excludePaths = [];
111 4
112 4
        foreach ($this->excludePaths as $path) {
113
            $path = str_replace('*', '.*', $path);
114
            $excludePaths[] = '#' . str_replace($this->rootDirectory . '/', '', $path) . '#';
115
        }
116 5
117 7
        return $excludePaths;
118
    }
119
120
    /**
121
     * Returns a filter callback for enumerating files
122
     *
123
     * @return \Closure
124
     */
125
    public function getFilter()
126
    {
127
        $rootDirectory = $this->rootDirectory;
128
        $includePaths = $this->includePaths;
129
        $excludePaths = $this->excludePaths;
130
131 1
        return function (SplFileInfo $file) use ($rootDirectory, $includePaths, $excludePaths) {
132
133 1
            if ($file->getExtension() !== 'php') {
134
                return false;
135
            }
136
137
            $fullPath = $this->getFileFullPath($file);
138
            // Do not touch files that not under rootDirectory
139
            if (strpos($fullPath, $rootDirectory) !== 0) {
140
                return false;
141
            }
142
143
            if (!empty($includePaths)) {
144
                $found = false;
145
                foreach ($includePaths as $includePattern) {
146
                    if (fnmatch("{$includePattern}*", $fullPath, FNM_NOESCAPE)) {
147
                        $found = true;
148
                        break;
149
                    }
150
                }
151
                if (!$found) {
152
                    return false;
153
                }
154
            }
155
156
            foreach ($excludePaths as $excludePattern) {
157
                if (fnmatch("{$excludePattern}*", $fullPath, FNM_NOESCAPE)) {
158
                    return false;
159
                }
160
            }
161
162
            return true;
163
        };
164
    }
165
166
    /**
167
     * Return the real path of the given file
168
     *
169
     * This is used for testing purpose with virtual file system.
170
     * In a vfs the 'realPath' methode will always return false.
171
     * So we have a chance to mock this single function to return different path.
172
     *
173
     * @param SplFileInfo $file
174
     *
175
     * @return string
176
     */
177
    protected function getFileFullPath(SplFileInfo $file)
178
    {
179
        return $file->getRealPath();
180
    }
181
182
}
183