Passed
Push — develop ( 8d04e4...f8d7bf )
by Freddie
03:08
created

Schema::setIcon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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
        \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
        \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
            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
                    ];
165
                }
166
167 2
                return $result;
168 2
            },
169 2
            []
170
        );
171
    }
172
173 46
    private function setName(string $name): void
174
    {
175 46
        if (empty(\trim($name))) {
176 4
            throw new InvalidSchemaException('Schema name is required');
177
        }
178
179 42
        if (\preg_match('#^[a-zA-Z]\w*$#', $name) === 0) {
180 3
            throw new InvalidSchemaException('Schema name only accept alphanum and underscore');
181
        }
182
183 39
        $this->name = $name;
184 39
    }
185
186 39
    private function setTitle(string $title): void
187
    {
188 39
        if (empty(\trim($title))) {
189 5
            throw new InvalidSchemaException(\sprintf('Schema %s:title is required', $this->name()));
190
        }
191
192 34
        $this->title = $title;
193 34
    }
194
195 34
    private function setAttributes(array $attributes): void
196
    {
197 34
        $schemaAttributes = [];
198
199 34
        foreach ($attributes as $attribute) {
200 16
            if ($attribute instanceof SchemaAttributeInterface) {
201 2
                $schemaAttributes[] = $attribute;
202
203 2
                continue;
204
            }
205
206 14
            $name = $attribute[Keyword::NAME] ?? '';
207 14
            $dataType = $attribute[Keyword::DATATYPE] ?? '';
208 14
            $constraints = $attribute[Keyword::CONSTRAINTS] ?? '';
209
210
            try {
211 14
                $schemaAttributes[] = new SchemaAttribute($name, $dataType, $constraints);
212 2
            } catch (Exception $exception) {
213 2
                throw new InvalidSchemaException(
214 2
                    \sprintf('Schema %s > %s', $this->name(), $exception->getMessage())
215
                );
216
            }
217
        }
218
219 32
        $this->attributes = $schemaAttributes;
220 32
    }
221
222 32
    private function setIcon(?string $icon): void
223
    {
224 32
        $this->icon = $icon;
225 32
    }
226
227 32
    private function setLanguage(?string $language): void
228
    {
229 32
        if (!empty($language)) {
230
            $this->language = $language;
231
        }
232 32
    }
233
234 32
    private function setActions(array $actions): void
235
    {
236 32
        $invalidActions = [];
237
238 32
        if (empty($actions)) {
239 10
            $actions = [Action::INDEX, Action::CREATE, Action::READ, Action::UPDATE, Action::DELETE];
240
        }
241
242 32
        foreach ($actions as $action) {
243 32
            if (!\in_array($action, [
244
                Action::INDEX,
245
                Action::CREATE,
246
                Action::READ,
247
                Action::UPDATE,
248
                Action::DELETE,
249
                Action::FILTER,
250
            ])) {
251 16
                $invalidActions[] = $action;
252
            }
253
        }
254
255 32
        if (\count($invalidActions) > 0) {
256 16
            throw new InvalidSchemaException(
257 16
                \sprintf('Schema %s:action are invalid: %s', $this->name(), \implode(',', $invalidActions))
258
            );
259
        }
260
261 16
        $this->actions = $actions;
262 16
    }
263
}
264