Completed
Push — master ( 03d576...3064ea )
by Henri
07:33
created

RestController::hierarchy()   D

Complexity

Conditions 10
Paths 3

Size

Total Lines 37
Code Lines 20

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 37
rs 4.8197
cc 10
eloc 20
nc 3
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 16 and the first side effect is on line 11.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Copyright (c) 2012-2013 Aalto University and University of Helsinki
4
 * MIT License
5
 * see LICENSE.txt for more information
6
 */
7
8
/**
9
 * Rest controller is an extension of the controller so that must be imported.
10
 */
11
require_once 'controller/Controller.php';
12
13
/**
14
 * RestController is responsible for handling all the requests directed to the /rest address.
15
 */
16
class RestController extends Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /* supported MIME types that can be used to return RDF data */
19
    private static $SUPPORTED_MIME_TYPES = 'application/rdf+xml text/turtle application/ld+json application/json';
20
    /* context array template */
21
    private $context = array(
22
        '@context' => array(
23
            'skos' => 'http://www.w3.org/2004/02/skos/core#',
24
            'uri' => '@id',
25
            'type' => '@type',
26
        ),
27
    );
28
29
    /**
30
     * Echos an error message when the request can't be fulfilled.
31
     * @param string $code
32
     * @param string $status
33
     * @param string $message
34
     */
35
    private function returnError($code, $status, $message)
36
    {
37
        header("HTTP/1.0 $code $status");
38
        header("Content-type: text/plain; charset=utf-8");
39
        echo "$code $status : $message";
40
    }
41
42
    /**
43
     * Handles json encoding, adding the content type headers and optional callback function.
44
     * @param array $data the data to be returned.
45
     */
46
    private function returnJson($data)
47
    {
48
        if (filter_input(INPUT_GET, 'callback', FILTER_SANITIZE_STRING)) {
49
            header("Content-type: application/javascript; charset=utf-8");
50
            // wrap with JSONP callback
51
            echo filter_input(INPUT_GET, 'callback', FILTER_UNSAFE_RAW) . "(" . json_encode($data) . ");";
52
        } else {
53
            // negotiate suitable format
54
            $negotiator = new \Negotiation\FormatNegotiator();
55
            $priorities = array('application/json', 'application/ld+json');
56
            $best = filter_input(INPUT_SERVER, 'HTTP_ACCEPT', FILTER_SANITIZE_STRING) ? $negotiator->getBest(filter_input(INPUT_SERVER, 'HTTP_ACCEPT', FILTER_SANITIZE_STRING), $priorities) : null;
57
            $format = ($best !== null) ? $best->getValue() : $priorities[0];
58
            header("Content-type: $format; charset=utf-8");
59
            header("Vary: Accept"); // inform caches that we made a choice based on Accept header
60
            echo json_encode($data);
61
        }
62
    }
63
64
    /**
65
     * Parses and returns the limit parameter. Returns and error if the parameter is missing.
66
     */
67
    private function parseLimit()
68
    {
69
        $limit = filter_input(INPUT_GET, 'limit', FILTER_SANITIZE_NUMBER_INT) ? filter_input(INPUT_GET, 'limit', FILTER_SANITIZE_NUMBER_INT) : $this->model->getConfig()->getDefaultTransitiveLimit();
70
        if ($limit <= 0) {
71
            return $this->returnError(400, "Bad Request", "Invalid limit parameter");
72
        }
73
74
        return $limit;
75
    }
76
77
    /**
78
     * Negotiate a MIME type according to the proposed format, the list of valid
79
     * formats, and an optional proposed format.
80
     * As a side effect, set the HTTP Vary header if a choice was made based on
81
     * the Accept header.
82
     * @param array $choices possible MIME types as strings
83
     * @param string $accept HTTP Accept header value
84
     * @param string $format proposed format
85
     * @return string selected format, or null if negotiation failed
86
     */
87
    private function negotiateFormat($choices, $accept, $format)
88
    {
89
        if ($format) {
90
            if (!in_array($format, $choices)) {
91
                return null;
92
            }
93
94
        } else {
95
            header('Vary: Accept'); // inform caches that a decision was made based on Accept header
96
            $best = $this->negotiator->getBest($accept, $choices);
97
            $format = ($best !== null) ? $best->getValue() : null;
98
        }
99
        return $format;
100
    }
