Total Complexity | 195 |
Total Lines | 1119 |
Duplicated Lines | 0 % |
Changes | 7 | ||
Bugs | 1 | Features | 2 |
Complex classes like RestController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use RestController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
6 | class RestController extends Controller |
||
7 | { |
||
8 | /* supported MIME types that can be used to return RDF data */ |
||
9 | const SUPPORTED_FORMATS = 'application/rdf+xml text/turtle application/ld+json application/json application/marcxml+xml'; |
||
10 | /* context array template */ |
||
11 | private $context = array( |
||
12 | '@context' => array( |
||
13 | 'skos' => 'http://www.w3.org/2004/02/skos/core#', |
||
14 | 'uri' => '@id', |
||
15 | 'type' => '@type', |
||
16 | ), |
||
17 | ); |
||
18 | |||
19 | /** |
||
20 | * Handles json encoding, adding the content type headers and optional callback function. |
||
21 | * @param array $data the data to be returned. |
||
22 | */ |
||
23 | private function returnJson($data) |
||
24 | { |
||
25 | // wrap with JSONP callback if requested |
||
26 | if (filter_input(INPUT_GET, 'callback', FILTER_SANITIZE_STRING)) { |
||
27 | header("Content-type: application/javascript; charset=utf-8"); |
||
28 | echo filter_input(INPUT_GET, 'callback', FILTER_UNSAFE_RAW) . "(" . json_encode($data) . ");"; |
||
29 | return; |
||
30 | } |
||
31 | |||
32 | // otherwise negotiate suitable format for the response and return that |
||
33 | $negotiator = new \Negotiation\Negotiator(); |
||
|
|||
34 | $priorities = array('application/json', 'application/ld+json'); |
||
35 | $best = filter_input(INPUT_SERVER, 'HTTP_ACCEPT', FILTER_SANITIZE_STRING) ? $negotiator->getBest(filter_input(INPUT_SERVER, 'HTTP_ACCEPT', FILTER_SANITIZE_STRING), $priorities) : null; |
||
36 | $format = ($best !== null) ? $best->getValue() : $priorities[0]; |
||
37 | header("Content-type: $format; charset=utf-8"); |
||
38 | header("Vary: Accept"); // inform caches that we made a choice based on Accept header |
||
39 | echo json_encode($data); |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * Parses and returns the limit parameter. Returns and error if the parameter is missing. |
||
44 | */ |
||
45 | private function parseLimit() |
||
46 | { |
||
47 | $limit = filter_input(INPUT_GET, 'limit', FILTER_SANITIZE_NUMBER_INT) ? filter_input(INPUT_GET, 'limit', FILTER_SANITIZE_NUMBER_INT) : $this->model->getConfig()->getDefaultTransitiveLimit(); |
||
48 | if ($limit <= 0) { |
||
49 | return $this->returnError(400, "Bad Request", "Invalid limit parameter"); |
||
50 | } |
||
51 | |||
52 | return $limit; |
||
53 | } |
||
54 | |||
55 | |||
56 | /** Global REST methods **/ |
||
57 | |||
58 | /** |
||
59 | * Returns all the vocabularies available on the server in a json object. |
||
60 | */ |
||
61 | public function vocabularies($request) |
||
62 | { |
||
63 | if (!$request->getLang()) { |
||
64 | return $this->returnError(400, "Bad Request", "lang parameter missing"); |
||
65 | } |
||
66 | |||
67 | $this->setLanguageProperties($request->getLang()); |
||
68 | |||
69 | $vocabs = array(); |
||
70 | foreach ($this->model->getVocabularies() as $voc) { |
||
71 | $vocabs[$voc->getId()] = $voc->getConfig()->getTitle($request->getLang()); |
||
72 | } |
||
73 | ksort($vocabs); |
||
74 | $results = array(); |
||
75 | foreach ($vocabs as $id => $title) { |
||
76 | $results[] = array( |
||
77 | 'uri' => $id, |
||
78 | 'id' => $id, |
||
79 | 'title' => $title); |
||
80 | } |
||
81 | |||
82 | /* encode the results in a JSON-LD compatible array */ |
||
83 | $ret = array( |
||
84 | '@context' => array( |
||
85 | 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', |
||
86 | 'onki' => 'http://schema.onki.fi/onki#', |
||
87 | 'title' => array('@id' => 'rdfs:label', '@language' => $request->getLang()), |
||
88 | 'vocabularies' => 'onki:hasVocabulary', |
||
89 | 'id' => 'onki:vocabularyIdentifier', |
||
90 | 'uri' => '@id', |
||
91 | '@base' => $this->getBaseHref() . "rest/v1/vocabularies", |
||
92 | ), |
||
93 | 'uri' => '', |
||
94 | 'vocabularies' => $results, |
||
95 | ); |
||
96 | |||
97 | return $this->returnJson($ret); |
||
98 | } |
||
99 | |||
100 | private function constructSearchParameters($request) |
||
101 | { |
||
102 | $parameters = new ConceptSearchParameters($request, $this->model->getConfig(), true); |
||
103 | |||
104 | $vocabs = $request->getQueryParam('vocab'); # optional |
||
105 | // convert to vocids array to support multi-vocabulary search |
||
106 | $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : array(); |
||
107 | $vocabObjects = array(); |
||
108 | foreach($vocids as $vocid) { |
||
109 | $vocabObjects[] = $this->model->getVocabulary($vocid); |
||
110 | } |
||
111 | $parameters->setVocabularies($vocabObjects); |
||
112 | return $parameters; |
||
113 | } |
||
114 | |||
115 | private function transformSearchResults($request, $results, $parameters) |
||
116 | { |
||
117 | // before serializing to JSON, get rid of the Vocabulary object that came with each resource |
||
118 | foreach ($results as &$res) { |
||
119 | unset($res['voc']); |
||
120 | } |
||
121 | |||
122 | $context = array( |
||
123 | 'skos' => 'http://www.w3.org/2004/02/skos/core#', |
||
124 | 'isothes' => 'http://purl.org/iso25964/skos-thes#', |
||
125 | 'onki' => 'http://schema.onki.fi/onki#', |
||
126 | 'uri' => '@id', |
||
127 | 'type' => '@type', |
||
128 | 'results' => array( |
||
129 | '@id' => 'onki:results', |
||
130 | '@container' => '@list', |
||
131 | ), |
||
132 | 'prefLabel' => 'skos:prefLabel', |
||
133 | 'altLabel' => 'skos:altLabel', |
||
134 | 'hiddenLabel' => 'skos:hiddenLabel', |
||
135 | ); |
||
136 | foreach ($parameters->getAdditionalFields() as $field) { |
||
137 | |||
138 | // Quick-and-dirty compactification |
||
139 | $context[$field] = 'skos:' . $field; |
||
140 | foreach ($results as &$result) { |
||
141 | foreach ($result as $k => $v) { |
||
142 | if ($k == 'skos:' . $field) { |
||
143 | $result[$field] = $v; |
||
144 | unset($result['skos:' . $field]); |
||
145 | } |
||
146 | } |
||
147 | } |
||
148 | } |
||
149 | |||
150 | $ret = array( |
||
151 | '@context' => $context, |
||
152 | 'uri' => '', |
||
153 | 'results' => $results, |
||
154 | ); |
||
155 | |||
156 | if (isset($results[0]['prefLabels'])) { |
||
157 | $ret['@context']['prefLabels'] = array('@id' => 'skos:prefLabel', '@container' => '@language'); |
||
158 | } |
||
159 | |||
160 | if ($request->getQueryParam('labellang')) { |
||
161 | $ret['@context']['@language'] = $request->getQueryParam('labellang'); |
||
162 | } elseif ($request->getQueryParam('lang')) { |
||
163 | $ret['@context']['@language'] = $request->getQueryParam('lang'); |
||
164 | } |
||
165 | return $ret; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Performs the search function calls. And wraps the result in a json-ld object. |
||
170 | * @param Request $request |
||
171 | */ |
||
172 | public function search($request) |
||
193 | } |
||
194 | |||
195 | /** Vocabulary-specific methods **/ |
||
196 | |||
197 | /** |
||
198 | * Loads the vocabulary metadata. And wraps the result in a json-ld object. |
||
199 | * @param Request $request |
||
200 | */ |
||
201 | public function vocabularyInformation($request) |
||
248 | } |
||
249 | |||
250 | /** |
||
251 | * Loads the vocabulary metadata. And wraps the result in a json-ld object. |
||
252 | * @param Request $request |
||
253 | */ |
||
254 | public function vocabularyStatistics($request) |
||
255 | { |
||
256 | if ($this->notModified($request->getVocab())) { |
||
257 | return null; |
||
258 | } |
||
259 | $this->setLanguageProperties($request->getLang()); |
||
260 | $arrayClass = $request->getVocab()->getConfig()->getArrayClassURI(); |
||
261 | $groupClass = $request->getVocab()->getConfig()->getGroupClassURI(); |
||
262 | $queryLang = $request->getQueryParam('lang') ?? $request->getLang(); |
||
263 | $vocabStats = $request->getVocab()->getStatistics($queryLang, $arrayClass, $groupClass); |
||
264 | $types = array('http://www.w3.org/2004/02/skos/core#Concept', 'http://www.w3.org/2004/02/skos/core#Collection', $arrayClass, $groupClass); |
||
265 | $subTypes = array(); |
||
266 | foreach ($vocabStats as $subtype) { |
||
267 | if (!in_array($subtype['type'], $types)) { |
||
268 | $subTypes[] = $subtype; |
||
269 | } |
||
270 | } |
||
271 | |||
272 | /* encode the results in a JSON-LD compatible array */ |
||
273 | $ret = array( |
||
274 | '@context' => array( |
||
275 | 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', |
||
276 | 'skos' => 'http://www.w3.org/2004/02/skos/core#', |
||
277 | 'void' => 'http://rdfs.org/ns/void#', |
||
278 | 'onki' => 'http://schema.onki.fi/onki#', |
||
279 | 'uri' => '@id', |
||
280 | 'id' => 'onki:vocabularyIdentifier', |
||
281 | 'concepts' => 'void:classPartition', |
||
282 | 'label' => 'rdfs:label', |
||
283 | 'class' => array('@id' => 'void:class', '@type' => '@id'), |
||
284 | 'subTypes' => array('@id' => 'void:class', '@type' => '@id'), |
||
285 | 'count' => 'void:entities', |
||
286 | '@language' => $request->getLang(), |
||
287 | '@base' => $this->getBaseHref() . "rest/v1/" . $request->getVocab()->getId() . "/", |
||
288 | ), |
||
289 | 'uri' => '', |
||
290 | 'id' => $request->getVocab()->getId(), |
||
291 | 'title' => $request->getVocab()->getConfig()->getTitle(), |
||
292 | 'concepts' => array( |
||
293 | 'class' => 'http://www.w3.org/2004/02/skos/core#Concept', |
||
294 | 'label' => gettext('skos:Concept'), |
||
295 | 'count' => isset($vocabStats['http://www.w3.org/2004/02/skos/core#Concept']) ? $vocabStats['http://www.w3.org/2004/02/skos/core#Concept']['count'] : 0, |
||
296 | 'deprecatedCount' => isset($vocabStats['http://www.w3.org/2004/02/skos/core#Concept']) ? $vocabStats['http://www.w3.org/2004/02/skos/core#Concept']['deprecatedCount'] : 0, |
||
297 | ), |
||
298 | 'subTypes' => $subTypes, |
||
299 | ); |
||
300 | |||
301 | if (isset($vocabStats['http://www.w3.org/2004/02/skos/core#Collection'])) { |
||
302 | $ret['conceptGroups'] = array( |
||
303 | 'class' => 'http://www.w3.org/2004/02/skos/core#Collection', |
||
304 | 'label' => gettext('skos:Collection'), |
||
305 | 'count' => $vocabStats['http://www.w3.org/2004/02/skos/core#Collection']['count'], |
||
306 | 'deprecatedCount' => $vocabStats['http://www.w3.org/2004/02/skos/core#Collection']['deprecatedCount'], |
||
307 | ); |
||
308 | |||
309 | } else if (isset($vocabStats[$groupClass])) { |
||
310 | $ret['conceptGroups'] = array( |
||
311 | 'class' => $groupClass, |
||
312 | 'label' => isset($vocabStats[$groupClass]['label']) ? $vocabStats[$groupClass]['label'] : gettext(EasyRdf\RdfNamespace::shorten($groupClass)), |
||
313 | 'count' => $vocabStats[$groupClass]['count'], |
||
314 | 'deprecatedCount' => $vocabStats[$groupClass]['deprecatedCount'], |
||
315 | ); |
||
316 | } else if (isset($vocabStats[$arrayClass])) { |
||
317 | $ret['arrays'] = array( |
||
318 | 'class' => $arrayClass, |
||
319 | 'label' => isset($vocabStats[$arrayClass]['label']) ? $vocabStats[$arrayClass]['label'] : gettext(EasyRdf\RdfNamespace::shorten($arrayClass)), |
||
320 | 'count' => $vocabStats[$arrayClass]['count'], |
||
321 | 'deprecatedCount' => $vocabStats[$arrayClass]['deprecatedCount'], |
||
322 | ); |
||
323 | } |
||
324 | |||
325 | return $this->returnJson($ret); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Loads the vocabulary metadata. And wraps the result in a json-ld object. |
||
330 | * @param Request $request |
||
331 | */ |
||
332 | public function labelStatistics($request) |
||
333 | { |
||
334 | if ($this->notModified($request->getVocab())) { |
||
335 | return null; |
||
336 | } |
||
337 | $lang = $request->getLang(); |
||
338 | $this->setLanguageProperties($request->getLang()); |
||
339 | $vocabStats = $request->getVocab()->getLabelStatistics(); |
||
340 | |||
341 | /* encode the results in a JSON-LD compatible array */ |
||
342 | $counts = array(); |
||
343 | foreach ($vocabStats['terms'] as $proplang => $properties) { |
||
344 | $langdata = array('language' => $proplang); |
||
345 | if ($lang) { |
||
346 | $langdata['literal'] = Punic\Language::getName($proplang, $lang); |
||
347 | } |
||
348 | |||
349 | $langdata['properties'] = array(); |
||
350 | foreach ($properties as $prop => $value) { |
||
351 | $langdata['properties'][] = array('property' => $prop, 'labels' => $value); |
||
352 | } |
||
353 | $counts[] = $langdata; |
||
354 | } |
||
355 | |||
356 | $ret = array( |
||
357 | '@context' => array( |
||
358 | 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', |
||
359 | 'skos' => 'http://www.w3.org/2004/02/skos/core#', |
||
360 | 'void' => 'http://rdfs.org/ns/void#', |
||
361 | 'void-ext' => 'http://ldf.fi/void-ext#', |
||
362 | 'onki' => 'http://schema.onki.fi/onki#', |
||
363 | 'uri' => '@id', |
||
364 | 'id' => 'onki:vocabularyIdentifier', |
||
365 | 'languages' => 'void-ext:languagePartition', |
||
366 | 'language' => 'void-ext:language', |
||
367 | 'properties' => 'void:propertyPartition', |
||
368 | 'labels' => 'void:triples', |
||
369 | '@base' => $this->getBaseHref() . "rest/v1/" . $request->getVocab()->getId() . "/", |
||
370 | ), |
||
371 | 'uri' => '', |
||
372 | 'id' => $request->getVocab()->getId(), |
||
373 | 'title' => $request->getVocab()->getConfig()->getTitle($lang), |
||
374 | 'languages' => $counts, |
||
375 | ); |
||
376 | |||
377 | if ($lang) { |
||
378 | $ret['@context']['literal'] = array('@id' => 'rdfs:label', '@language' => $lang); |
||
379 | } |
||
380 | |||
381 | return $this->returnJson($ret); |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Loads the vocabulary type metadata. And wraps the result in a json-ld object. |
||
386 | * @param Request $request |
||
387 | */ |
||
388 | public function types($request) |
||
389 | { |
||
390 | $vocid = $request->getVocab() ? $request->getVocab()->getId() : null; |
||
391 | if ($vocid === null && !$request->getLang()) { |
||
392 | return $this->returnError(400, "Bad Request", "lang parameter missing"); |
||
393 | } |
||
394 | if ($this->notModified($request->getVocab())) { |
||
395 | return null; |
||
396 | } |
||
397 | |||
398 | $this->setLanguageProperties($request->getLang()); |
||
399 | |||
400 | $queriedtypes = $this->model->getTypes($vocid, $request->getLang()); |
||
401 | |||
402 | $types = array(); |
||
403 | |||
404 | /* encode the results in a JSON-LD compatible array */ |
||
405 | foreach ($queriedtypes as $uri => $typedata) { |
||
406 | $type = array_merge(array('uri' => $uri), $typedata); |
||
407 | $types[] = $type; |
||
408 | } |
||
409 | |||
410 | $base = $request->getVocab() ? $this->getBaseHref() . "rest/v1/" . $request->getVocab()->getId() . "/" : $this->getBaseHref() . "rest/v1/"; |
||
411 | |||
412 | $ret = array_merge_recursive($this->context, array( |
||
413 | '@context' => array( |
||
414 | 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', |
||
415 | 'onki' => 'http://schema.onki.fi/onki#', |
||
416 | 'label' => 'rdfs:label', |
||
417 | 'superclass' => array('@id' => 'rdfs:subClassOf', '@type' => '@id'), |
||
418 | 'types' => 'onki:hasType', |
||
419 | '@language' => $request->getLang(), |
||
420 | '@base' => $base, |
||
421 | ), |
||
422 | 'uri' => '', |
||
423 | 'types' => $types) |
||
424 | ); |
||
425 | |||
426 | return $this->returnJson($ret); |
||
427 | } |
||
428 | |||
429 | private function findLookupHits($results, $label, $lang) |
||
430 | { |
||
431 | $hits = array(); |
||
432 | // case 1: exact match on preferred label |
||
433 | foreach ($results as $res) { |
||
434 | if (isset($res['prefLabel']) && $res['prefLabel'] == $label) { |
||
435 | $hits[] = $res; |
||
436 | } |
||
437 | } |
||
438 | if (sizeof($hits) > 0) return $hits; |
||
439 | |||
440 | // case 2: case-insensitive match on preferred label |
||
441 | foreach ($results as $res) { |
||
442 | if (isset($res['prefLabel']) && strtolower($res['prefLabel']) == strtolower($label)) { |
||
443 | $hits[] = $res; |
||
444 | } |
||
445 | } |
||
446 | if (sizeof($hits) > 0) return $hits; |
||
447 | |||
448 | if ($lang === null) { |
||
449 | // case 1A: exact match on preferred label in any language |
||
450 | foreach ($results as $res) { |
||
451 | if (isset($res['matchedPrefLabel']) && $res['matchedPrefLabel'] == $label) { |
||
452 | $res['prefLabel'] = $res['matchedPrefLabel']; |
||
453 | unset($res['matchedPrefLabel']); |
||
454 | $hits[] = $res; |
||
455 | } |
||
456 | } |
||
457 | if (sizeof($hits) > 0) return $hits; |
||
458 | |||
459 | // case 2A: case-insensitive match on preferred label in any language |
||
460 | foreach ($results as $res) { |
||
461 | if (isset($res['matchedPrefLabel']) && strtolower($res['matchedPrefLabel']) == strtolower($label)) { |
||
462 | $res['prefLabel'] = $res['matchedPrefLabel']; |
||
463 | unset($res['matchedPrefLabel']); |
||
464 | $hits[] = $res; |
||
465 | } |
||
466 | } |
||
467 | if (sizeof($hits) > 0) return $hits; |
||
468 | } |
||
469 | |||
470 | // case 3: exact match on alternate label |
||
471 | foreach ($results as $res) { |
||
472 | if (isset($res['altLabel']) && $res['altLabel'] == $label) { |
||
473 | $hits[] = $res; |
||
474 | } |
||
475 | } |
||
476 | if (sizeof($hits) > 0) return $hits; |
||
477 | |||
478 | |||
479 | // case 4: case-insensitive match on alternate label |
||
480 | foreach ($results as $res) { |
||
481 | if (isset($res['altLabel']) && strtolower($res['altLabel']) == strtolower($label)) { |
||
482 | $hits[] = $res; |
||
483 | } |
||
484 | } |
||
485 | if (sizeof($hits) > 0) return $hits; |
||
486 | |||
487 | return $hits; |
||
488 | } |
||
489 | |||
490 | private function transformLookupResults($lang, $hits) |
||
491 | { |
||
492 | if (sizeof($hits) == 0) { |
||
493 | // no matches found |
||
494 | return; |
||
495 | } |
||
496 | |||
497 | // found matches, getting rid of Vocabulary objects |
||
498 | foreach ($hits as &$res) { |
||
499 | unset($res['voc']); |
||
500 | } |
||
501 | |||
502 | $ret = array_merge_recursive($this->context, array( |
||
503 | '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'results' => array('@id' => 'onki:results'), 'prefLabel' => 'skos:prefLabel', 'altLabel' => 'skos:altLabel', 'hiddenLabel' => 'skos:hiddenLabel'), |
||
504 | 'result' => $hits) |
||
505 | ); |
||
506 | |||
507 | if ($lang) { |
||
508 | $ret['@context']['@language'] = $lang; |
||
509 | } |
||
510 | |||
511 | return $ret; |
||
512 | } |
||
513 | |||
514 | /** |
||
515 | * Used for finding terms by their exact prefLabel. Wraps the result in a json-ld object. |
||
516 | * @param Request $request |
||
517 | */ |
||
518 | public function lookup($request) |
||
519 | { |
||
520 | $label = $request->getQueryParamRaw('label'); |
||
521 | if (!$label) { |
||
522 | return $this->returnError(400, "Bad Request", "label parameter missing"); |
||
523 | } |
||
524 | |||
525 | $lang = $request->getQueryParam('lang'); |
||
526 | $parameters = new ConceptSearchParameters($request, $this->model->getConfig(), true); |
||
527 | $results = $this->model->searchConcepts($parameters); |
||
528 | $hits = $this->findLookupHits($results, $label, $lang); |
||
529 | $ret = $this->transformLookupResults($lang, $hits); |
||
530 | if ($ret === null) { |
||
531 | return $this->returnError(404, 'Not Found', "Could not find label '$label'"); |
||
532 | } |
||
533 | return $this->returnJson($ret); |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * Queries the top concepts of a vocabulary and wraps the results in a json-ld object. |
||
538 | * @param Request $request |
||
539 | * @return object json-ld object |
||
540 | */ |
||
541 | public function topConcepts($request) |
||
542 | { |
||
543 | $vocab = $request->getVocab(); |
||
544 | if ($this->notModified($vocab)) { |
||
545 | return null; |
||
546 | } |
||
547 | $scheme = $request->getQueryParam('scheme'); |
||
548 | if (!$scheme) { |
||
549 | $scheme = $vocab->getConfig()->showConceptSchemesInHierarchy() ? array_keys($vocab->getConceptSchemes()) : $vocab->getDefaultConceptScheme(); |
||
550 | } |
||
551 | |||
552 | /* encode the results in a JSON-LD compatible array */ |
||
553 | $topconcepts = $vocab->getTopConcepts($scheme, $request->getLang()); |
||
554 | |||
555 | $ret = array_merge_recursive($this->context, array( |
||
556 | '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'topconcepts' => 'skos:hasTopConcept', 'notation' => 'skos:notation', 'label' => 'skos:prefLabel', '@language' => $request->getLang()), |
||
557 | 'uri' => $scheme, |
||
558 | 'topconcepts' => $topconcepts) |
||
559 | ); |
||
560 | |||
561 | return $this->returnJson($ret); |
||
562 | } |
||
563 | |||
564 | private function redirectToVocabData($request) { |
||
565 | $urls = $request->getVocab()->getConfig()->getDataURLs(); |
||
566 | if (sizeof($urls) == 0) { |
||
567 | $vocid = $request->getVocab()->getId(); |
||
568 | return $this->returnError('404', 'Not Found', "No download source URL known for vocabulary $vocid"); |
||
569 | } |
||
570 | |||
571 | $format = $this->negotiateFormat(array_keys($urls), $request->getServerConstant('HTTP_ACCEPT'), $request->getQueryParam('format')); |
||
572 | if (!$format) { |
||
573 | return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . implode(' ', array_keys($urls))); |
||
574 | } |
||
575 | if (is_array($urls[$format])) { |
||
576 | $arr = $urls[$format]; |
||
577 | $dataLang = $request->getLang(); |
||
578 | if (isset($arr[$dataLang])) { |
||
579 | header("Location: " . $arr[$dataLang]); |
||
580 | } else { |
||
581 | $vocid = $request->getVocab()->getId(); |
||
582 | return $this->returnError('404', 'Not Found', "No download source URL known for vocabulary $vocid in language $dataLang"); |
||
583 | } |
||
584 | } else { |
||
585 | header("Location: " . $urls[$format]); |
||
586 | } |
||
587 | } |
||
588 | |||
589 | private function returnDataResults($results, $format) { |
||
590 | if ($format == 'application/ld+json' || $format == 'application/json') { |
||
591 | // further compact JSON-LD document using a context |
||
592 | $context = array( |
||
593 | 'skos' => 'http://www.w3.org/2004/02/skos/core#', |
||
594 | 'isothes' => 'http://purl.org/iso25964/skos-thes#', |
||
595 | 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', |
||
596 | 'owl' => 'http://www.w3.org/2002/07/owl#', |
||
597 | 'dct' => 'http://purl.org/dc/terms/', |
||
598 | 'dc11' => 'http://purl.org/dc/elements/1.1/', |
||
599 | 'uri' => '@id', |
||
600 | 'type' => '@type', |
||
601 | 'lang' => '@language', |
||
602 | 'value' => '@value', |
||
603 | 'graph' => '@graph', |
||
604 | 'label' => 'rdfs:label', |
||
605 | 'prefLabel' => 'skos:prefLabel', |
||
606 | 'altLabel' => 'skos:altLabel', |
||
607 | 'hiddenLabel' => 'skos:hiddenLabel', |
||
608 | 'broader' => 'skos:broader', |
||
609 | 'narrower' => 'skos:narrower', |
||
610 | 'related' => 'skos:related', |
||
611 | 'inScheme' => 'skos:inScheme', |
||
612 | 'exactMatch' => 'skos:exactMatch', |
||
613 | 'closeMatch' => 'skos:closeMatch', |
||
614 | 'broadMatch' => 'skos:broadMatch', |
||
615 | 'narrowMatch' => 'skos:narrowMatch', |
||
616 | 'relatedMatch' => 'skos:relatedMatch', |
||
617 | ); |
||
618 | $compactJsonLD = \ML\JsonLD\JsonLD::compact($results, json_encode($context)); |
||
619 | $results = \ML\JsonLD\JsonLD::toString($compactJsonLD); |
||
620 | } |
||
621 | |||
622 | header("Content-type: $format; charset=utf-8"); |
||
623 | echo $results; |
||
624 | } |
||
625 | |||
626 | /** |
||
627 | * Download a concept as json-ld or redirect to download the whole vocabulary. |
||
628 | * @param Request $request |
||
629 | * @return object json-ld formatted concept. |
||
630 | */ |
||
631 | public function data($request) |
||
632 | { |
||
633 | $vocab = $request->getVocab(); |
||
634 | if ($this->notModified($request->getVocab())) { |
||
635 | return null; |
||
636 | } |
||
637 | |||
638 | if ($request->getUri()) { |
||
639 | $uri = $request->getUri(); |
||
640 | } else if ($vocab !== null) { // whole vocabulary - redirect to download URL |
||
641 | return $this->redirectToVocabData($request); |
||
642 | } else { |
||
643 | return $this->returnError(400, 'Bad Request', "uri parameter missing"); |
||
644 | } |
||
645 | |||
646 | $format = $this->negotiateFormat(explode(' ', self::SUPPORTED_FORMATS), $request->getServerConstant('HTTP_ACCEPT'), $request->getQueryParam('format')); |
||
647 | if (!$format) { |
||
648 | return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . self::SUPPORTED_FORMATS); |
||
649 | } |
||
650 | |||
651 | $vocid = $vocab ? $vocab->getId() : null; |
||
652 | $results = $this->model->getRDF($vocid, $uri, $format); |
||
653 | if (empty($results)) { |
||
654 | return $this->returnError(404, 'Bad Request', "no concept found with given uri"); |
||
655 | } |
||
656 | return $this->returnDataResults($results, $format); |
||
657 | } |
||
658 | |||
659 | /** |
||
660 | * Get the mappings associated with a concept, enriched with labels and notations. |
||
661 | * Returns a JSKOS-compatible JSON object. |
||
662 | * @param Request $request |
||
663 | * @throws Exception if the vocabulary ID is not found in configuration |
||
664 | */ |
||
665 | public function mappings(Request $request) |
||
666 | { |
||
667 | $this->setLanguageProperties($request->getLang()); |
||
668 | $vocab = $request->getVocab(); |
||
669 | if ($this->notModified($vocab)) { |
||
670 | return null; |
||
671 | } |
||
672 | |||
673 | $uri = $request->getUri(); |
||
674 | if (!$uri) { |
||
675 | return $this->returnError(400, 'Bad Request', "uri parameter missing"); |
||
676 | } |
||
677 | |||
678 | $queryExVocabs = $request->getQueryParamBoolean('external', true); |
||
679 | |||
680 | $results = $vocab->getConceptInfo($uri, $request->getContentLang()); |
||
681 | if (empty($results)) { |
||
682 | return $this->returnError(404, 'Bad Request', "no concept found with given uri"); |
||
683 | } |
||
684 | |||
685 | $concept = $results[0]; |
||
686 | |||
687 | $mappings = []; |
||
688 | foreach ($concept->getMappingProperties() as $mappingProperty) { |
||
689 | foreach ($mappingProperty->getValues() as $mappingPropertyValue) { |
||
690 | $hrefLink = $this->linkUrlFilter($mappingPropertyValue->getUri(), $mappingPropertyValue->getExVocab(), $request->getLang(), 'page', $request->getContentLang()); |
||
691 | $mappings[] = $mappingPropertyValue->asJskos($queryExVocabs, $request->getLang(), $hrefLink); |
||
692 | } |
||
693 | } |
||
694 | |||
695 | $ret = array( |
||
696 | 'mappings' => $mappings, |
||
697 | 'graph' => $concept->dumpJsonLd() |
||
698 | ); |
||
699 | |||
700 | return $this->returnJson($ret); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * Used for querying labels for a uri. |
||
705 | * @param Request $request |
||
706 | * @return object json-ld wrapped labels. |
||
707 | */ |
||
708 | public function label($request) |
||
709 | { |
||
710 | if (!$request->getUri()) { |
||
711 | return $this->returnError(400, "Bad Request", "uri parameter missing"); |
||
712 | } |
||
713 | |||
714 | if ($this->notModified($request->getVocab())) { |
||
715 | return null; |
||
716 | } |
||
717 | |||
718 | $vocab = $request->getVocab(); |
||
719 | if ($vocab === null) { |
||
720 | $vocab = $this->model->guessVocabularyFromUri($request->getUri()); |
||
721 | } |
||
722 | if ($vocab === null) { |
||
723 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
724 | } |
||
725 | |||
726 | $labelResults = $vocab->getAllConceptLabels($request->getUri(), $request->getLang()); |
||
727 | if ($labelResults === null) { |
||
728 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
729 | } |
||
730 | |||
731 | // there should be only one preferred label so no need for an array |
||
732 | if (array_key_exists('prefLabel', $labelResults)) { |
||
733 | $labelResults['prefLabel'] = $labelResults['prefLabel'][0]; |
||
734 | } |
||
735 | |||
736 | $ret = array_merge_recursive($this->context, |
||
737 | array('@context' => array('prefLabel' => 'skos:prefLabel', 'altLabel' => 'skos:altLabel', 'hiddenLabel' => 'skos:hiddenLabel', '@language' => $request->getLang()), |
||
738 | 'uri' => $request->getUri()), |
||
739 | $labelResults); |
||
740 | |||
741 | return $this->returnJson($ret); |
||
742 | } |
||
743 | |||
744 | /** |
||
745 | * Query for the available letters in the alphabetical index. |
||
746 | * @param Request $request |
||
747 | * @return object JSON-LD wrapped list of letters |
||
748 | */ |
||
749 | |||
750 | public function indexLetters($request) |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Query for the concepts with terms starting with a given letter in the |
||
771 | * alphabetical index. |
||
772 | * @param Request $request |
||
773 | * @return object JSON-LD wrapped list of terms/concepts |
||
774 | */ |
||
775 | |||
776 | public function indexConcepts($letter, $request) |
||
777 | { |
||
778 | $this->setLanguageProperties($request->getLang()); |
||
779 | |||
780 | $offset_param = $request->getQueryParam('offset'); |
||
781 | $offset = (is_numeric($offset_param) && $offset_param >= 0) ? $offset_param : 0; |
||
782 | $limit_param = $request->getQueryParam('limit'); |
||
783 | $limit = (is_numeric($limit_param) && $limit_param >= 0) ? $limit_param : 0; |
||
784 | |||
785 | $concepts = $request->getVocab()->searchConceptsAlphabetical($letter, $limit, $offset, $request->getLang()); |
||
786 | |||
787 | $ret = array_merge_recursive($this->context, array( |
||
788 | '@context' => array( |
||
789 | 'indexConcepts' => array( |
||
790 | '@id' => 'skosmos:indexConcepts', |
||
791 | '@container' => '@list' |
||
792 | ) |
||
793 | ), |
||
794 | 'uri' => '', |
||
795 | 'indexConcepts' => $concepts) |
||
796 | ); |
||
797 | return $this->returnJson($ret); |
||
798 | } |
||
799 | |||
800 | private function transformPropertyResults($uri, $lang, $objects, $propname, $propuri) |
||
801 | { |
||
802 | $results = array(); |
||
803 | foreach ($objects as $objuri => $vals) { |
||
804 | $results[] = array('uri' => $objuri, 'prefLabel' => $vals['label']); |
||
805 | } |
||
806 | |||
807 | return array_merge_recursive($this->context, array( |
||
808 | '@context' => array('prefLabel' => 'skos:prefLabel', $propname => $propuri, '@language' => $lang), |
||
809 | 'uri' => $uri, |
||
810 | $propname => $results) |
||
811 | ); |
||
812 | } |
||
813 | |||
814 | private function transformTransitivePropertyResults($uri, $lang, $objects, $tpropname, $tpropuri, $dpropname, $dpropuri) |
||
829 | ); |
||
830 | } |
||
831 | |||
832 | /** |
||
833 | * Used for querying broader relations for a concept. |
||
834 | * @param Request $request |
||
835 | * @return object json-ld wrapped broader concept uris and labels. |
||
836 | */ |
||
837 | public function broader($request) |
||
838 | { |
||
839 | if ($this->notModified($request->getVocab())) { |
||
840 | return null; |
||
841 | } |
||
842 | $broaders = $request->getVocab()->getConceptBroaders($request->getUri(), $request->getLang()); |
||
843 | if ($broaders === null) { |
||
844 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
845 | } |
||
846 | $ret = $this->transformPropertyResults($request->getUri(), $request->getLang(), $broaders, "broader", "skos:broader"); |
||
847 | return $this->returnJson($ret); |
||
848 | } |
||
849 | |||
850 | /** |
||
851 | * Used for querying broader transitive relations for a concept. |
||
852 | * @param Request $request |
||
853 | * @return object json-ld wrapped broader transitive concept uris and labels. |
||
854 | */ |
||
855 | public function broaderTransitive($request) |
||
856 | { |
||
857 | if ($this->notModified($request->getVocab())) { |
||
858 | return null; |
||
859 | } |
||
860 | $broaders = $request->getVocab()->getConceptTransitiveBroaders($request->getUri(), $this->parseLimit(), false, $request->getLang()); |
||
861 | if (empty($broaders)) { |
||
862 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
863 | } |
||
864 | $ret = $this->transformTransitivePropertyResults($request->getUri(), $request->getLang(), $broaders, "broaderTransitive", "skos:broaderTransitive", "broader", "skos:broader"); |
||
865 | return $this->returnJson($ret); |
||
866 | } |
||
867 | |||
868 | /** |
||
869 | * Used for querying narrower relations for a concept. |
||
870 | * @param Request $request |
||
871 | * @return object json-ld wrapped narrower concept uris and labels. |
||
872 | */ |
||
873 | public function narrower($request) |
||
874 | { |
||
875 | if ($this->notModified($request->getVocab())) { |
||
876 | return null; |
||
877 | } |
||
878 | $narrowers = $request->getVocab()->getConceptNarrowers($request->getUri(), $request->getLang()); |
||
879 | if ($narrowers === null) { |
||
880 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
881 | } |
||
882 | $ret = $this->transformPropertyResults($request->getUri(), $request->getLang(), $narrowers, "narrower", "skos:narrower"); |
||
883 | return $this->returnJson($ret); |
||
884 | } |
||
885 | |||
886 | /** |
||
887 | * Used for querying narrower transitive relations for a concept. |
||
888 | * @param Request $request |
||
889 | * @return object json-ld wrapped narrower transitive concept uris and labels. |
||
890 | */ |
||
891 | public function narrowerTransitive($request) |
||
902 | } |
||
903 | |||
904 | /** |
||
905 | * Used for querying broader transitive relations |
||
906 | * and some narrowers for a concept in the hierarchy view. |
||
907 | * @param Request $request |
||
908 | * @return object json-ld wrapped hierarchical concept uris and labels. |
||
909 | */ |
||
910 | public function hierarchy($request) |
||
984 | } |
||
985 | |||
986 | /** |
||
987 | * Used for querying group hierarchy for the sidebar group view. |
||
988 | * @param Request $request |
||
989 | * @return object json-ld wrapped hierarchical concept uris and labels. |
||
990 | */ |
||
991 | public function groups($request) |
||
1005 | } |
||
1006 | |||
1007 | /** |
||
1008 | * Used for querying member relations for a group. |
||
1009 | * @param Request $request |
||
1010 | * @return object json-ld wrapped narrower concept uris and labels. |
||
1011 | */ |
||
1012 | public function groupMembers($request) |
||
1013 | { |
||
1014 | if ($this->notModified($request->getVocab())) { |
||
1015 | return null; |
||
1016 | } |
||
1017 | $children = $request->getVocab()->listConceptGroupContents($request->getUri(), $request->getLang()); |
||
1018 | if (empty($children)) { |
||
1019 | return $this->returnError('404', 'Not Found', "Could not find group <{$request->getUri()}>"); |
||
1020 | } |
||
1021 | |||
1022 | $ret = array_merge_recursive($this->context, array( |
||
1023 | '@context' => array('prefLabel' => 'skos:prefLabel', 'members' => 'skos:member', '@language' => $request->getLang()), |
||
1024 | 'uri' => $request->getUri(), |
||
1025 | 'members' => $children) |
||
1026 | ); |
||
1027 | |||
1028 | return $this->returnJson($ret); |
||
1029 | } |
||
1030 | |||
1031 | /** |
||
1032 | * Used for querying narrower relations for a concept in the hierarchy view. |
||
1033 | * @param Request $request |
||
1034 | * @return object json-ld wrapped narrower concept uris and labels. |
||
1035 | */ |
||
1036 | public function children($request) |
||
1037 | { |
||
1038 | if ($this->notModified($request->getVocab())) { |
||
1039 | return null; |
||
1040 | } |
||
1041 | $children = $request->getVocab()->getConceptChildren($request->getUri(), $request->getLang()); |
||
1042 | if ($children === null) { |
||
1043 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
1044 | } |
||
1045 | |||
1046 | $ret = array_merge_recursive($this->context, array( |
||
1047 | '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => 'skos:narrower', 'notation' => 'skos:notation', 'hasChildren' => 'onki:hasChildren', '@language' => $request->getLang()), |
||
1048 | 'uri' => $request->getUri(), |
||
1049 | 'narrower' => $children) |
||
1050 | ); |
||
1051 | |||
1052 | return $this->returnJson($ret); |
||
1053 | } |
||
1054 | |||
1055 | /** |
||
1056 | * Used for querying narrower relations for a concept in the hierarchy view. |
||
1057 | * @param Request $request |
||
1058 | * @return object json-ld wrapped hierarchical concept uris and labels. |
||
1059 | */ |
||
1060 | public function related($request) |
||
1061 | { |
||
1062 | if ($this->notModified($request->getVocab())) { |
||
1063 | return null; |
||
1064 | } |
||
1065 | $related = $request->getVocab()->getConceptRelateds($request->getUri(), $request->getLang()); |
||
1066 | if ($related === null) { |
||
1067 | return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>"); |
||
1068 | } |
||
1069 | $ret = $this->transformPropertyResults($request->getUri(), $request->getLang(), $related, "related", "skos:related"); |
||
1070 | return $this->returnJson($ret); |
||
1071 | } |
||
1072 | |||
1073 | /** |
||
1074 | * Used for querying new concepts in the vocabulary |
||
1075 | * @param Request $request |
||
1076 | * @return object json-ld wrapped list of changed concepts |
||
1077 | */ |
||
1078 | public function newConcepts($request) |
||
1079 | { |
||
1080 | $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; |
||
1081 | $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; |
||
1082 | |||
1083 | return $this->changedConcepts($request, 'dc:created', $offset, $limit); |
||
1084 | } |
||
1085 | |||
1086 | /** |
||
1087 | * Used for querying modified concepts in the vocabulary |
||
1088 | * @param Request $request |
||
1089 | * @return object json-ld wrapped list of changed concepts |
||
1090 | */ |
||
1091 | public function modifiedConcepts($request) |
||
1092 | { |
||
1093 | $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; |
||
1094 | $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; |
||
1095 | |||
1096 | return $this->changedConcepts($request, 'dc:modified', $offset, $limit); |
||
1097 | } |
||
1098 | |||
1099 | /** |
||
1100 | * Used for querying changed concepts in the vocabulary |
||
1101 | * @param Request $request |
||
1102 | * @param int $offset starting index offset |
||
1103 | * @param int $limit maximum number of concepts to return |
||
1104 | * @return object json-ld wrapped list of changed concepts |
||
1105 | */ |
||
1106 | private function changedConcepts($request, $prop, $offset, $limit) |
||
1125 | |||
1126 | } |
||
1127 | } |
||
1128 |
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