Completed
Push — master ( 1d9aa7...03d576 )
by Henri
10:00
created

RestController::lookup()   D

Complexity

Conditions 18
Paths 121

Size

Total Lines 74
Code Lines 34

Duplication

Lines 16
Ratio 21.62 %
Metric Value
dl 16
loc 74
rs 4.9556
cc 18
eloc 34
nc 121
nop 1

How to fix   Long Method    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
        $vocab = $request->getVocab();
0 ignored issues
show
Unused Code introduced by
$vocab is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
420
421
        $parameters = new ConceptSearchParameters($request, $this->model->getConfig(), true);
422
423
        $results = $this->model->searchConcepts($parameters);
424
425
        $hits = array();
426
        // case 1: exact match on preferred label
427
        foreach ($results as $res) {
428
            if ($res['prefLabel'] == $label) {
429
                $hits[] = $res;
430
            }
431
        }
432
433
        // case 2: case-insensitive match on preferred label
434
        if (sizeof($hits) == 0) { // not yet found
435
            foreach ($results as $res) {
436
                if (strtolower($res['prefLabel']) == strtolower($label)) {
437
                    $hits[] = $res;
438
                }
439
            }
440
441
        }
442
443
        // case 3: exact match on alternate label
444 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...
445
            foreach ($results as $res) {
446
                if (isset($res['altLabel']) && $res['altLabel'] == $label) {
447
                    $hits[] = $res;
448
                }
449
            }
450
451
        }
452
453
        // case 4: case-insensitive match on alternate label
454 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...
455
            foreach ($results as $res) {
456
                if (isset($res['altLabel']) && strtolower($res['altLabel']) == strtolower($label)) {
457
                    $hits[] = $res;
458
                }
459
            }
460
461
        }
462
463
        if (sizeof($hits) == 0) {
464
            // no matches found
465
            return $this->returnError(404, 'Not Found', "Could not find label '$label'");
466
        }
467
468
        // did find some matches!
469
        // get rid of Vocabulary objects
470
        foreach ($hits as &$res) {
471
            unset($res['voc']);
472
        }
473
474
        $ret = array_merge_recursive($this->context, array(
475
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'results' => array('@id' => 'onki:results'), 'prefLabel' => 'skos:prefLabel', 'altLabel' => 'skos:altLabel', 'hiddenLabel' => 'skos:hiddenLabel'),
476
            'result' => $hits)
477
        );
478
479
        if ($lang) {
480
            $ret['@context']['@language'] = $lang;
481
        }
482
483
        return $this->returnJson($ret);
484
    }
485
486
    /**
487
     * Queries the top concepts of a vocabulary and wraps the results in a json-ld object.
488
     * @param Request $request
489
     * @return object json-ld object
490
     */
491
    public function topConcepts($request)
492
    {
493
        $vocab = $request->getVocab();
494
        $scheme = $request->getQueryParam('scheme');
495
        if (!$scheme) {
496
            $scheme = $vocab->getConfig()->showConceptSchemesInHierarchy() ? array_keys($vocab->getConceptSchemes()) : $vocab->getDefaultConceptScheme();
497
        }
498
499
        /* encode the results in a JSON-LD compatible array */
500
        $topconcepts = $vocab->getTopConcepts($scheme, $request->getLang());
501
502
        $ret = array_merge_recursive($this->context, array(
503
            '@context' => array('onki' => 'http://schema.onki.fi/onki#', 'topconcepts' => 'skos:hasTopConcept', 'notation' => 'skos:notation', 'label' => 'skos:prefLabel', '@language' => $request->getLang()),
504
            'uri' => $scheme,
505
            'topconcepts' => $topconcepts)
506
        );
507
508
        return $this->returnJson($ret);
509
    }
510
511
    /**
512
     * Download a concept as json-ld or redirect to download the whole vocabulary.
513
     * @param Request $request
514
     * @return object json-ld formatted concept.
515
     */
516
    public function data($request)