101
102
/** Global REST methods **/
103
104
    /**
105
     * Returns all the vocabularies available on the server in a json object.
106
     */
107
    public function vocabularies($request)
108
    {
109
        if (!$request->getLang()) {
110
            return $this->returnError(400, "Bad Request", "lang parameter missing");
111
        }
112
113
        $this->setLanguageProperties($request->getLang());
114
115
        $vocabs = array();
116
        foreach ($this->model->getVocabularies() as $voc) {
117
            $vocabs[$voc->getId()] = $voc->getConfig()->getTitle($request->getLang());
118
        }
119
        ksort($vocabs);
120
        $results = array();
121
        foreach ($vocabs as $id => $title) {
122
            $results[] = array(
123
                'uri' => $id,
124
                'id' => $id,
125
                'title' => $title);
126
        }
127
128
        /* encode the results in a JSON-LD compatible array */
129
        $ret = array(
130
            '@context' => array(
131
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
132
                'onki' => 'http://schema.onki.fi/onki#',
133
                'title' => array('@id' => 'rdfs:label', '@language' => $request->getLang()),
134
                'vocabularies' => 'onki:hasVocabulary',
135
                'id' => 'onki:vocabularyIdentifier',
136
                'uri' => '@id',
137
            ),
138
            'uri' => '',
139
            'vocabularies' => $results,
140
        );
141
142
        return $this->returnJson($ret);
143
    }
144
145
    /**
146
     * Performs the search function calls. And wraps the result in a json-ld object.
147
     * @param Request $request
148
     */
149
    public function search($request)
150
    {
151
        $maxhits = $request->getQueryParam('maxhits');
152
        $offset = $request->getQueryParam('offset');
153
        $term = $request->getQueryParam('query');
154
155
        if (!$term) {
156
            return $this->returnError(400, "Bad Request", "query parameter missing");
157
        }
158
        if ($maxhits && (!is_numeric($maxhits) || $maxhits <= 0)) {
159
            return $this->returnError(400, "Bad Request", "maxhits parameter is invalid");
160
        }
161
        if ($offset && (!is_numeric($offset) || $offset < 0)) {
162
            return $this->returnError(400, "Bad Request", "offset parameter is invalid");
163
        }
164
165
        $lang = $request->getQueryParam('lang'); # optional
166
        $labellang = $request->getQueryParam('labellang'); # optional
167
168
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig(), true);
169
        
170
        $vocabs = $request->getQueryParam('vocab'); # optional
171
        // convert to vocids array to support multi-vocabulary search
172
        $vocids = ($vocabs !== null && $vocabs !== '') ? explode(' ', $vocabs) : array();
173
        $vocabObjects = array();
174
        foreach($vocids as $vocid) {
175
            $vocabObjects[] = $this->model->getVocabulary($vocid);
176
        }
177
        $parameters->setVocabularies($vocabObjects);
178
179
        $results = $this->model->searchConcepts($parameters);
180
        // before serializing to JSON, get rid of the Vocabulary object that came with each resource
181
        foreach ($results as &$res) {
182
            unset($res['voc']);
183
        }
184
185
        $ret = array(
186
            '@context' => array(
187
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
188
                'onki' => 'http://schema.onki.fi/onki#',
189
                'uri' => '@id',
190
                'type' => '@type',
191
                'results' => array(
192
                    '@id' => 'onki:results',
193
                    '@container' => '@list',
194
                ),
195
                'prefLabel' => 'skos:prefLabel',
196
                'altLabel' => 'skos:altLabel',
197
                'hiddenLabel' => 'skos:hiddenLabel',
198
                'broader' => 'skos:broader',
199
            ),
200
            'uri' => '',
201
            'results' => $results,
202
        );
203
204
        if ($labellang) {
205
            $ret['@context']['@language'] = $labellang;
206
        } elseif ($lang) {
207
            $ret['@context']['@language'] = $lang;
208
        }
209
210
        return $this->returnJson($ret);
211
    }
212
213
/** Vocabulary-specific methods **/
214
215
    /**
216
     * Loads the vocabulary metadata. And wraps the result in a json-ld object.
217
     * @param Request $request
218
     */
