• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

miaoxing / plugin / 10654305469

01 Sep 2024 01:03PM UTC coverage: 42.917% (-0.08%) from 42.997%
10654305469

push

github

semantic-release-bot
chore(release): publish

See CHANGELOG.md for more details.

1233 of 2873 relevant lines covered (42.92%)

7.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.86
/src/Service/PageRouter.php
1
<?php
2

3
namespace Miaoxing\Plugin\Service;
4

5
use Miaoxing\Plugin\BaseService;
6

7
class PageRouter extends BaseService
8
{
9
    /**
10
     * @var string
11
     */
12
    protected $pageDirGlob = '{pages,plugins/*/pages}';
13

14
    /**
15
     * @var array|null
16
     */
17
    protected $pages;
18

19
    /**
20
     * @return array
21
     */
22
    public function generatePages(): array
23
    {
24
        $dirs = glob($this->pageDirGlob, \GLOB_BRACE | \GLOB_ONLYDIR);
2✔
25
        $pages = [];
2✔
26
        foreach ($dirs as $dir) {
2✔
27
            $pages = $this->scanPages($dir, $dir, $pages);
2✔
28
        }
29
        return $pages;
2✔
30
    }
31

32
    /**
33
     * @param string $pathInfo
34
     * @return array|null
35
     */
36
    public function match(string $pathInfo): ?array
37
    {
38
        $paths = explode('/', ltrim($pathInfo, '/'));
29✔
39
        $pages = $this->getPages();
29✔
40

41
        // Handle index page
42
        if ('/' === $pathInfo) {
29✔
43
            $pages = ['/' => $pages];
1✔
44
        }
45

46
        $result = $this->matchPaths($paths, $pages);
29✔
47
        if (!$result) {
29✔
48
            return null;
7✔
49
        }
50

51
        $params = [];
26✔
52
        foreach ($result['paths'] as $i => $path) {
26✔
53
            if (false !== strpos($path, '[')) {
26✔
54
                preg_match('/\[(.+?)\]/', $path, $matches);
16✔
55
                if ($matches) {
16✔
56
                    $params[$matches[1]] = $paths[$i];
16✔
57
                }
58
            }
59
        }
60

61
        $path = (isset($result['path']) && $result['path']) ? ($result['path'] . '/') : '';
26✔
62
        return [
26✔
63
            'file' => $path . ltrim(implode('', $result['paths']), '/'),
26✔
64
            'params' => $params,
26✔
65
        ] + $result;
26✔
66
    }
67

68
    /**
69
     * @return array
70
     */
71
    public function getPages(): array
72
    {
73
        if (null === $this->pages) {
30✔
74
            $this->pages = $this->generatePages();
1✔
75
        }
76
        return $this->pages;
30✔
77
    }
78

79
    /**
80
     * @param array|null $pages
81
     * @return $this
82
     */
83
    public function setPages(?array $pages = null): self
84
    {
85
        $this->pages = $pages;
30✔
86
        return $this;
30✔
87
    }
88

89
    /**
90
     * @return string
91
     */
92
    public function getPageDirGlob(): string
93
    {
94
        return $this->pageDirGlob;
1✔
95
    }
96

97
    /**
98
     * @param string $pageDirGlob
99
     * @return $this
100
     */
101
    public function setPageDirGlob(string $pageDirGlob): self
102
    {
103
        $this->pageDirGlob = $pageDirGlob;
2✔
104
        $this->pages = null;
2✔
105
        return $this;
2✔
106
    }
107

108
    /**
109
     * @param array $urlPaths
110
     * @param array $filePaths
111
     * @param int $depth
112
     * @param array $matches
113
     * @return array|null
114
     */
115
    protected function matchPaths(array $urlPaths, array $filePaths, int $depth = 0, array $matches = []): ?array
116
    {
117
        if (!isset($urlPaths[$depth])) {
29✔
118
            return null;
4✔
119
        }
120

121
        $isLast = $depth + 1 === count($urlPaths);
29✔
122
        foreach ($filePaths as $filePath => $next) {
29✔
123
            if (!$this->matchPath($urlPaths[$depth], $filePath, $isLast)) {
29✔
124
                continue;
21✔
125
            }
126

127
            $hasNext = $this->hasNext($next);
28✔
128
            if ($isLast && $this->isEnded($next, $hasNext)) {
28✔
129
                $matches[] = $filePath;
26✔
130
                if (isset($next['file'])) {
26✔
131
                    $matches[] = '/' . $next['file'];
15✔
132
                }
133
                return $next + ['paths' => $matches];
26✔
134
            }
135

136
            if (!$hasNext) {
21✔
137
                continue;
10✔
138
            }
139

140
            $result = $this->matchPaths($urlPaths, $next, $depth + 1, array_merge($matches, [$filePath]));
19✔
141
            if ($result) {
19✔
142
                return $result;
17✔
143
            }
144
        }
145

146
        return null;
7✔
147
    }
148

149
    /**
150
     * @param string $urlPath
151
     * @param string $filePath
152
     * @param bool $isLast
153
     * @return bool
154
     */
155
    protected function matchPath(string $urlPath, string $filePath, bool $isLast): bool
156
    {
157
        $urlPath = '/' . $urlPath;
29✔
158

159
        // Ignore config
160
        if ('/' !== substr($filePath, 0, 1)) {
29✔
161
            return false;
18✔
162
        }
163

164
        if ($urlPath === $filePath) {
29✔
165
            return true;
27✔
166
        }
167

168
        if ($isLast && ($urlPath . '.php') === $filePath) {
23✔
169
            return true;
3✔
170
        }
171

172
        if (false !== strpos($filePath, '[')) {
22✔
173
            return true;
18✔
174
        }
175

176
        return false;
15✔
177
    }
178

179
    /**
180
     * @param string|array $pages
181
     * @return bool
182
     */
183
    protected function hasNext($pages): bool
184
    {
185
        if (!$pages || !is_array($pages)) {
28✔
186
            return false;
20✔
187
        }
188
        foreach ($pages as $name => $page) {
27✔
189
            if ('/' === substr($name, 0, 1)) {
27✔
190
                return true;
21✔
191
            }
192
        }
193
        return false;
9✔
194
    }
195

196
    /**
197
     * @param string $rootDir
198
     * @param string $dir
199
     * @param array $pages
200
     * @return array
201
     */
202
    protected function scanPages(string $rootDir, string $dir, array $pages = []): array
203
    {
204
        $files = array_reverse(scandir($dir));
2✔
205

206
        foreach ($files as $file) {
2✔
207
            if ('.' === $file || '..' === $file) {
2✔
208
                continue;
2✔
209
            }
210

211
            $path = '/' . $file;
2✔
212
            if (is_dir($dir . $path)) {
2✔
213
                $result = $this->scanPages($rootDir, $dir . $path);
1✔
214
                // Ignore empty array
215
                if ($result) {
1✔
216
                    if (isset($pages[$path])) {
1✔
217
                        $pages[$path] = array_merge_recursive($result, $pages[$path]);
×
218
                    } else {
219
                        $pages[$path] = $result;
1✔
220
                    }
221
                }
222
                continue;
1✔
223
            }
224

225
            if ('index.php' === $file) {
2✔
226
                $pages += ['file' => 'index.php', 'path' => $rootDir];
2✔
227
                continue;
2✔
228
            }
229

230
            // TODO better support for views
231
            $info = pathinfo($file);
1✔
232
            // Ignore file start with underscore
233
            if ('_' !== substr($info['basename'], 0, 1) && 'php' === $info['extension']) {
1✔
234
                $pages[$path] = ['path' => $rootDir];
1✔
235
            }
236
        }
237
        return $pages;
2✔
238
    }
239

240
    /**
241
     * @param string|array $next
242
     * @param bool $hasNext
243
     * @return bool
244
     */
245
    private function isEnded($next, bool $hasNext): bool
246
    {
247
        if (isset($next['file']) || isset($next['name'])) {
26✔
248
            return true;
15✔
249
        }
250
        return !$hasNext;
15✔
251
    }
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc