Schema::setTitle()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of FlexPHP.
4
 *
5
 * (c) Freddie Gar <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace FlexPHP\Schema;
11
12
use Exception;
13
use FlexPHP\Schema\Constants\Action;
14
use FlexPHP\Schema\Constants\Keyword;
15
use FlexPHP\Schema\Exception\InvalidFileSchemaException;
16
use FlexPHP\Schema\Exception\InvalidSchemaException;
17
use Symfony\Component\Yaml\Exception\ParseException;
18
use Symfony\Component\Yaml\Yaml;
19
20
final class Schema implements SchemaInterface
21
{
22
    private string $name;
23
24
    private string $title;
25
26
    /**
27
     * @var array<int,SchemaAttributeInterface>
28
     */
29
    private array $attributes = [];
30
31
    private ?string $icon = null;
32
33
    private string $language = 'en';
34
35
    private array $actions = [];
36
37 21
    public static function fromArray(array $schema): SchemaInterface
38
    {
39
        /** @var string $name */
40 21
        $name = \key($schema) ?? '';
41 21
        $title = $schema[$name][Keyword::TITLE] ?? '';
42 21
        $attributes = $schema[$name][Keyword::ATTRIBUTES] ?? [];
43 21
        $icon = $schema[$name][Keyword::ICON] ?? null;
44 21
        $language = $schema[$name][Keyword::LANGUAGE] ?? null;
45 21
        $actions = $schema[$name][Keyword::ACTIONS] ?? [];
46
47 21
        if (\is_string($actions)) {
48 8
            $actions = \str_split($actions);
49
        }
50
51 21
        return new self($name, $title, $attributes, $icon, $language, $actions);
52
    }
53
54 3
    public static function fromFile(string $schemafile): SchemaInterface
55
    {
56
        try {
57 3
            $yaml = new Yaml();
58 3
            $schema = $yaml->parseFile($schemafile);
59 1
        } catch (ParseException $parseException) {
60 1
            throw new InvalidFileSchemaException();
61
        }
62
63 2
        return self::fromArray($schema);
64
    }
65
66 46
    public function __construct(
67
        string $name,
68
        string $title,
69
        array $attributes,
70
        ?string $icon = null,
71
        ?string $language = null,
72
        array $actions = []
73
    ) {
74 46
        $this->setName($name);
75 39
        $this->setTitle($title);
76 34
        $this->setAttributes($attributes);
77 32
        $this->setIcon($icon);
78 32
        $this->setLanguage($language);
79 32
        $this->setActions($actions);
80 16
    }
81
82 27
    public function name(): string
83
    {
84 27
        return $this->name;
85
    }
86
87 4
    public function title(): string
88
    {
89 4
        return $this->title;
90
    }
91
92 4
    public function attributes(): array
93
    {
94 4
        return $this->attributes;
95
    }
96
97 2
    public function icon(): ?string
98
    {
99 2
        return $this->icon;
100
    }
101
102 2
    public function language(): string
103
    {
104 2
        return $this->language;
105
    }
106
107 9
    public function actions(): array
108
    {
109 9
        return $this->actions;
110
    }
111
112 7
    public function hasAction(string $action): bool
113
    {
114 7
        return \in_array($action, $this->actions(), true);
115
    }
116
117 4
    public function pkName(): string
118
    {
119 4
        $pkName = 'id';
120
121 4
        \array_filter($this->attributes(), function (SchemaAttributeInterface $property) use (&$pkName) {
122 4
            if ($property->isPk()) {
123 2
                $pkName = $property->name();
124
            }
125
126 4
            return true;
127 4
        });
128
129 4
        return $pkName;
130
    }
131
132 2
    public function pkTypeHint(): string
133
    {
134 2
        $pkTypeHint = 'string';
135
136 2
        \array_filter($this->attributes(), function (SchemaAttributeInterface $property) use (&$pkTypeHint) {
137 2
            if ($property->isPk()) {
138 2
                $pkTypeHint = $property->typeHint();
139
            }
140
141 2
            return true;
142 2
        });
143
144 2
        return $pkTypeHint;
145
    }
146
147 2
    public function fkRelations(): array
148
    {
149 2
        return \array_reduce(
150 2
            $this->attributes(),
151 2
            function (array $result, SchemaAttributeInterface $property): array {
152 2
                if ($property->isfk()) {
153 2
                    $result[$property->name()] = [
154 2
                        'pkTable' => $property->fkTable(),
155 2
                        'pkId' => $property->name(),
156 2
                        'pkDataType' => $property->dataType(),
157 2
                        'pkTypeHint' => $property->typeHint(),
158 2
                        'fkId' => $property->fkId(),
159 2
                        'fkName' => $property->fkName(),
160 2
                        'fkTable' => $this->name(),
161 2
                        'isBlameBy' => $property->isBlameBy(),
162 2
                        'isRequired' => $property->isRequired(),
163 2
                        'minChars' => $property->fchars(),
164 2
                        'check' => $property->fkcheck(),
165
                    ];
166
                }
167
168 2
                return $result;
169 2
            },
170 2
            []
171
        );
172
    }
173
174 46
    private function setName(string $name): void
175
    {
176 46
        if (empty(\trim($name))) {
177 4
            throw new InvalidSchemaException('Schema name is required');
178
        }
179
180 42
        if (\preg_match('#^[a-zA-Z]\w*$#', $name) === 0) {
181 3
            throw new InvalidSchemaException('Schema name only accept alphanum and underscore');
182
        }
183
184 39
        $this->name = $name;
185 39
    }
186
187 39
    private function setTitle(string $title): void
188
    {
189 39
        if (empty(\trim($title))) {
190 5
            throw new InvalidSchemaException(\sprintf('Schema %s:title is required', $this->name()));
191
        }
192
193 34
        $this->title = $title;
194 34
    }
195
196 34
    private function setAttributes(array $attributes): void
197
    {
198 34
        $schemaAttributes = [];
199
200 34
        foreach ($attributes as $attribute) {
201 16
            if ($attribute instanceof SchemaAttributeInterface) {
202 2
                $schemaAttributes[] = $attribute;
203
204 2
                continue;
205
            }
206
207 14
            $name = $attribute[Keyword::NAME] ?? '';
208 14
            $dataType = $attribute[Keyword::DATATYPE] ?? '';
209 14
            $constraints = $attribute[Keyword::CONSTRAINTS] ?? '';
210
211
            try {
212 14
                $schemaAttributes[] = new SchemaAttribute($name, $dataType, $constraints);
213 2
            } catch (Exception $exception) {
214 2
                throw new InvalidSchemaException(
215 2
                    \sprintf('Schema %s > %s', $this->name(), $exception->getMessage())
216
                );
217
            }
218
        }
219
220 32
        $this->attributes = $schemaAttributes;
221 32
    }
222
223 32
    private function setIcon(?string $icon): void
224
    {
225 32
        $this->icon = $icon;
226 32
    }
227
228 32
    private function setLanguage(?string $language): void
229
    {
230 32
        if (!empty($language)) {
231
            $this->language = $language;
232
        }
233 32
    }
234
235 32
    private function setActions(array $actions): void
236
    {
237 32
        $invalidActions = [];
238
239 32
        if (empty($actions)) {
240 10
            $actions = [Action::INDEX, Action::CREATE, Action::READ, Action::UPDATE, Action::DELETE];
241
        }
242
243 32
        foreach ($actions as $action) {
244 32
            if (!\in_array($action, [
245
                Action::INDEX,
246
                Action::CREATE,
247
                Action::READ,
248
                Action::UPDATE,
249
                Action::PATCH,
250
                Action::DELETE,
251
                Action::FILTER,
252
            ])) {
253 16
                $invalidActions[] = $action;
254
            }
255
        }
256
257 32
        if (\count($invalidActions) > 0) {
258 16
            throw new InvalidSchemaException(
259 16
                \sprintf('Schema %s:action are invalid: %s', $this->name(), \implode(',', $invalidActions))
260
            );
261
        }
262
263 16
        $this->actions = $actions;
264 16
    }
265
}
266