Passed
Pull Request — master (#22)
by Sergei
13:33
created

PathMatcher::withNotExactSlashes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Files\PathMatch;
6
7
final class PathMatcher implements PathMatcherInterface
8
{
9
    private ?array $only = null;
10
    private ?array $except = null;
11
    private ?array $callbacks = null;
12
13
    private bool $caseSensitive = false;
14
    private bool $matchFullPath = false;
15
    private bool $matchSlashesExactly = true;
16
17
    /**
18
     * Make string patterns case sensitive.
19
     * @return self
20
     */
21
    public function caseSensitive(): self
22
    {
23
        $new = clone $this;
24
        $new->caseSensitive = true;
25
        return $new;
26
    }
27
28
    /**
29
     * Match string patterns as full path, not just ending of path.
30
     * @return self
31
     */
32
    public function withFullPath(): self
33
    {
34
        $new = clone $this;
35
        $new->matchFullPath = true;
36
        return $new;
37
    }
38
39
    /**
40
     * Match `/` character with wildcards in string patterns.
41
     * @return self
42
     */
43
    public function withNotExactSlashes(): self
44
    {
45
        $new = clone $this;
46
        $new->matchSlashesExactly = false;
47
        return $new;
48
    }
49
50
    /**
51
     * Set list of patterns that the files or directories should match.
52
     * @param string|PathPattern ...$patterns
53
     * @return self
54
     */
55
    public function only(...$patterns): self
56
    {
57
        $new = clone $this;
58
        $new->only = $patterns;
59
        return $new;
60
    }
61
62
    /**
63
     * Set list of patterns that the files or directories should not match.
64
     * @param string|PathPattern ...$patterns
65
     * @return self
66
     */
67
    public function except(string ...$patterns): self
68
    {
69
        $new = clone $this;
70
        $new->except = $patterns;
71
        return $new;
72
    }
73
74
    /**
75
     * Set list of PHP callback that is called for each path.
76
     *
77
     * The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be filtered.
78
     * The callback should return `true` if the passed path would match and `false` if it doesn't.
79
     *
80
     * @param callable ...$callbacks
81
     * @return self
82
     */
83
    public function callback(callable ...$callbacks): self
84
    {
85
        $new = clone $this;
86
        $new->callbacks = $callbacks;
87
        return $new;
88
    }
89
90
    /**
91
     * Checks if the passed path would match specified conditions.
92
     *
93
     * @param string $path The tested path.
94
     * @return bool Whether the path matches conditions or not.
95
     */
96
    public function match(string $path): bool
97
    {
98
        $path = str_replace('\\', '/', $path);
99
100
        if ($this->only !== null) {
101
            if (!$this->matchPathPatterns($path, $this->only)) {
102
                return false;
103
            }
104
        }
105
106
        if ($this->except !== null) {
107
            if ($this->matchPathPatterns($path, $this->except)) {
108
                return false;
109
            }
110
        }
111
112
        if ($this->callbacks !== null) {
113
            foreach ($this->callbacks as $callback) {
114
                if (!$callback($path)) {
115
                    return false;
116
                }
117
            }
118
        }
119
120
        return true;
121
    }
122
123
    /**
124
     * @param string $path
125
     * @param string|PathPattern[] $patterns
126
     * @return bool
127
     */
128
    private function matchPathPatterns(string $path, array $patterns): bool
129
    {
130
        $patterns = $this->makePathPatterns($patterns);
131
132
        foreach ($patterns as $pattern) {
133
            if ($pattern->match($path)) {
134
                return true;
135
            }
136
        }
137
138
        return false;
139
    }
140
141
    /**
142
     * @param string[]|PathPattern[] $patterns
143
     * @return PathPattern[]
144
     */
145
    private function makePathPatterns(array $patterns): array
146
    {
147
        $pathPatterns = [];
148
        foreach ($patterns as $pattern) {
149
            if ($pattern instanceof PathPattern) {
150
                $pathPatterns[] = $pattern;
151
                continue;
152
            }
153
154
            $pathPattern = new PathPattern($pattern);
155
156
            if ($this->caseSensitive) {
157
                $pathPattern = $pathPattern->caseSensitive();
158
            }
159
160
            if ($this->matchFullPath) {
161
                $pathPattern = $pathPattern->withFullPath();
162
            }
163
164
            if (!$this->matchSlashesExactly) {
165
                $pathPattern = $pathPattern->withNotExactSlashes();
166
            }
167
168
            $pathPatterns[] = $pathPattern;
169
        }
170
        return $pathPatterns;
171
    }
172
}
173