517
    {
518
        $vocab = $request->getVocab();
519
        $format = $request->getQueryParam('format');
520
521
        if ($request->getUri()) {
522
            $uri = $request->getUri();
523
        } else if ($vocab !== null) { // whole vocabulary - redirect to download URL
524
            $urls = $vocab->getConfig()->getDataURLs();
525
            if (sizeof($urls) == 0) {
526
                return $this->returnError('404', 'Not Found', "No download source URL known for vocabulary $vocab");
527
            }
528
529
            $format = $this->negotiateFormat(array_keys($urls), $request->getServerConstant('HTTP_ACCEPT'), $format);
530
            if (!$format) {
531
                return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . implode(' ', array_keys($urls)));
532
            }
533
534
            header("Location: " . $urls[$format]);
535
            return;
536
        } else {
537
            return $this->returnError(400, 'Bad Request', "uri parameter missing");
538
        }
539
540
        $format = $this->negotiateFormat(explode(' ', self::$SUPPORTED_MIME_TYPES), $request->getServerConstant('HTTP_ACCEPT'), $format);
541
        if (!$format) {
542
            return $this->returnError(406, 'Not Acceptable', "Unsupported format. Supported MIME types are: " . self::$SUPPORTED_MIME_TYPES);
543
        }
544
545
        $vocid = $vocab ? $vocab->getId() : null;
546
        $results = $this->model->getRDF($vocid, $uri, $format);
547
548
        if ($format == 'application/ld+json' || $format == 'application/json') {
549
            // further compact JSON-LD document using a context
550
            $context = array(
551
                'skos' => 'http://www.w3.org/2004/02/skos/core#',
552
                'isothes' => 'http://purl.org/iso25964/skos-thes#',
553
                'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
554
                'owl' => 'http://www.w3.org/2002/07/owl#',
555
                'dct' => 'http://purl.org/dc/terms/',
556
                'dc11' => 'http://purl.org/dc/elements/1.1/',
557
                'uri' => '@id',
558
                'type' => '@type',
559
                'lang' => '@language',
560
                'value' => '@value',
561
                'graph' => '@graph',
562
                'label' => 'rdfs:label',
563
                'prefLabel' => 'skos:prefLabel',
564
                'altLabel' => 'skos:altLabel',
565
                'hiddenLabel' => 'skos:hiddenLabel',
566
                'broader' => 'skos:broader',
567
                'narrower' => 'skos:narrower',
568
                'related' => 'skos:related',
569
                'inScheme' => 'skos:inScheme',
570
            );
571
            $compact_jsonld = \ML\JsonLD\JsonLD::compact($results, json_encode($context));
572
            $results = \ML\JsonLD\JsonLD::toString($compact_jsonld);
573
        }
574
575
        header("Content-type: $format; charset=utf-8");
576
        echo $results;
577
    }
578
579
    /**
580
     * Used for querying labels for a uri.
581
     * @param Request $request
582
     * @return object json-ld wrapped labels.
583
     */
584
    public function label($request)
585
    {
586
        if (!$request->getUri()) {
587
            return $this->returnError(400, "Bad Request", "uri parameter missing");
588
        }
589
590
        $results = $request->getVocab()->getConceptLabel($request->getUri(), $request->getLang());
591
        if ($results === null) {
592
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
593
        }
594
595
        $ret = array_merge_recursive($this->context, array(
596
            '@context' => array('prefLabel' => 'skos:prefLabel', '@language' => $request->getLang()),
597
            'uri' => $request->getUri())
598
        );
599
600
        if (isset($results[$request->getLang()])) {
601
            $ret['prefLabel'] = $results[$request->getLang()]->getValue();
602
        }
603
604
        return $this->returnJson($ret);
605
    }
606
607
    /**
608
     * Used for querying broader relations for a concept.
609
     * @param Request $request
610
     * @return object json-ld wrapped broader concept uris and labels.
611
     */
612 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...
613
    {
614
        $results = array();
615
        $broaders = $request->getVocab()->getConceptBroaders($request->getUri(), $request->getLang());
616
        if ($broaders === null) {
617
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
618
        }
619
620
        foreach ($broaders as $object => $vals) {
621
            $results[] = array('uri' => $object, 'prefLabel' => $vals['label']);
622
        }
623
624
        $ret = array_merge_recursive($this->context, array(
625
            '@context' => array('prefLabel' => 'skos:prefLabel', 'broader' => 'skos:broader', '@language' => $request->getLang()),
626
            'uri' => $request->getUri(),
627
            'broader' => $results)
628
        );
629
630
        return $this->returnJson($ret);
631
    }
632
633
    /**
634
     * Used for querying broader transitive relations for a concept.
635
     * @param Request $request
636
     * @return object json-ld wrapped broader transitive concept uris and labels.
637
     */
638 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...
639
    {
640
        $results = array();
641
        $broaders = $request->getVocab()->getConceptTransitiveBroaders($request->getUri(), $this->parseLimit(), false, $request->getLang());
642
        if (empty($broaders)) {
643
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
644
        }
645
646
        foreach ($broaders as $buri => $vals) {
647
            $result = array('uri' => $buri, 'prefLabel' => $vals['label']);
648
            if (isset($vals['direct'])) {
649
                $result['broader'] = $vals['direct'];
650
            }
651
            $results[$buri] = $result;
652
        }
653
654
        $ret = array_merge_recursive($this->context, array(
655
            '@context' => array('prefLabel' => 'skos:prefLabel', 'broader' => array('@id' => 'skos:broader', '@type' => '@id'), 'broaderTransitive' => array('@id' => 'skos:broaderTransitive', '@container' => '@index'), '@language' => $request->getLang()),
656
            'uri' => $request->getUri(),
657
            'broaderTransitive' => $results)
658
        );
659
660
        return $this->returnJson($ret);
661
    }
662
663
    /**
664
     * Used for querying narrower relations for a concept.
665
     * @param Request $request
666
     * @return object json-ld wrapped narrower concept uris and labels.
667
     */
668 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...
669
    {
670
        $results = array();
671
        $narrowers = $request->getVocab()->getConceptNarrowers($request->getUri(), $request->getLang());
672
        if ($narrowers === null) {
673
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
674
        }
675
676
        foreach ($narrowers as $object => $vals) {
677
            $results[] = array('uri' => $object, 'prefLabel' => $vals['label']);
678
        }
679
680
        $ret = array_merge_recursive($this->context, array(
681
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => 'skos:narrower', '@language' => $request->getLang()),
682
            'uri' => $request->getUri(),
683
            'narrower' => $results)
684
        );
685
686
        return $this->returnJson($ret);
687
    }
688
689
    /**
690
     * Used for querying narrower transitive relations for a concept.
691
     * @param Request $request
692
     * @return object json-ld wrapped narrower transitive concept uris and labels.
693
     */
694 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...
695
    {
696
        $results = array();
697
        $narrowers = $request->getVocab()->getConceptTransitiveNarrowers($request->getUri(), $this->parseLimit(), $request->getLang());
698
        if (empty($narrowers)) {
699
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
700
        }
701
702
        foreach ($narrowers as $nuri => $vals) {
703
            $result = array('uri' => $nuri, 'prefLabel' => $vals['label']);
704
            if (isset($vals['direct'])) {
705
                $result['narrower'] = $vals['direct'];
706
            }
707
            $results[$nuri] = $result;
708
        }
709
710
        $ret = array_merge_recursive($this->context, array(
711
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => array('@id' => 'skos:narrower', '@type' => '@id'), 'narrowerTransitive' => array('@id' => 'skos:narrowerTransitive', '@container' => '@index'), '@language' => $request->getLang()),
712
            'uri' => $request->getUri(),
713
            'narrowerTransitive' => $results)
714
        );
715
716
        return $this->returnJson($ret);
717
    }
718
719
    /**
720
     * Used for querying broader transitive relations
721
     * and some narrowers for a concept in the hierarchy view.
722
     * @param Request $request
723
     * @return object json-ld wrapped hierarchical concept uris and labels.
724
     */
725
    public function hierarchy($request)