219
    public function vocabularyInformation($request)
220
    {
221
        $vocab = $request->getVocab();
222
223
        /* encode the results in a JSON-LD compatible array */
224
        $conceptschemes = array();
225
        foreach ($vocab->getConceptSchemes() as $uri => $csdata) {
226
            $csdata['uri'] = $uri;
227
            $csdata['type'] = 'skos:ConceptScheme';
228
            $conceptschemes[] = $csdata;
229
        }
230
231
        $ret = array(
232
            '@context' => array(
233
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
234
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
235
                'onki' => 'http://schema.onki.fi/onki#',
236
                'dct' => 'http://purl.org/dc/terms/',
237
                'uri' => '@id',
238
                'type' => '@type',
239
                'title' => 'rdfs:label',
240
                'conceptschemes' => 'onki:hasConceptScheme',
241
                'id' => 'onki:vocabularyIdentifier',
242
                'defaultLanguage' => 'onki:defaultLanguage',
243
                'languages' => 'onki:language',
244
                'label' => 'rdfs:label',
245
                'prefLabel' => 'skos:prefLabel',
246
                'title' => 'dct:title',
247
                '@language' => $request->getLang(),
248
            ),
249
            'uri' => '',
250
            'id' => $vocab->getId(),
251
            'title' => $vocab->getConfig()->getTitle($request->getLang()),
252
            'defaultLanguage' => $vocab->getConfig()->getDefaultLanguage(),
253
            'languages' => $vocab->getConfig()->getLanguages(),
254
            'conceptschemes' => $conceptschemes,
255
        );
256
257
        return $this->returnJson($ret);
258
    }
259
260
    /**
261
     * Loads the vocabulary metadata. And wraps the result in a json-ld object.
262
     * @param Request $request
263
     */
264
    public function vocabularyStatistics($request)
