PhpFileSchemaProvider::removeFile()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 13
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Provider;
6
7
use Cycle\Schema\Provider\Exception\ConfigurationException;
8
use Cycle\Schema\Provider\Exception\SchemaProviderException;
9
use Cycle\Schema\Renderer\PhpSchemaRenderer;
10
use Spiral\Files\Files;
11
use Spiral\Files\FilesInterface;
12
13
final class PhpFileSchemaProvider implements SchemaProviderInterface
14
{
15
    public const MODE_READ_AND_WRITE = 0;
16
    public const MODE_WRITE_ONLY = 1;
17
18
    private string $file = '';
19
    private int $mode = self::MODE_READ_AND_WRITE;
20
21
    /**
22
     * @var \Closure(non-empty-string): non-empty-string
23
     */
24
    private \Closure $pathResolver;
25
    private FilesInterface $files;
26
27
    /**
28
     * @param null|callable(non-empty-string): non-empty-string $pathResolver A function that resolves
29
     *        framework-specific file paths.
30
     */
31 12
    public function __construct(?callable $pathResolver = null, ?FilesInterface $files = null)
32
    {
33 12
        $this->files = $files ?? new Files();
34
        /** @psalm-suppress PropertyTypeCoercion */
35 12
        $this->pathResolver = $pathResolver === null
36 12
            ? static fn (string $path): string => $path
37 12
            : \Closure::fromCallable($pathResolver);
38
    }
39
40
    /**
41
     * Create a configuration array for the {@see self::withConfig()} method.
42
     */
43 1
    public static function config(string $file, int $mode = self::MODE_READ_AND_WRITE): array
44
    {
45 1
        return [
46 1
            'file' => $file,
47 1
            'mode' => $mode,
48 1
        ];
49
    }
50
51 10
    public function withConfig(array $config): self
52
    {
53 10
        $new = clone $this;
54
55
        // required option
56 10
        if ($this->file === '' && !array_key_exists('file', $config)) {
57 1
            throw new ConfigurationException('The `file` parameter is required.');
58
        }
59 9
        $new->file = ($this->pathResolver)($config['file']);
60
61 9
        $new->mode = $config['mode'] ?? $this->mode;
62
63 9
        return $new;
64
    }
65
66 8
    public function read(?SchemaProviderInterface $nextProvider = null): ?array
67
    {
68 8
        if (!$this->isReadable()) {
69 4
            if ($nextProvider === null) {
70 2
                throw new SchemaProviderException(__CLASS__ . ' can not read schema.');
71
            }
72 2
            $schema = null;
73
        } else {
74
            /** @psalm-suppress UnresolvableInclude */
75 4
            $schema = !$this->files->isFile($this->file) ? null : (include $this->file);
76
        }
77
78 6
        if ($schema !== null || $nextProvider === null) {
79 2
            return $schema;
80
        }
81
82 4
        $schema = $nextProvider->read();
83 4
        if ($schema !== null) {
84 3
            $this->write($schema);
85
        }
86 3
        return $schema;
87
    }
88
89 3
    public function clear(): bool
90
    {
91
        try {
92 3
            return $this->removeFile();
93 1
        } catch (\Throwable $e) {
94 1
            return false;
95
        }
96
    }
97
98 3
    private function write(array $schema): bool
99
    {
100 3
        if (\basename($this->file) === '') {
101 1
            throw new SchemaProviderException('The `file` parameter must not be empty.');
102
        }
103
104 2
        $content = (new PhpSchemaRenderer())->render($schema);
105 2
        $this->files->write($this->file, $content, 0777, true);
106
107 2
        return true;
108
    }
109
110 3
    private function removeFile(): bool
111
    {
112 3
        if (!$this->files->exists($this->file)) {
113 1
            return true;
114
        }
115 2
        if (!$this->files->isFile($this->file)) {
116 1
            throw new SchemaProviderException(\sprintf('`%s` is not a file.', $this->file));
117
        }
118 1
        if (!\is_writable($this->file)) {
119
            throw new SchemaProviderException(\sprintf('File `%s` is not writeable.', $this->file));
120
        }
121
122 1
        return $this->files->delete($this->file);
123
    }
124
125 8
    private function isReadable(): bool
126
    {
127 8
        return $this->mode !== self::MODE_WRITE_ONLY;
128
    }
129
}
130