-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFromFilesSchemaProvider.php
129 lines (110 loc) · 3.55 KB
/
FromFilesSchemaProvider.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
declare(strict_types=1);
namespace Cycle\Schema\Provider;
use Cycle\Schema\Provider\Exception\ConfigurationException;
use Cycle\Schema\Provider\Exception\SchemaFileNotFoundException;
use Webmozart\Glob\Glob;
use Webmozart\Glob\Iterator\GlobIterator;
use Cycle\Schema\Provider\Support\SchemaMerger;
/**
* Be careful, using this class may be insecure.
*/
final class FromFilesSchemaProvider implements SchemaProviderInterface
{
/**
* @var array<non-empty-string> Schema files
*/
private array $files = [];
/**
* @var bool Throw exception if file not found
*/
private bool $strict = false;
/**
* @var \Closure(non-empty-string): non-empty-string
*/
private \Closure $pathResolver;
/**
* @param null|callable(non-empty-string): non-empty-string $pathResolver A function that resolves
* framework-specific file paths.
*/
public function __construct(?callable $pathResolver = null)
{
/** @psalm-suppress PropertyTypeCoercion */
$this->pathResolver = $pathResolver === null
? static fn (string $path): string => $path
: \Closure::fromCallable($pathResolver);
}
/**
* Create a configuration array for the {@see self::withConfig()} method.
* @param array<non-empty-string> $files
*/
public static function config(array $files, bool $strict = false): array
{
return [
'files' => $files,
'strict' => $strict,
];
}
public function withConfig(array $config): self
{
$files = $config['files'] ?? [];
if (!\is_array($files)) {
throw new ConfigurationException('The `files` parameter must be an array.');
}
if (\count($files) === 0) {
throw new ConfigurationException('Schema file list is not set.');
}
$strict = $config['strict'] ?? $this->strict;
if (!\is_bool($strict)) {
throw new ConfigurationException('The `strict` parameter must be a boolean.');
}
$files = \array_map(
function (mixed $file) {
if (!\is_string($file) || $file === '') {
throw new ConfigurationException('The `files` parameter must contain non-empty string values.');
}
return ($this->pathResolver)($file);
},
$files
);
$new = clone $this;
$new->files = $files;
$new->strict = $strict;
return $new;
}
public function read(?SchemaProviderInterface $nextProvider = null): ?array
{
$schema = (new SchemaMerger())->merge(...$this->readFiles());
return $schema !== null || $nextProvider === null ? $schema : $nextProvider->read();
}
public function clear(): bool
{
return false;
}
/**
* Read schema from each file
*
* @return \Generator<int, array|null>
*/
private function readFiles(): \Generator
{
foreach ($this->files as $path) {
$path = \str_replace('\\', '/', $path);
if (!Glob::isDynamic($path)) {
yield $this->loadFile($path);
continue;
}
foreach (new GlobIterator($path) as $file) {
yield $this->loadFile($file);
}
}
}
private function loadFile(string $path): ?array
{
$isFile = \is_file($path);
if (!$isFile && $this->strict) {
throw new SchemaFileNotFoundException($path);
}
return $isFile ? require $path : null;
}
}