265
    {
266
        $this->setLanguageProperties($request->getLang());
267
        $arrayClass = $request->getVocab()->getConfig()->getArrayClassURI(); 
268
        $groupClass = $request->getVocab()->getConfig()->getGroupClassURI(); 
269
        $vocab_stats = $request->getVocab()->getStatistics($request->getQueryParam('lang'), $arrayClass, $groupClass);
270
        $types = array('http://www.w3.org/2004/02/skos/core#Concept', 'http://www.w3.org/2004/02/skos/core#Collection', $arrayClass, $groupClass);
271
        $subTypes = array();
272
        foreach ($vocab_stats as $subtype) {
273
            if (!in_array($subtype['type'], $types)) {
274
                $subTypes[] = $subtype;
275
            }
276
        }
277
278
        /* encode the results in a JSON-LD compatible array */
279
        $ret = array(
280
            '@context' => array(
281
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
282
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
283
                'void' => 'http://rdfs.org/ns/void#',
284
                'onki' => 'http://schema.onki.fi/onki#',
285
                'uri' => '@id',
286
                'id' => 'onki:vocabularyIdentifier',
287
                'concepts' => 'void:classPartition',
288
                'label' => 'rdfs:label',
289
                'class' => array('@id' => 'void:class', '@type' => '@id'),
290
                'subTypes' => array('@id' => 'void:class', '@type' => '@id'),
291
                'count' => 'void:entities',
292
                '@language' => $request->getLang(),
293
            ),
294
            'uri' => '',
295
            'id' => $request->getVocab()->getId(),
296
            'title' => $request->getVocab()->getConfig()->getTitle(),
297
            'concepts' => array(
298
                'class' => 'http://www.w3.org/2004/02/skos/core#Concept',
299
                'label' => gettext('skos:Concept'),
300
                'count' => $vocab_stats['http://www.w3.org/2004/02/skos/core#Concept']['count'],
301
            ),
302
            'subTypes' => $subTypes,
303
        );
304
305
        if (isset($vocab_stats['http://www.w3.org/2004/02/skos/core#Collection'])) {
306
            $ret['conceptGroups'] = array(
307
                'class' => 'http://www.w3.org/2004/02/skos/core#Collection',
308
                'label' => gettext('skos:Collection'),
309
                'count' => $vocab_stats['http://www.w3.org/2004/02/skos/core#Collection']['count'],
310
            );
311
        } else if (isset($vocab_stats[$groupClass])) {
312
            $ret['conceptGroups'] = array(
313
                'class' => $groupClass,
314
                'label' => isset($vocab_stats[$groupClass]['label']) ? $vocab_stats[$groupClass]['label'] : gettext(EasyRdf_Namespace::shorten($groupClass)),
315
                'count' => $vocab_stats[$groupClass]['count'],
316
            );
317
        } else if (isset($vocab_stats[$arrayClass])) {
318
            $ret['arrays'] = array(
319
                'class' => $arrayClass,
320
                'label' => isset($vocab_stats[$arrayClass]['label']) ? $vocab_stats[$arrayClass]['label'] : gettext(EasyRdf_Namespace::shorten($arrayClass)),
321
                'count' => $vocab_stats[$arrayClass]['count'],
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
        $lang = $request->getLang();
335
        $this->setLanguageProperties($request->getLang());
336
        $vocab_stats = $request->getVocab()->getLabelStatistics();
337
338
        /* encode the results in a JSON-LD compatible array */
339
        $counts = array();
340
        foreach ($vocab_stats['terms'] as $proplang => $properties) {
341
            $langdata = array('language' => $proplang);
342
            if ($lang) {
343
                $langdata['literal'] = Punic\Language::getName($proplang, $lang);
344
            }
345
346
            $langdata['properties'] = array();
347
            foreach ($properties as $prop => $value) {
348
                $langdata['properties'][] = array('property' => $prop, 'labels' => $value);
349
            }
350
            $counts[] = $langdata;
351
        }
352
353
        $ret = array(
354
            '@context' => array(
355
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
356
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
357
                'void' => 'http://rdfs.org/ns/void#',
358
                'void-ext' => 'http://ldf.fi/void-ext#',
359
                'onki' => 'http://schema.onki.fi/onki#',
360
                'uri' => '@id',
361
                'id' => 'onki:vocabularyIdentifier',
362
                'languages' => 'void-ext:languagePartition',
363
                'language' => 'void-ext:language',
364
                'properties' => 'void:propertyPartition',
365
                'labels' => 'void:triples',
366
            ),
367
            'uri' => '',
368
            'id' => $request->getVocab()->getId(),
369
            'title' => $request->getVocab()->getConfig()->getTitle($lang),
370
            'languages' => $counts,
371
        );
372
373
        if ($lang) {
374
            $ret['@context']['literal'] = array('@id' => 'rdfs:label', '@language' => $lang);
375
        }
376
377
        return $this->returnJson($ret);
378
    }
379
380
    /**
381
     * Loads the vocabulary type metadata. And wraps the result in a json-ld object.
382
     * @param Request $request
383
     */
384
    public function types($request)
385
    {
386
        $this->setLanguageProperties($request->getLang());
387
        $vocid = $request->getVocab() ? $request->getVocab()->getId() : null;
388
        $queriedtypes = $this->model->getTypes($vocid, $request->getLang());
389
390
        $types = array();
391
392
        /* encode the results in a JSON-LD compatible array */
393
        foreach ($queriedtypes as $uri => $typedata) {
394
            $type = array_merge(array('uri' => $uri), $typedata);
395
            $types[] = $type;
396
        }
397
398
        $ret = array_merge_recursive($this->context, array(
399
            '@context' => array('rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', 'onki' => 'http://schema.onki.fi/onki#', 'label' => 'rdfs:label', 'superclass' => array('@id' => 'rdfs:subClassOf', '@type' => '@id'), 'types' => 'onki:hasType', '@language' => $request->getLang()),
400
            'uri' => '',
401
            'types' => $types)
402
        );
403
404
        return $this->returnJson($ret);
405
    }
406
407
    /**
408
     * Used for finding terms by their exact prefLabel. Wraps the result in a json-ld object.
409
     * @param Request $request
410
     */
411
    public function lookup($request)
412
    {
413
        $label = $request->getQueryParam('label');
414
        if (!$label) {
415
            return $this->returnError(400, "Bad Request", "label parameter missing");
416
        }
417
418
        $lang = $request->getQueryParam('lang');
419
420
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig(), true);
421
422
        $results = $this->model->searchConcepts($parameters);
423
424
        $hits = array();
425
        // case 1: exact match on preferred label
426
        foreach ($results as $res) {
427
            if ($res['prefLabel'] == $label) {
428
                $hits[] = $res;
429
            }
430
        }
431
432
        // case 2: case-insensitive match on preferred label
433
        if (sizeof($hits) == 0) { // not yet found
434
            foreach ($results as $res) {
435
                if (strtolower($res['prefLabel']) == strtolower($label)) {
436
                    $hits[] = $res;
437
                }
438
            }
439
440
        }
441
442
        // case 3: exact match on alternate label
443 View Code Duplication
        if (sizeof($hits) == 0) { // not yet found
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
444
            foreach ($results as $res) {
445
                if (isset($res['altLabel']) && $res['altLabel'] == $label) {
446
                    $hits[] = $res;
447
                }
448
            }
449
450
        }
451
452
        // case 4: case-insensitive match on alternate label
453 View Code Duplication
        if (sizeof($hits) == 0) { // not yet found
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
454
            foreach ($results as $res) {
455
                if (isset($res['altLabel']) && strtolower($res['altLabel']) == strtolower($label)) {
456
                    $hits[] = $res;
457
                }
458
            }
459
460
        }
461
462
        if (sizeof($hits) == 0) {
463
            // no matches found
464
            return $this->returnError(404, 'Not Found', "Could not find label '$label'");
465
        }
466
467
        // did find some matches!
468
        // get rid of Vocabulary objects
469
        foreach ($hits as &$res) {
470
            unset($res['voc']);
471
        }
472
473
        $ret = array_merge_recursive($this->context, array(
474
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'results' => array('@id' => 'onki:results'), 'prefLabel' => 'skos:prefLabel', 'altLabel' => 'skos:altLabel', 'hiddenLabel' => 'skos:hiddenLabel'),
475
            'result' => $hits)
476
        );
477
478
        if ($lang) {
479
            $ret['@context']['@language'] = $lang;
480
        }
481
482
        return $this->returnJson($ret);
483
    }
