Passed
Push — master ( d5dda9...c69dbe )
by Alexander
02:26
created

PhpFileSchemaProvider::read()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 20
ccs 12
cts 12
cp 1
rs 8.8333
cc 7
nc 10
nop 1
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\Schema\Provider;
6
7
use Cycle\ORM\Schema;
8
use RuntimeException;
9
use Yiisoft\Aliases\Aliases;
10
use Yiisoft\Yii\Cycle\Schema\Converter\SchemaToPHP;
11
use Yiisoft\Yii\Cycle\Schema\SchemaProviderInterface;
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
    private Aliases $aliases;
22
23 11
    public function __construct(Aliases $aliases)
24
    {
25 11
        $this->aliases = $aliases;
26 11
    }
27
28 10
    public function withConfig(array $config): self
29
    {
30 10
        $new = clone $this;
31
32
        // required option
33 10
        if ($this->file === '' && !array_key_exists('file', $config)) {
34 1
            throw new \InvalidArgumentException('The "file" parameter is required.');
35
        }
36 9
        $new->file = $this->aliases->get($config['file']);
37
38 9
        $new->mode = $config['mode'] ?? $this->mode;
39
40 9
        return $new;
41
    }
42
43 7
    public function read(?SchemaProviderInterface $nextProvider = null): ?array
44
    {
45 7
        if (!$this->isReadable()) {
46 4
            if ($nextProvider === null) {
47 2
                throw new RuntimeException(__CLASS__ . ' can not read schema.');
48
            }
49 2
            $schema = null;
50
        } else {
51 3
            $schema = !is_file($this->file) ? null : (include $this->file);
52
        }
53
54 5
        if ($schema !== null || $nextProvider === null) {
55 2
            return $schema;
56
        }
57
58 3
        $schema = $nextProvider->read();
59 3
        if ($schema !== null) {
60 2
            $this->write($schema);
61
        }
62 3
        return $schema;
63
    }
64
65 2
    private function write(array $schema): bool
66
    {
67 2
        if (basename($this->file) === '') {
68
            throw new RuntimeException('The "file" parameter must not be empty.');
69
        }
70 2
        $dirname = dirname($this->file);
71 2
        if ($dirname !== '' && !is_dir($dirname)) {
72
            mkdir($dirname, 0777, true);
73
        }
74
75 2
        $content = (new SchemaToPHP(new Schema($schema)))->convert();
76 2
        file_put_contents($this->file, $content, LOCK_EX);
77 2
        return true;
78
    }
79
80 3
    private function removeFile(): void
81
    {
82 3
        if (!file_exists($this->file)) {
83 1
            return;
84
        }
85 2
        if (!is_file($this->file)) {
86 1
            throw new RuntimeException("`$this->file` is not a file.");
87
        }
88 1
        if (!is_writable($this->file)) {
89
            throw new RuntimeException("File `$this->file` is not writeable.");
90
        }
91 1
        unlink($this->file);
92 1
    }
93
94 3
    public function clear(): bool
95
    {
96
        try {
97 3
            $this->removeFile();
98 1
        } catch (\Throwable $e) {
99 1
            return false;
100
        }
101 2
        return true;
102
    }
103
104 7
    private function isReadable(): bool
105
    {
106 7
        return $this->mode !== self::MODE_WRITE_ONLY;
107
    }
108
}
109