Passed
Push — master ( 463945...c0e83c )
by Bruno
08:14
created

Model::fromJSONFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php declare(strict_types=1);
2
3
namespace Formularium;
4
5
use Formularium\Exception\Exception;
6
7
/**
8
 * Model class, representing a whole object.
9
 */
10
class Model
11
{
12
    /**
13
     * @var string
14
     */
15
    protected $name;
16
17
    /**
18
     * @var Field[]
19
     */
20
    protected $fields;
21
22
    /**
23
     *
24
     * @param string $name
25
     * @throws Exception
26
     */
27 6
    protected function __construct(string $name = '')
28
    {
29 6
        $this->name = $name;
30 6
    }
31
32
    /**
33
     * Loads model from JSON file.
34
     *
35
     * @param array $struct
36
     * @return Model
37
     */
38 2
    public static function fromStruct(array $struct): Model
39
    {
40 2
        $m = new self('');
41 2
        $m->parseStruct($struct);
42 2
        return $m;
43
    }
44
45
    /**
46
     * Loads model from JSON file.
47
     *
48
     * @param string $name The JSON filename.
49
     * @return Model
50
     */
51
    public static function fromJSONFile(string $name): Model
52
    {
53
        $json = file_get_contents($name); // TODO: path
54
        if ($json === false) {
55
            throw new Exception('File not found');
56
        }
57
        return static::fromJSON($json);
58
    }
59
60
    /**
61
     * Loads model from JSON string
62
     *
63
     * @param string $json The JSON string.
64
     * @return Model
65
     */
66 5
    public static function fromJSON(string $json): Model
67
    {
68 5
        $data = \json_decode($json, true);
69 5
        if ($data === null) {
70 1
            throw new Exception('Invalid JSON format');
71
        }
72 4
        $m = new self('');
73 4
        $m->parseStruct($data);
74 1
        return $m;
75
    }
76
77 1
    public function getName(): string
78
    {
79 1
        return $this->name;
80
    }
81
82 1
    public function getFields(): array
83
    {
84 1
        return $this->fields;
85
    }
86
87
    /**
88
     * Validates a set of data against this model.
89
     *
90
     * @param array $data A field name => data array.
91
     * @return array
92
     */
93 1
    public function validate(array $data): array
94
    {
95 1
        $validate = [];
96 1
        $errors = [];
97 1
        foreach ($data as $name => $d) {
98 1
            if (!array_key_exists($name, $this->fields)) {
99
                $errors[$name] = "Field $name does not exist in this model";
100
                continue;
101
            }
102 1
            $field = $this->fields[$name];
103
            try {
104 1
                $validate[$name] = $field->getDatatype()->validate($d, $field);
105 1
            } catch (Exception $e) {
106 1
                $errors[$name] = $e->getMessage();
107
            }
108
        }
109 1
        foreach ($this->fields as $name => $field) {
110 1
            if (($field->getValidators()[Datatype::REQUIRED] ?? false)
111 1
                && !array_key_exists($name, $validate)
112 1
                && !array_key_exists($name, $errors)
113
            ) {
114 1
                $errors[$name] = "Field $name is missing";
115
            }
116
        }
117 1
        return ['validated' => $validate, 'errors' => $errors];
118
    }
119
120
    /**
121
     * Serializes this model to JSON.
122
     *
123
     * @return string
124
     */
125
    public function toJSON(): string
126
    {
127
        $fields = array_map(
128
            function ($f) {
129
                return [
130
                    'datatype' => $f->getDatatype()->getName(),
131
                    'validators' => $f->getValidators(),
132
                    'extensions' => $f->getExtensions()
133
                ];
134
            },
135
            $this->fields
136
        );
137
        $model = [
138
            'name' => $this->name,
139
            'fields' => $fields
140
        ];
141
        return json_encode($model);
142
    }
143
144
    /**
145
     * Renders a readonly view of the model with given data.
146
     *
147
     * @param array $modelData
148
     * @return string
149
     */
150
    public function viewable(array $modelData): string
151
    {
152
        return FrameworkComposer::viewable($this, $modelData);
153
    }
154
155
    /**
156
     * Renders a form view of the model with given data.
157
     *
158
     * @param array $modelData
159
     * @return string
160
     */
161
    public function editable(array $modelData = []): string
162
    {
163
        return FrameworkComposer::editable($this, $modelData);
164
    }
165
166 1
    public function getRandom(): array
167
    {
168 1
        $data = [];
169 1
        foreach ($this->fields as $f) {
170 1
            $data[$f->getName()] = $f->getDatatype()->getRandom();
171
        }
172 1
        return $data;
173
    }
174
175
    /**
176
     * Parses struct
177
     *
178
     * @param array $data
179
     * @throws Exception
180
     * @return void
181
     */
182 6
    protected function parseStruct(array $data)
183
    {
184 6
        if (!array_key_exists('name', $data)) {
185 1
            throw new Exception('Missing name in model');
186
        }
187 5
        if (!array_key_exists('fields', $data)) {
188 1
            throw new Exception('Missing fields in model');
189
        }
190 4
        $this->name = $data['name'];
191 4
        foreach ($data['fields'] as $fieldName => $fieldData) {
192 4
            $this->fields[$fieldName] = Field::getFromData($fieldName, $fieldData);
193
        }
194 3
    }
195
}
196