484
485
    /**
486
     * Queries the top concepts of a vocabulary and wraps the results in a json-ld object.
487
     * @param Request $request
488
     * @return object json-ld object
489
     */
490
    public function topConcepts($request)
491
    {
492
        $vocab = $request->getVocab();
493
        $scheme = $request->getQueryParam('scheme');
494
        if (!$scheme) {
495
            $scheme = $vocab->getConfig()->showConceptSchemesInHierarchy() ? array_keys($vocab->getConceptSchemes()) : $vocab->getDefaultConceptScheme();
496
        }
497
498
        /* encode the results in a JSON-LD compatible array */
499
        $topconcepts = $vocab->getTopConcepts($scheme, $request->getLang());
500
501
        $ret = array_merge_recursive($this->context, array(
502
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'topconcepts' => 'skos:hasTopConcept', 'notation' => 'skos:notation', 'label' => 'skos:prefLabel', '@language' => $request->getLang()),
503
            'uri' => $scheme,
504
            'topconcepts' => $topconcepts)
505
        );
506
507
        return $this->returnJson($ret);
508
    }
509
510
    /**
511
     * Download a concept as json-ld or redirect to download the whole vocabulary.
512
     * @param Request $request
513
     * @return object json-ld formatted concept.
514
     */
515
    public function data($request)
516
    {
517
        $vocab = $request->getVocab();
518
        $format = $request->getQueryParam('format');
519
520
        if ($request->getUri()) {
521
            $uri = $request->getUri();
522
        } else if ($vocab !== null) { // whole vocabulary - redirect to download URL
523
            $urls = $vocab->getConfig()->getDataURLs();
524
            if (sizeof($urls) == 0) {
525
                return $this->returnError('404', 'Not Found', "No download source URL known for vocabulary $vocab");
526
            }
527
528
            $format = $this->negotiateFormat(array_keys($urls), $request->getServerConstant('HTTP_ACCEPT'), $format);
529
            if (!$format) {
530
                return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . implode(' ', array_keys($urls)));
531
            }
532
533
            header("Location: " . $urls[$format]);
534
            return;
535
        } else {
536
            return $this->returnError(400, 'Bad Request', "uri parameter missing");
537
        }
