1 | <?php |
||
2 | App::uses('AppModel', 'Model'); |
||
3 | App::uses('Xml', 'Utility'); |
||
4 | |||
5 | /** |
||
6 | * Edexml Model. |
||
7 | * |
||
8 | */ |
||
9 | class Edexml extends AppModel { |
||
0 ignored issues
–
show
|
|||
10 | |||
11 | /** |
||
12 | * Use table |
||
13 | * |
||
14 | * @var mixed False or table name |
||
15 | */ |
||
16 | public $useTable = false; |
||
17 | |||
18 | /** |
||
19 | * The (translation) domain to be used for extracted validation messages in models. |
||
20 | * |
||
21 | * @var string |
||
22 | */ |
||
23 | public $validationDomain = 'edexml'; |
||
24 | |||
25 | /** |
||
26 | * Validation rules |
||
27 | * |
||
28 | * @var array |
||
29 | */ |
||
30 | public $validate = [ |
||
31 | 'file' => [ |
||
32 | 'uploadError' => [ |
||
33 | 'rule' => 'uploadError', |
||
34 | 'message' => 'File upload failed', |
||
35 | 'last' => true |
||
36 | ], |
||
37 | 'extension' => [ |
||
38 | 'rule' => ['extension', ['xml']], |
||
39 | 'message' => 'Must be a xml file', |
||
40 | 'last' => true |
||
41 | ], |
||
42 | 'fileSize' => [ |
||
43 | 'rule' => ['fileSize', '<=', '1MB'], |
||
44 | 'message' => 'Must be smaller than 1MB', |
||
45 | 'last' => true |
||
46 | ], |
||
47 | 'mimeType' => [ |
||
48 | 'rule' => ['mimeType', ['application/xml', 'text/xml']], |
||
49 | 'message' => 'Must be of type `xml`' |
||
50 | ], |
||
51 | 'edexml' => [ |
||
52 | 'rule' => 'validateEdexml', |
||
53 | 'message' => 'Must be a valid Edexml file' |
||
54 | ] |
||
55 | ] |
||
56 | ]; |
||
57 | |||
58 | /** |
||
59 | * Year group to grade mapping |
||
60 | * |
||
61 | * @var array |
||
62 | */ |
||
63 | protected $_yearGroupToGradeMapping = [ |
||
64 | 'B' => 1, // Baby's leeftijd 0 tot 12 maanden |
||
65 | 'D' => 1, // Dreumesen leeftijd 1 tot 2 jaar |
||
66 | 0 => 1, // Peutergroep / Kleutergroep 1 |
||
67 | 1 => 1, // Groep 1 / Kleutergroep 2 |
||
68 | 2 => 2, // Groep 2 / Kleutergroep 3 |
||
69 | 3 => 3, // Groep 3 / Klas 1 |
||
70 | 4 => 4, // Groep 4 / Klas 2 |
||
71 | 5 => 5, // Groep 5 / Klas 3 |
||
72 | 6 => 6, // Groep 6 / Klas 4 |
||
73 | 7 => 7, // Groep 7 / Klas 5 |
||
74 | 8 => 8, // Groep 8 / Klas 6 |
||
75 | 11 => 9, // Voortgezet onderwijs leerjaar 1 / Secundair onderwijs leerjaar 1 (Vlaanderen) |
||
76 | 12 => 10, // Voortgezet onderwijs leerjaar 2 / Secundair onderwijs leerjaar 2 (Vlaanderen) |
||
77 | 13 => 11, // Voortgezet onderwijs leerjaar 3 / Secundair onderwijs leerjaar 3 (Vlaanderen) |
||
78 | 14 => 12, // Voortgezet onderwijs leerjaar 4 / Secundair onderwijs leerjaar 4 (Vlaanderen) |
||
79 | 15 => 13, // Voortgezet onderwijs leerjaar 5 / Secundair onderwijs leerjaar 5 (Vlaanderen) |
||
80 | 16 => 14, // Voortgezet onderwijs leerjaar 6 / Secundair onderwijs leerjaar 6 (Vlaanderen) |
||
81 | 'S' => 19, // S(B)O (speciaal (basis)onderwijs / BuO (buitengewoon kleuter/lager onderwijs, Vlaanderen) |
||
82 | 'V' => null, // VSO (voortgezet speciaal onderwijs) / BuSO (buitengewoon secundair onderwijs, Vlaanderen) |
||
83 | 'C' => null, // Combinatiegroep (jaargroep per leerling vastgelegd) |
||
84 | 'N' => 19, // Niet PO / VO |
||
85 | 'H' => null // Historisch |
||
86 | ]; |
||
87 | |||
88 | /** |
||
89 | * School Classes |
||
90 | * |
||
91 | * @var array |
||
92 | */ |
||
93 | protected $_schoolClasses = []; |
||
94 | |||
95 | /** |
||
96 | * An Edexml file validation function to be used in Models. |
||
97 | * |
||
98 | * @param array $check Model data for a file upload ('field' => 'value') |
||
99 | * @return bool Whether or not the Edexml file is valid |
||
100 | */ |
||
101 | public function validateEdexml($check) { |
||
102 | $value = array_shift($check); |
||
103 | |||
104 | return (bool)$this->_parse($value['tmp_name']); |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * Convert XML file to DOMDocument and validate against Edexml XSD |
||
109 | * |
||
110 | * @param string $filename Filename of XML file |
||
111 | * @return bool|DOMDocument A DOMDocument, or false on validation errors |
||
112 | */ |
||
113 | protected function _parse($filename) { |
||
114 | if (!file_exists($filename)) { |
||
115 | return false; |
||
116 | } |
||
117 | |||
118 | // Enable user error handling |
||
119 | libxml_use_internal_errors(true); |
||
120 | libxml_clear_errors(); |
||
121 | |||
122 | $dom = Xml::build($filename, ['return' => 'domdocument']); |
||
123 | if (!$dom) { |
||
124 | return false; |
||
125 | } |
||
126 | |||
127 | $schemaFile = CakePlugin::path('Edexml') . 'File' . DS . 'EDEXML-2.1' . DS . 'EDEXML.structuur.xsd'; |
||
0 ignored issues
–
show
The type
CakePlugin was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
128 | if (!$dom->schemaValidate($schemaFile)) { |
||
129 | foreach (libxml_get_errors() as $error) { |
||
130 | CakeLog::error($this->_displayXmlError($error), 'debug'); |
||
0 ignored issues
–
show
The type
CakeLog was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
131 | } |
||
132 | |||
133 | libxml_clear_errors(); |
||
134 | |||
135 | return false; |
||
136 | } |
||
137 | |||
138 | return $dom; |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Parse XML into array |
||
143 | * |
||
144 | * @param string $filename Filename of XML file to parse |
||
145 | * @return mixed data (array), or false (boolean) on failure |
||
146 | */ |
||
147 | public function parseToArray($filename) { |
||
148 | $data = $this->_parse($filename); |
||
149 | if ($data) { |
||
150 | $data = Xml::toArray($data); |
||
151 | } |
||
152 | |||
153 | return $data; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Convert libXMLError to human-readable string |
||
158 | * |
||
159 | * @param libXMLError $error A libXMLError error |
||
160 | * @return string Human-readable string |
||
161 | */ |
||
162 | protected function _displayXmlError($error) { |
||
163 | $return = ''; |
||
164 | $return .= str_repeat('-', $error->column) . "^\n"; |
||
165 | |||
166 | switch ($error->level) { |
||
167 | case LIBXML_ERR_WARNING: |
||
168 | $return .= "Warning $error->code: "; |
||
169 | break; |
||
170 | case LIBXML_ERR_ERROR: |
||
171 | $return .= "Error $error->code: "; |
||
172 | break; |
||
173 | case LIBXML_ERR_FATAL: |
||
174 | $return .= "Fatal Error $error->code: "; |
||
175 | break; |
||
176 | } |
||
177 | |||
178 | $return .= trim($error->message) . |
||
179 | "\n Line: $error->line" . |
||
180 | "\n Column: $error->column"; |
||
181 | |||
182 | return "$return\n\n--------------------------------------------\n\n"; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Convert Edexml key to reusable key |
||
187 | * |
||
188 | * @param string $key Edexml key |
||
189 | * @return mixed Edexml key (string), or null (null) when key is not reusable |
||
190 | */ |
||
191 | protected function _convertKey($key) { |
||
192 | $result = null; |
||
193 | if (is_string($key) && substr($key, 0, 1) !== '#') { |
||
194 | $result = $key; |
||
195 | } |
||
196 | |||
197 | return $result; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Extract names (first and last name) from user element in extracted Edexml data |
||
202 | * |
||
203 | * @param array $user User element from extracted Edexml data |
||
204 | * @return array Normalized data (first name and last name) |
||
205 | */ |
||
206 | protected function _convertNames($user) { |
||
207 | $result = [ |
||
208 | 'first_name' => '', |
||
209 | 'last_name' => '' |
||
210 | ]; |
||
211 | |||
212 | if (!empty($user['voorvoegsel'])) { |
||
213 | $result['last_name'] .= $user['voorvoegsel'] . ' '; |
||
214 | } |
||
215 | if (!empty($user['achternaam'])) { |
||
216 | $result['last_name'] .= $user['achternaam']; |
||
217 | } |
||
218 | |||
219 | if (empty($result['first_name']) && !empty($user['roepnaam'])) { |
||
220 | $result['first_name'] = $user['roepnaam']; |
||
221 | } |
||
222 | if (empty($result['first_name']) && !empty($user['voornamen'])) { |
||
223 | $result['first_name'] = $user['voornamen']; |
||
224 | } |
||
225 | if (empty($result['first_name']) && !empty($user['voorletters-1'])) { |
||
226 | $result['first_name'] = $user['voorletters-1']; |
||
227 | } |
||
228 | |||
229 | return $result; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Convert school element in extracted Edexml data to normalized data |
||
234 | * |
||
235 | * @param array $school School element from extracted Edexml data |
||
236 | * @return array Normalized data |
||
237 | */ |
||
238 | protected function _convertSchool($school) { |
||
239 | $result = [ |
||
240 | 'key' => null |
||
241 | ]; |
||
242 | if (!empty($school['schoolkey'])) { |
||
243 | $result['key'] = $this->_convertKey($school['schoolkey']); |
||
244 | } |
||
245 | |||
246 | return $result; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Convert school class element in extracted Edexml data to normalized data |
||
251 | * |
||
252 | * @param array $schoolClass School class element from extracted Edexml data |
||
253 | * @return array Normalized data |
||
254 | */ |
||
255 | protected function _convertSchoolClass($schoolClass) { |
||
256 | $result = [ |
||
257 | 'key' => null, |
||
258 | 'grade' => null |
||
259 | ]; |
||
260 | if (!empty($schoolClass['@key'])) { |
||
261 | $result['key'] = $this->_convertKey($schoolClass['@key']); |
||
262 | } |
||
263 | $result['name'] = $schoolClass['naam']; |
||
264 | $result['grade'] = $this->_yearGroupToGradeMapping[$schoolClass['jaargroep']]; |
||
265 | |||
266 | return $result; |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * Convert school element in extracted Edexml data to normalized data |
||
271 | * |
||
272 | * @param array $schoolClasses School classes element from extracted Edexml data |
||
273 | * @return array Normalized data |
||
274 | */ |
||
275 | protected function _convertSchoolClasses($schoolClasses) { |
||
276 | $result = []; |
||
277 | if (!empty($schoolClasses)) { |
||
278 | foreach ($schoolClasses as $schoolClass) { |
||
279 | $result[$schoolClass['@key']] = $this->_convertSchoolClass($schoolClass); |
||
280 | } |
||
281 | } |
||
282 | |||
283 | return $result; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Convert student element in extracted Edexml data to normalized data |
||
288 | * |
||
289 | * @param array $student Student element from extracted Edexml data |
||
290 | * @return array Normalized data |
||
291 | */ |
||
292 | protected function _convertStudent($student) { |
||
293 | $result = [ |
||
294 | 'key' => null, |
||
295 | 'date_of_birth' => null, |
||
296 | 'gender' => null, |
||
297 | 'grade' => null, |
||
298 | 'SchoolClass' => [] |
||
299 | ]; |
||
300 | |||
301 | if (!empty($student['@key'])) { |
||
302 | $result['key'] = $this->_convertKey($student['@key']); |
||
303 | } |
||
304 | |||
305 | if (!empty($student['@eckid'])) { |
||
306 | $result['eckid'] = $student['@eckid']; |
||
307 | } |
||
308 | |||
309 | $result = array_merge($result, $this->_convertNames($student)); |
||
310 | if (!empty($student['geboortedatum'])) { |
||
311 | if (strtotime($student['geboortedatum'])) { |
||
312 | $result['date_of_birth'] = $student['geboortedatum']; |
||
313 | } |
||
314 | } |
||
315 | |||
316 | if (!empty($student['geslacht'])) { |
||
317 | switch ($student['geslacht']) { |
||
318 | case 1: |
||
319 | $result['gender'] = 'm'; |
||
320 | break; |
||
321 | case 2: |
||
322 | $result['gender'] = 'f'; |
||
323 | break; |
||
324 | } |
||
325 | } |
||
326 | |||
327 | if (!empty($student['groep']['@key'])) { |
||
328 | $result['SchoolClass'][$student['groep']['@key']] = $this->_schoolClasses[$student['groep']['@key']]; |
||
329 | $result['grade'] = $this->_schoolClasses[$student['groep']['@key']]['grade']; |
||
330 | } |
||
331 | |||
332 | if (!empty($student['jaargroep'])) { |
||
333 | $result['grade'] = $this->_yearGroupToGradeMapping[$student['jaargroep']]; |
||
334 | } |
||
335 | |||
336 | return $result; |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Convert teacher element in extracted Edexml data to normalized data |
||
341 | * |
||
342 | * @param array $teacher Teacher element from extracted Edexml data |
||
343 | * @return array Normalized data |
||
344 | */ |
||
345 | protected function _convertTeacher($teacher) { |
||
346 | $result = [ |
||
347 | 'key' => null, |
||
348 | 'date_of_birth' => null, |
||
349 | 'gender' => null, |
||
350 | 'grade' => null, |
||
351 | 'email_address' => null, |
||
352 | 'SchoolClass' => [] |
||
353 | ]; |
||
354 | |||
355 | if (!empty($teacher['@key'])) { |
||
356 | $result['key'] = $this->_convertKey($teacher['@key']); |
||
357 | } |
||
358 | |||
359 | if (!empty($teacher['@eckid'])) { |
||
360 | $result['eckid'] = $teacher['@eckid']; |
||
361 | } |
||
362 | |||
363 | $result = array_merge($result, $this->_convertNames($teacher)); |
||
364 | |||
365 | if (!empty($teacher['emailadres'])) { |
||
366 | $result['email_address'] = $teacher['emailadres']; |
||
367 | } |
||
368 | |||
369 | if (!empty($teacher['groepen']['groep'])) { |
||
370 | if (!Hash::numeric(array_keys($teacher['groepen']['groep']))) { |
||
371 | $teacher['groepen']['groep'] = [$teacher['groepen']['groep']]; |
||
372 | } |
||
373 | |||
374 | foreach ($teacher['groepen']['groep'] as $groep) { |
||
375 | $result['SchoolClass'][$groep['@key']] = $this->_schoolClasses[$groep['@key']]; |
||
376 | } |
||
377 | } |
||
378 | |||
379 | return $result; |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * Convert extracted Edexml data to normalized data |
||
384 | * |
||
385 | * @param array $data Extracted Edexml data |
||
386 | * @return array Normalized data |
||
387 | */ |
||
388 | public function convert($data) { |
||
389 | $result = []; |
||
390 | |||
391 | $result['school'] = $this->_convertSchool($data['EDEX']['school']); |
||
392 | |||
393 | if (!empty($data['EDEX']['groepen']['groep'])) { |
||
394 | if (!Hash::numeric(array_keys($data['EDEX']['groepen']['groep']))) { |
||
395 | $data['EDEX']['groepen']['groep'] = [$data['EDEX']['groepen']['groep']]; |
||
396 | } |
||
397 | |||
398 | $this->_schoolClasses = $this->_convertSchoolClasses($data['EDEX']['groepen']['groep']); |
||
399 | $result['SchoolClass'] = $this->_schoolClasses; |
||
400 | } |
||
401 | |||
402 | if (!empty($data['EDEX']['leerlingen']['leerling'])) { |
||
403 | if (!Hash::numeric(array_keys($data['EDEX']['leerlingen']['leerling']))) { |
||
404 | $data['EDEX']['leerlingen']['leerling'] = [$data['EDEX']['leerlingen']['leerling']]; |
||
405 | } |
||
406 | foreach ($data['EDEX']['leerlingen']['leerling'] as $i => $student) { |
||
407 | $result['Student'][$i] = $this->_convertStudent($student); |
||
408 | } |
||
409 | } |
||
410 | |||
411 | if (!empty($data['EDEX']['leerkrachten']['leerkracht'])) { |
||
412 | if (!Hash::numeric(array_keys($data['EDEX']['leerkrachten']['leerkracht']))) { |
||
413 | $data['EDEX']['leerkrachten']['leerkracht'] = [$data['EDEX']['leerkrachten']['leerkracht']]; |
||
414 | } |
||
415 | |||
416 | foreach ($data['EDEX']['leerkrachten']['leerkracht'] as $i => $teacher) { |
||
417 | $result['Teacher'][$i] = $this->_convertTeacher($teacher); |
||
418 | } |
||
419 | } |
||
420 | |||
421 | return $result; |
||
422 | } |
||
423 | } |
||
424 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths