Passed
Pull Request — master (#196)
by Rustam
13:36
created

FileRoutesProvider   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 66
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 31
c 2
b 0
f 0
dl 0
loc 66
ccs 37
cts 37
cp 1
rs 10
wmc 15

3 Methods

Rating   Name   Duplication   Size   Complexity  
A isRoutesAreValid() 0 10 4
A __construct() 0 2 1
B getRoutes() 0 45 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router\Provider;
6
7
use Closure;
8
use Yiisoft\Router\Group;
9
use Yiisoft\Router\Route;
10
11
/**
12
 * A file provider provides routes from a file or directory of files.
13
 */
14
final class FileRoutesProvider implements RoutesProviderInterface
15
{
16 4
    public function __construct(private string $file, private array $scope = [])
17
    {
18 4
    }
19
20 4
    public function getRoutes(): array
21
    {
22
        /** @var Closure $scopeRequire */
23 4
        $scopeRequire = Closure::bind(static function (string $file, array $scope): mixed {
24 3
            extract($scope, EXTR_SKIP);
25
            /**
26
             * @psalm-suppress UnresolvableInclude
27
             */
28 3
            return require $file;
29 4
        }, null);
30 4
        if (!file_exists($this->file)) {
31 1
            throw new \RuntimeException(
32 1
                'Failed to provide routes from "' . $this->file . '". File or directory not found.'
33 1
            );
34
        }
35 3
        if (is_dir($this->file) && !is_file($this->file)) {
36 1
            $directoryRoutes = [];
37 1
            $files = new \CallbackFilterIterator(
38 1
                new \FilesystemIterator(
39 1
                    $this->file,
40 1
                    \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS
41 1
                ),
42 1
                fn (\SplFileInfo $fileInfo) => $fileInfo->isFile() && $fileInfo->getExtension() === 'php'
43 1
            );
44
            /** @var \SplFileInfo[] $files */
45 1
            foreach ($files as $file) {
46
                /** @var mixed $fileRoutes */
47 1
                $fileRoutes = $scopeRequire($file->getRealPath(), $this->scope);
48 1
                if (is_array($fileRoutes) && $this->isRoutesAreValid($fileRoutes)) {
49 1
                    array_push(
50 1
                        $directoryRoutes,
51 1
                        ...$fileRoutes
52 1
                    );
53
                }
54
            }
55 1
            return $directoryRoutes;
56
        }
57
58
        /** @var mixed $routes */
59 2
        $routes = $scopeRequire($this->file, $this->scope);
60 2
        if (is_array($routes) && $this->isRoutesAreValid($routes)) {
61 1
            return $routes;
62
        }
63
64 1
        return [];
65
    }
66
67
    /**
68
     * @psalm-assert-if-true Route[]|Group[] $routes
69
     */
70 3
    private function isRoutesAreValid(array $routes): bool
71
    {
72 3
        foreach ($routes as $route) {
73
            if (
74 3
                !is_a($route, Route::class, true) && !is_a($route, Group::class, true)
75
            ) {
76 2
                return false;
77
            }
78
        }
79 2
        return true;
80
    }
81
}
82