538
539
        $format = $this->negotiateFormat(explode(' ', self::$SUPPORTED_MIME_TYPES), $request->getServerConstant('HTTP_ACCEPT'), $format);
540
        if (!$format) {
541
            return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . self::$SUPPORTED_MIME_TYPES);
542
        }
543
544
        $vocid = $vocab ? $vocab->getId() : null;
545
        $results = $this->model->getRDF($vocid, $uri, $format);
546
547
        if ($format == 'application/ld+json' || $format == 'application/json') {
548
            // further compact JSON-LD document using a context
549
            $context = array(
550
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
551
                'isothes' => 'http://purl.org/iso25964/skos-thes#',
552
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
553
                'owl' => 'http://www.w3.org/2002/07/owl#',
554
                'dct' => 'http://purl.org/dc/terms/',
555
                'dc11' => 'http://purl.org/dc/elements/1.1/',
556
                'uri' => '@id',
557
                'type' => '@type',
558
                'lang' => '@language',
559
                'value' => '@value',
560
                'graph' => '@graph',
561
                'label' => 'rdfs:label',
562
                'prefLabel' => 'skos:prefLabel',
563
                'altLabel' => 'skos:altLabel',
564
                'hiddenLabel' => 'skos:hiddenLabel',
565
                'broader' => 'skos:broader',
566
                'narrower' => 'skos:narrower',
567
                'related' => 'skos:related',
568
                'inScheme' => 'skos:inScheme',
569
            );
570
            $compact_jsonld = \ML\JsonLD\JsonLD::compact($results, json_encode($context));
571
            $results = \ML\JsonLD\JsonLD::toString($compact_jsonld);
572
        }
573
574
        header("Content-type: $format; charset=utf-8");
575
        echo $results;
576
    }
577
578
    /**
579
     * Used for querying labels for a uri.
580
     * @param Request $request
581
     * @return object json-ld wrapped labels.
582
     */
583
    public function label($request)
584
    {
585
        if (!$request->getUri()) {
586
            return $this->returnError(400, "Bad Request", "uri parameter missing");
587
        }
588
589
        $results = $request->getVocab()->getConceptLabel($request->getUri(), $request->getLang());
590
        if ($results === null) {
591
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
592
        }
593
594
        $ret = array_merge_recursive($this->context, array(
595
            '@context' => array('prefLabel' => 'skos:prefLabel', '@language' => $request->getLang()),
596
            'uri' => $request->getUri())
597
        );
598
599
        if (isset($results[$request->getLang()])) {
600
            $ret['prefLabel'] = $results[$request->getLang()]->getValue();
601
        }
602
603
        return $this->returnJson($ret);
604
    }
605
606
    /**
607
     * Used for querying broader relations for a concept.
608
     * @param Request $request
609
     * @return object json-ld wrapped broader concept uris and labels.
610
     */