726
    {
727
        $results = $request->getVocab()->getConceptHierarchy($request->getUri(), $request->getLang());
728
        if (empty($results)) {
729
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
730
        }
731
732
        if ($request->getVocab()->getConfig()->getShowHierarchy()) {
733
            $schemes = $request->getVocab()->getConceptSchemes($request->getLang());
734
            foreach ($schemes as $scheme) {
735
                if (!isset($scheme['title']) && !isset($scheme['label']) && !isset($scheme['prefLabel'])) {
736
                    unset($schemes[array_search($scheme, $schemes)]);
737
                }
738
739
            }
740
741
            /* encode the results in a JSON-LD compatible array */
742
            $topconcepts = $request->getVocab()->getTopConcepts(array_keys($schemes), $request->getLang());
743
            foreach ($topconcepts as $top) {
744
                if (!isset($results[$top['uri']])) {
745
                    $results[$top['uri']] = array('uri' => $top['uri'], 'top' => $top['topConceptOf'], 'prefLabel' => $top['label'], 'hasChildren' => $top['hasChildren']);
746
                    if (isset($top['notation'])) {
747
                        $results[$top['uri']]['notation'] = $top['notation'];
748
                    }
749
750
                }
751
            }
752
        }
753
754
        $ret = array_merge_recursive($this->context, array(
755
            '@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()),
756
            'uri' => $request->getUri(),
757
            'broaderTransitive' => $results)
758
        );
759
760
        return $this->returnJson($ret);
761
    }
762
763
    /**
764
     * Used for querying group hierarchy for the sidebar group view.
765
     * @param Request $request
766
     * @return object json-ld wrapped hierarchical concept uris and labels.
767
     */
768
    public function groups($request)
769
    {
770
        $results = $request->getVocab()->listConceptGroups($request->getLang());
771
772
        $ret = array_merge_recursive($this->context, array(
773
            '@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()),
774
            'uri' => '',
775
            'groups' => $results)
776
        );
777
778
        return $this->returnJson($ret);
779
    }
780
781
    /**
782
     * Used for querying member relations for a group.
783
     * @param Request $request
784
     * @return object json-ld wrapped narrower concept uris and labels.
785
     */
786
    public function groupMembers($request)
787
    {
788
        $children = $request->getVocab()->listConceptGroupContents($request->getUri(), $request->getLang());
789
        if (empty($children)) {
790
            return $this->returnError('404', 'Not Found', "Could not find group <{$request->getUri()}>");
791
        }
792
793
        $ret = array_merge_recursive($this->context, array(
794
            '@context' => array('prefLabel' => 'skos:prefLabel', 'members' => 'skos:member', '@language' => $request->getLang()),
795
            'uri' => $request->getUri(),
796
            'members' => $children)
797
        );
798
799
        return $this->returnJson($ret);
800
    }
801
802
    /**
803
     * Used for querying narrower relations for a concept in the hierarchy view.
804
     * @param Request $request
805
     * @return object json-ld wrapped narrower concept uris and labels.
806
     */
807
    public function children($request)
808
    {
809
        $children = $request->getVocab()->getConceptChildren($request->getUri(), $request->getLang());
810
        if ($children === null) {
811
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
812
        }
813
814
        $ret = array_merge_recursive($this->context, array(
815
            '@context' => array('prefLabel' => 'skos:prefLabel', 'narrower' => 'skos:narrower', 'notation' => 'skos:notation', 'hasChildren' => 'onki:hasChildren', '@language' => $request->getLang()),
816
            'uri' => $request->getUri(),
817
            'narrower' => $children)
818
        );
819
820
        return $this->returnJson($ret);
821
    }
822
823
    /**
824
     * Used for querying narrower relations for a concept in the hierarchy view.
825
     * @param Request $request
826
     * @return object json-ld wrapped hierarchical concept uris and labels.
827
     */
828
    public function related($request)
829
    {
830
        $results = array();
831
        $related = $request->getVocab()->getConceptRelateds($request->getUri(), $request->getLang());
832
        if ($related === null) {
833
            return $this->returnError('404', 'Not Found', "Could not find concept <{$request->getUri()}>");
834
        }
835
836
        foreach ($related as $uri => $vals) {
837
            $results[] = array('uri' => $uri, 'prefLabel' => $vals['label']);
838
        }
839
840
        $ret = array_merge_recursive($this->context, array(
841
            '@context' => array('prefLabel' => 'skos:prefLabel', 'related' => 'skos:related', '@language' => $request->getLang()),
842
            'uri' => $request->getUri(),
843
            'related' => $results)
844
        );
845
846
        return $this->returnJson($ret);
847
    }
848
}
849