611 View Code Duplication
    public function broader($request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
612
    {
613
        $results = array();
614
        $broaders = $request->getVocab()->getConceptBroaders($request->getUri(), $request->getLang());
615
        if ($broaders === null) {
616
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
617
        }
618
619
        foreach ($broaders as $object => $vals) {
620
            $results[] = array('uri' => $object, 'prefLabel' => $vals['label']);
621
        }
622
623
        $ret = array_merge_recursive($this->context, array(
624
            '@context' => array('prefLabel' => 'skos:prefLabel', 'broader' => 'skos:broader', '@language' => $request->getLang()),
625
            'uri' => $request->getUri(),
626
            'broader' => $results)
627
        );
628
629
        return $this->returnJson($ret);
630
    }
631
632
    /**
633
     * Used for querying broader transitive relations for a concept.
634
     * @param Request $request
635
     * @return object json-ld wrapped broader transitive concept uris and labels.
636
     */
637 View Code Duplication
    public function broaderTransitive($request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
638
    {
639
        $results = array();
640
        $broaders = $request->getVocab()->getConceptTransitiveBroaders($request->getUri(), $this->parseLimit(), false, $request->getLang());
641
        if (empty($broaders)) {
642
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
643
        }
644
645
        foreach ($broaders as $buri => $vals) {
646
            $result = array('uri' => $buri, 'prefLabel' => $vals['label']);
647
            if (isset($vals['direct'])) {
648
                $result['broader'] = $vals['direct'];
649
            }
650
            $results[$buri] = $result;
651
        }
652
653
        $ret = array_merge_recursive($this->context, array(
654
            '@context' => array('prefLabel' => 'skos:prefLabel', 'broader' => array('@id' => 'skos:broader', '@type' => '@id'), 'broaderTransitive' => array('@id' => 'skos:broaderTransitive', '@container' => '@index'), '@language' => $request->getLang()),
655
            'uri' => $request->getUri(),
656
            'broaderTransitive' => $results)
657
        );
658
659
        return $this->returnJson($ret);
660
    }
661
662
    /**
663
     * Used for querying narrower relations for a concept.
664
     * @param Request $request
665
     * @return object json-ld wrapped narrower concept uris and labels.
666
     */
667 View Code Duplication
    public function narrower($request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
668
    {
669
        $results = array();
670
        $narrowers = $request->getVocab()->getConceptNarrowers($request->getUri(), $request->getLang());
671
        if ($narrowers === null) {
672
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
673
        }
674
675
        foreach ($narrowers as $object => $vals) {
676
            $results[] = array('uri' => $object, 'prefLabel' => $vals['label']);
677
        }
678
679
        $ret = array_merge_recursive($this->context, array(
680
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => 'skos:narrower', '@language' => $request->getLang()),
681
            'uri' => $request->getUri(),
682
            'narrower' => $results)
683
        );
684
685
        return $this->returnJson($ret);
686
    }
687
688
    /**
689
     * Used for querying narrower transitive relations for a concept.
690
     * @param Request $request
691
     * @return object json-ld wrapped narrower transitive concept uris and labels.
692
     */
693 View Code Duplication
    public function narrowerTransitive($request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
694
    {
695
        $results = array();
696
        $narrowers = $request->getVocab()->getConceptTransitiveNarrowers($request->getUri(), $this->parseLimit(), $request->getLang());
697
        if (empty($narrowers)) {
698
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
699
        }
700
701
        foreach ($narrowers as $nuri => $vals) {
702
            $result = array('uri' => $nuri, 'prefLabel' => $vals['label']);
703
            if (isset($vals['direct'])) {
704
                $result['narrower'] = $vals['direct'];
705
            }
706
            $results[$nuri] = $result;
707
        }
708
709
        $ret = array_merge_recursive($this->context, array(
710
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => array('@id' => 'skos:narrower', '@type' => '@id'), 'narrowerTransitive' => array('@id' => 'skos:narrowerTransitive', '@container' => '@index'), '@language' => $request->getLang()),
711
            'uri' => $request->getUri(),
712
            'narrowerTransitive' => $results)
713
        );
714
715
        return $this->returnJson($ret);
716
    }
717
718
    /**
719
     * Used for querying broader transitive relations
720
     * and some narrowers for a concept in the hierarchy view.
721
     * @param Request $request
722
     * @return object json-ld wrapped hierarchical concept uris and labels.
723
     */
724
    public function hierarchy($request)
725
    {
726
        $results = $request->getVocab()->getConceptHierarchy($request->getUri(), $request->getLang());
727
        if (empty($results)) {
728
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
729
        }
730
731
        if ($request->getVocab()->getConfig()->getShowHierarchy()) {
732
            $schemes = $request->getVocab()->getConceptSchemes($request->getLang());
733
            foreach ($schemes as $scheme) {
734
                if (!isset($scheme['title']) && !isset($scheme['label']) && !isset($scheme['prefLabel'])) {
735
                    unset($schemes[array_search($scheme, $schemes)]);
736
                }
737
738
            }
739
740
            /* encode the results in a JSON-LD compatible array */
741
            $topconcepts = $request->getVocab()->getTopConcepts(array_keys($schemes), $request->getLang());
742
            foreach ($topconcepts as $top) {
743
                if (!isset($results[$top['uri']])) {
744
                    $results[$top['uri']] = array('uri' => $top['uri'], 'top' => $top['topConceptOf'], 'prefLabel' => $top['label'], 'hasChildren' => $top['hasChildren']);
745
                    if (isset($top['notation'])) {
746
                        $results[$top['uri']]['notation'] = $top['notation'];
747
                    }
748
749
                }
750
            }
751
        }
752
753
        $ret = array_merge_recursive($this->context, array(
754
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'prefLabel' => 'skos:prefLabel', 'notation' => 'skos:notation', 'narrower' => array('@id' => 'skos:narrower', '@type' => '@id'), 'broader' => array('@id' => 'skos:broader', '@type' => '@id'), 'broaderTransitive' => array('@id' => 'skos:broaderTransitive', '@container' => '@index'), 'top' => array('@id' => 'skos:topConceptOf', '@type' => '@id'), 'hasChildren' => 'onki:hasChildren', '@language' => $request->getLang()),
755
            'uri' => $request->getUri(),
756
            'broaderTransitive' => $results)
757
        );
758
759
        return $this->returnJson($ret);
760
    }
761
762
    /**
763
     * Used for querying group hierarchy for the sidebar group view.
764
     * @param Request $request
765
     * @return object json-ld wrapped hierarchical concept uris and labels.
766
     */
767
    public function groups($request)
768
    {
769
        $results = $request->getVocab()->listConceptGroups($request->getLang());
770
771
        $ret = array_merge_recursive($this->context, array(
772
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'prefLabel' => 'skos:prefLabel', 'groups' => 'onki:hasGroup', 'childGroups' => array('@id' => 'skos:member', '@type' => '@id'), 'hasMembers' => 'onki:hasMembers', '@language' => $request->getLang()),
773
            'uri' => '',
774
            'groups' => $results)
775
        );
776
777
        return $this->returnJson($ret);
778
    }
779
780
    /**
781
     * Used for querying member relations for a group.
782
     * @param Request $request
783
     * @return object json-ld wrapped narrower concept uris and labels.
784
     */
785
    public function groupMembers($request)
786
    {
787
        $children = $request->getVocab()->listConceptGroupContents($request->getUri(), $request->getLang());
788
        if (empty($children)) {
789
            return $this->returnError('404', 'Not Found', "Could not find group <{$request->getUri()}>");
790
        }
791
792
        $ret = array_merge_recursive($this->context, array(
793
            '@context' => array('prefLabel' => 'skos:prefLabel', 'members' => 'skos:member', '@language' => $request->getLang()),
794
            'uri' => $request->getUri(),
795
            'members' => $children)
796
        );
797
798
        return $this->returnJson($ret);
799
    }
800
801
    /**
802
     * Used for querying narrower relations for a concept in the hierarchy view.
803
     * @param Request $request
804
     * @return object json-ld wrapped narrower concept uris and labels.
805
     */
806
    public function children($request)
807
    {
808
        $children = $request->getVocab()->getConceptChildren($request->getUri(), $request->getLang());
809
        if ($children === null) {
810
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
811
        }
812
813
        $ret = array_merge_recursive($this->context, array(
814
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => 'skos:narrower', 'notation' => 'skos:notation', 'hasChildren' => 'onki:hasChildren', '@language' => $request->getLang()),
815
            'uri' => $request->getUri(),
816
            'narrower' => $children)
817
        );
818
819
        return $this->returnJson($ret);
820
    }
821
822
    /**
823
     * Used for querying narrower relations for a concept in the hierarchy view.
824
     * @param Request $request
825
     * @return object json-ld wrapped hierarchical concept uris and labels.
826
     */
827
    public function related($request)
828
    {
829
        $results = array();
830
        $related = $request->getVocab()->getConceptRelateds($request->getUri(), $request->getLang());
831
        if ($related === null) {
832
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
833
        }
834
835
        foreach ($related as $uri => $vals) {
836
            $results[] = array('uri' => $uri, 'prefLabel' => $vals['label']);
837
        }
838
839
        $ret = array_merge_recursive($this->context, array(
840
            '@context' => array('prefLabel' => 'skos:prefLabel', 'related' => 'skos:related', '@language' => $request->getLang()),
841
            'uri' => $request->getUri(),
842
            'related' => $results)
843
        );
844
845
        return $this->returnJson($ret);
846
    }
847
}
848