Vocabulary::getAlphabet()   A
last analyzed

Complexity

Conditions 6
Paths 16

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 16
nop 1
dl 0
loc 25
rs 9.0777
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Vocabulary dataobjects provide access to the vocabularies on the SPARQL endpoint.
5
 */
6
class Vocabulary extends DataObject implements Modifiable
7
{
8
    /** cached value of URI space */
9
    private $urispace = null;
10
    private $config;
11
12
    public function __construct($model, $resource)
13
    {
14
        parent::__construct($model, $resource);
15
        $this->config = new VocabularyConfig($model, $resource, $model->getConfig()->getGlobalPlugins());
16
    }
17
18
    /**
19
     * Returns the VocabularyConfig object
20
     * @return VocabularyConfig
21
     */
22
    public function getConfig()
23
    {
24
        return $this->config;
25
    }
26
27
    /**
28
     * Get the SPARQL endpoint URL for this vocabulary
29
     *
30
     * @return string endpoint URL
31
     */
32
    public function getEndpoint()
33
    {
34
        $endpoint = $this->config->getSparqlEndpoint();
35
        if ($endpoint === null) {
36
            $endpoint = $this->model->getConfig()->getDefaultEndpoint();
37
        }
38
        return $endpoint;
39
    }
40
41
    /**
42
     * Get the SPARQL graph URI for this vocabulary
43
     *
44
     * @return string|null graph URI
45
     */
46
    public function getGraph()
47
    {
48
        return $this->config->getSparqlGraph();
49
    }
50
51
    /**
52
     * Get the SPARQL implementation for this vocabulary
53
     *
54
     * @return GenericSparql SPARQL object
55
     */
56
    public function getSparql()
57
    {
58
        $endpoint = $this->getEndpoint();
59
        $graph = $this->getGraph();
60
        $dialect = $this->config->getSparqlDialect() ?? $this->model->getConfig()->getDefaultSparqlDialect();
61
62
        return $this->model->getSparqlImplementation($dialect, $endpoint, $graph);
63
    }
64
65
    /**
66
     * Get the URI space of concepts in this vocabulary.
67
     *
68
     * @return string full URI of concept
69
     */
70
    public function getUriSpace()
71
    {
72
        if ($this->urispace === null) { // initialize cache
73
            $urispace = $this->resource->getLiteral('void:uriSpace');
74
            if ($urispace) {
0 ignored issues
show
introduced by
$urispace is of type EasyRdf\Literal, thus it always evaluated to true.
Loading history...
75
                $this->urispace = $urispace->getValue();
76
            }
77
        }
78
79
        return $this->urispace;
80
    }
81
82
    /**
83
     * Return true if the URI is within the URI space of this vocabulary.
84
     *
85
     * @param string full URI of concept
0 ignored issues
show
Bug introduced by
The type full was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
86
     * @return bool true if URI is within URI namespace, false otherwise
87
     */
88
89
    public function containsURI($uri)
90
    {
91
        return (strpos($uri, $this->getUriSpace()) === 0);
92
    }
93
94
    /**
95
     * Get the full URI of a concept in a vocabulary. If the passed local
96
     * name is already a full URI, return it unchanged.
97
     *
98
     * @param $lname string local name of concept
99
     * @return string full URI of concept
100
     */
101
    public function getConceptURI($lname)
102
    {
103
        if (strpos($lname, 'http') === 0) {
104
            return $lname;
105
        }
106
        // already a full URI
107
        return $this->getUriSpace() . $lname;
108
    }
109
110
    /**
111
     * Asks the sparql implementation to make a label query for a uri.
112
     * @param string $uri
113
     * @param string $lang
114
     */
115
    public function getConceptLabel($uri, $lang)
116
    {
117
        return $this->getSparql()->queryLabel($uri, $lang);
118
    }
119
120
    /**
121
     * Asks the sparql implementation to make a label query for a uri.
122
     * @param string $uri
123
     * @param string $lang
124
     * @return array array of altLabels
125
     */
126
    public function getAllConceptLabels($uri, $lang)
127
    {
128
        return $this->getSparql()->queryAllConceptLabels($uri, $lang);
129
    }
130
    /**
131
     * Get the localname of a concept in the vocabulary. If the URI is not
132
     * in the URI space of this vocabulary, return the full URI.
133
     *
134
     * @param $uri string full URI of concept
135
     * @return string local name of concept, or original full URI if the local name cannot be determined
136
     */
137
    public function getLocalName($uri)
138
    {
139
        return str_replace($this->getUriSpace(), "", $uri);
140
    }
141
142
    /**
143
     * Retrieves all the information about the Vocabulary
144
     * from the SPARQL-endpoint.
145
     */
146
    public function getInfo($lang = null)
147
    {
148
        $ret = array();
149
        if (!$lang) {
150
            $lang = $this->getLang();
151
        }
152
153
        // get metadata (literals only e.g. name) from vocabulary configuration file
154
        foreach ($this->resource->properties() as $prop) {
155
            foreach ($this->resource->allLiterals($prop, $lang) as $val) {
156
                $ret[$prop][] = $val->getValue();
157
            }
158
        }
159
160
        try {
161
            // also include ConceptScheme metadata from SPARQL endpoint
162
            $defaultcs = $this->getDefaultConceptScheme();
163
164
            // query everything the endpoint knows about the ConceptScheme
165
            $sparql = $this->getSparql();
166
            $result = $sparql->queryConceptScheme($defaultcs);
167
        } catch (EasyRdf\Http\Exception | EasyRdf\Exception | Throwable $e) {
168
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
169
                error_log('Caught exception: ' . $e->getMessage());
170
            }
171
            return null;
172
        }
173
        $conceptscheme = $result->resource($defaultcs);
174
        $this->order = array(
175
            "dc:title", "dc11:title", "skos:prefLabel", "rdfs:label",
176
            "dc:subject", "dc11:subject",
177
            "dc:description", "dc11:description",
178
            "foaf:homepage",
179
            "dc:publisher", "dc11:publisher",
180
            "dc:creator", "dc11:creator",
181
            "dc:contributor",
182
            "dc:license",
183
            "dc:rights", "dc11:rights",
184
            "dc:language", "dc11:language",
185
            "owl:versionInfo",
186
            "dc:source", "dc11:source",
187
            "dc:relation", "dc11:relation",
188
            "dc:created",
189
            "dc:modified",
190
            "dc:date", "dc11:date"
191
        );
192
193
        foreach ($conceptscheme->properties() as $prop) {
194
            foreach ($conceptscheme->allLiterals($prop, $lang) as $val) {
195
                $prop = (substr($prop, 0, 5) == 'dc11:') ? str_replace('dc11:', 'dc:', $prop) : $prop;
196
                $ret[$prop][$val->getValue()] = $val;
197
            }
198
            if (!isset($ret[$prop]) || sizeof($ret[$prop]) == 0) { // not found with language tag
199
                foreach ($conceptscheme->allLiterals($prop, null) as $val) {
200
                    $prop = (substr($prop, 0, 5) == 'dc11:') ? str_replace('dc11:', 'dc:', $prop) : $prop;
201
                    if ($val->getValue() instanceof DateTime) {
202
                        $val = Punic\Calendar::formatDate($val->getValue(), 'full', $lang) . ' ' . Punic\Calendar::format($val->getValue(), 'HH:mm:ss', $lang);
203
                    }
204
                    $ret[$prop][] = $val;
205
                }
206
            }
207
            foreach ($conceptscheme->allResources($prop) as $val) {
208
                $prop = (substr($prop, 0, 5) == 'dc11:') ? str_replace('dc11:', 'dc:', $prop) : $prop;
209
                $exvocab = $this->model->guessVocabularyFromURI($val->getURI());
210
                $exlabel = $this->getExternalLabel($exvocab, $val->getURI(), $lang);
211
                if (isset($exlabel)) {
212
                    $val->add('skosmos:vocab', $exvocab->getId());
213
                    $val->add('skosmos:label', $exlabel);
214
                }
215
                $label = $val->label($lang) ? $val->label($lang)->getValue() : $val->getUri();
216
                $ret[$prop][$exlabel ? $exlabel->getValue() : $label] = $val;
217
            }
218
            if (isset($ret[$prop])) {
219
                ksort($ret[$prop]);
220
            }
221
        }
222
        if (isset($ret['owl:versionInfo'])) { // if version info available for vocabulary convert it to a more readable format
223
            $ret['owl:versionInfo'][0] = $this->parseVersionInfo($ret['owl:versionInfo'][0]);
224
        }
225
        // remove duplicate values
226
        foreach (array_keys($ret) as $prop) {
227
            $ret[$prop] = array_unique($ret[$prop]);
228
        }
229
230
        $ret = $this->arbitrarySort($ret);
231
232
        // filtering multiple labels
233
        if (isset($ret['dc:title'])) {
234
            unset($ret['dc11:title'], $ret['skos:prefLabel'], $ret['rdfs:label']);
235
        } elseif (isset($ret['dc11:title'])) {
236
            unset($ret['skos:prefLabel'], $ret['rdfs:label']);
237
        } elseif (isset($ret['skos:prefLabel'])) {
238
            unset($ret['rdfs:label']);
239
        }
240
241
        return $ret;
242
    }
243
244
    /**
245
     * Return all concept schemes in the vocabulary.
246
     * @return array Array with concept scheme URIs (string) as keys and labels (string) as values
247
     */
248
249
    public function getConceptSchemes($lang = '')
250
    {
251
        if ($lang === '') {
252
            $lang = $this->getLang();
253
        }
254
        $conceptSchemes = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $conceptSchemes is dead and can be removed.
Loading history...
255
        try {
256
            $conceptSchemes = $this->getSparql()->queryConceptSchemes($lang);
257
        } catch (EasyRdf\Http\Exception | EasyRdf\Exception | Throwable $e) {
258
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
259
                error_log('Caught exception: ' . $e->getMessage());
260
            }
261
        }
262
        return $conceptSchemes;
263
    }
264
265
    /**
266
     * Return the URI of the default concept scheme of this vocabulary. If the skosmos:mainConceptScheme property is set in the
267
     * vocabulary configuration, that will be returned. Otherwise an arbitrary concept scheme will be returned.
268
     * @return string concept scheme URI
269
     */
270
271
    public function getDefaultConceptScheme()
272
    {
273
        $conceptScheme = $this->config->getMainConceptSchemeURI();
274
        if ($conceptScheme) {
275
            return $conceptScheme;
276
        }
277
278
        // mainConceptScheme not explicitly set, guess it
279
        $conceptSchemes = $this->getConceptSchemes();
280
        $conceptSchemeURIs = array_keys($conceptSchemes);
281
        // return the URI of the last concept scheme
282
        return array_pop($conceptSchemeURIs);
283
    }
284
285
    /**
286
     * Returns the main Concept Scheme of that Vocabulary, or null if not set.
287
     * @param string $defaultConceptSchemeURI default concept scheme URI
288
     * @return \EasyRdf\Graph|mixed
289
     */
290
    public function getConceptScheme(string $defaultConceptSchemeURI)
291
    {
292
        return $this->getSparql()->queryConceptScheme($defaultConceptSchemeURI);
293
    }
294
295
    /**
296
     * Return the top concepts of a concept scheme in the vocabulary.
297
     * @param string $conceptScheme URI of concept scheme whose top concepts to return. If not set,
298
     *                              the default concept scheme of the vocabulary will be used.
299
     * @param string $lang preferred language for the concept labels,
300
     * @return array Array with concept URIs (string) as keys and labels (string) as values
301
     */
302
303
    public function getTopConcepts($conceptScheme = null, $lang = '')
304
    {
305
        if ($lang === '') {
306
            $lang = $this->getLang();
307
        }
308
        $fallback = $this->config->getDefaultLanguage();
309
310
        if ($conceptScheme === null || $conceptScheme == '') {
311
            $conceptScheme = $this->getDefaultConceptScheme();
312
        }
313
314
        return $this->getSparql()->queryTopConcepts($conceptScheme, $lang, $fallback);
315
    }
316
317
    /**
318
     * Tries to parse version, date and time from sparql version information into a readable format.
319
     * @param string $version
320
     * @return string
321
     */
322
    private function parseVersionInfo($version)
323
    {
324
        $parts = explode(' ', $version);
325
        if ($parts[0] != '$Id:') {
326
            return $version;
327
        }
328
        // don't know how to parse
329
        $rev = $parts[2];
330
        $datestr = $parts[3] . ' ' . $parts[4];
331
332
        return "$datestr (r$rev)";
333
    }
334
335
    /**
336
     * Counts the statistics of the vocabulary.
337
     * @return Array containing the label counts
338
     * @param string $array the uri of the concept array class, eg. isothes:ThesaurusArray
339
     * @param string $group the uri of the  concept group class, eg. isothes:ConceptGroup
340
     */
341
    public function getStatistics($lang = '', $array = null, $group = null)
342
    {
343
        $sparql = $this->getSparql();
344
        // find the number of concepts
345
        return $sparql->countConcepts($lang, $array, $group);
346
    }
347
348
    /**
349
     * Counts the statistics of the vocabulary.
350
     * @return array of the concept counts in different languages
351
     */
352
    public function getLabelStatistics()
353
    {
354
        $sparql = $this->getSparql();
355
        $ret = array();
356
        // count the number of different types of concepts in all languages
357
        $ret['terms'] = $sparql->countLangConcepts($this->config->getLanguages(), $this->config->getIndexClasses());
358
359
        return $ret;
360
    }
361
362
    /**
363
     * Gets the parent concepts of a concept and child concepts for all of those.
364
     * @param string $uri
365
     * @param string $lang language identifier.
366
     */
367
    public function getConceptHierarchy($uri, $lang)
368
    {
369
        $lang = $lang ? $lang : $this->getLang();
370
        $fallback = count($this->config->getLanguageOrder($lang)) > 1 ? $this->config->getLanguageOrder($lang)[1] : $this->config->getDefaultLanguage();
371
        $props = $this->config->getHierarchyProperty();
372
        return $this->getSparql()->queryParentList($uri, $lang, $fallback, $props);
373
    }
374
375
    /**
376
     * Gets the child relations of a concept and whether these children have more children.
377
     * @param string $uri
378
     */
379
    public function getConceptChildren($uri, $lang)
380
    {
381
        $lang = $lang ? $lang : $this->getLang();
382
        $fallback = count($this->config->getLanguageOrder($lang)) > 1 ? $this->config->getLanguageOrder($lang)[1] : $this->config->getDefaultLanguage();
383
        $props = $this->config->getHierarchyProperty();
384
        return $this->getSparql()->queryChildren($uri, $lang, $fallback, $props);
385
    }
386
387
    /**
388
     * Gets the skos:narrower relations of a concept.
389
     * @param string $uri
390
     * @param string $lang language identifier.
391
     */
392
    public function getConceptNarrowers($uri, $lang)
393
    {
394
        $lang = $lang ? $lang : $this->getLang();
395
        return $this->getSparql()->queryProperty($uri, 'skos:narrower', $lang);
396
    }
397
398
    /**
399
     * Gets the skos:narrowerTransitive relations of a concept.
400
     * @param string $uri
401
     * @param integer $limit
402
     * @param string $lang language identifier.
403
     */
404
    public function getConceptTransitiveNarrowers($uri, $limit, $lang)
405
    {
406
        $lang = $lang ? $lang : $this->getLang();
407
        return $this->getSparql()->queryTransitiveProperty($uri, array('skos:narrower'), $lang, $limit);
408
    }
409
410
    /**
411
     * Gets the skos:broader relations of a concept.
412
     * @param string $uri
413
     * @param string $lang language identifier.
414
     */
415
    public function getConceptBroaders($uri, $lang)
416
    {
417
        $lang = $lang ? $lang : $this->getLang();
418
        return $this->getSparql()->queryProperty($uri, 'skos:broader', $lang);
419
    }
420
421
    /**
422
     * Gets the skos:broaderTransitive relations of a concept.
423
     * @param string $uri
424
     * @param integer $limit
425
     * @param boolean $any set to true if you want to have a label even in case of a correct language one missing.
426
     * @param string $lang language identifier.
427
     */
428
    public function getConceptTransitiveBroaders($uri, $limit, $any, $lang)
429
    {
430
        $lang = $lang ? $lang : $this->getLang();
431
        $fallback = $this->config->getDefaultLanguage();
432
        return $this->getSparql()->queryTransitiveProperty($uri, array('skos:broader'), $lang, $limit, $any, $fallback);
433
    }
434
435
    /**
436
     * Gets all the skos:related concepts of a concept.
437
     * @param string $uri
438
     * @param string $lang language identifier.
439
     */
440
    public function getConceptRelateds($uri, $lang)
441
    {
442
        $lang = $lang ? $lang : $this->getLang();
443
        return $this->getSparql()->queryProperty($uri, 'skos:related', $lang);
444
    }
445
446
    /**
447
     * Get all information about a single concept.
448
     * @param string $uri full URI of the concept
449
     * @param string $clang content language
450
     * @return Concept
451
     */
452
    public function getConceptInfo(string $uri, string $clang): ?Concept
453
    {
454
        $sparql = $this->getSparql();
455
        $conceptInfo = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $conceptInfo is dead and can be removed.
Loading history...
456
        try {
457
            $conceptInfo = $sparql->queryConceptInfo([$uri], $this->config->getArrayClassURI(), array($this), $clang);
458
        } catch (EasyRdf\Http\Exception | EasyRdf\Exception | Throwable $e) {
459
            if ($this->model->getConfig()->getLogCaughtExceptions()) {
460
                error_log('Caught exception: ' . $e->getMessage());
461
            }
462
        }
463
        if (!$conceptInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $conceptInfo of type Concept[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
$conceptInfo is a non-empty array, thus ! $conceptInfo is always false.
Loading history...
464
            return null;
465
        }
466
        return $conceptInfo[0];
467
    }
468
469
    /**
470
     * Lists the different concept groups available in the vocabulary.
471
     * @param string $clang content language parameter
472
     * @return array
473
     */
474
    public function listConceptGroups($clang = null)
475
    {
476
        if ($clang === null || $clang == '') {
477
            $clang = $this->getLang();
478
        }
479
480
        $ret = array();
481
        $gclass = $this->config->getGroupClassURI();
482
        if ($gclass === null) {
0 ignored issues
show
introduced by
The condition $gclass === null is always false.
Loading history...
483
            return $ret;
484
        }
485
        // no group class defined, so empty result
486
        $groups = $this->getSparql()->listConceptGroups($gclass, $clang);
487
        foreach ($groups as $uri => $label) {
488
            $ret[$uri] = $label;
489
        }
490
491
        return $ret;
492
    }
493
494
    /**
495
     * Lists the concepts available in the concept group.
496
     * @param $clname
497
     * @return array
498
     */
499
    public function listConceptGroupContents($glname, $clang)
500
    {
501
        if (!$clang) {
502
            $clang = $this->getLang();
503
        }
504
505
        $ret = array();
506
        $gclass = $this->config->getGroupClassURI();
507
        if ($gclass === null) {
0 ignored issues
show
introduced by
The condition $gclass === null is always false.
Loading history...
508
            return $ret;
509
        }
510
        // no group class defined, so empty result
511
        $group = $this->getConceptURI($glname);
512
        $contents = $this->getSparql()->listConceptGroupContents($gclass, $group, $clang, $this->config->getShowDeprecated());
513
        foreach ($contents as $uri => $label) {
514
            $ret[$uri] = $label;
515
        }
516
517
        return $ret;
518
    }
519
520
    /**
521
     * Returns the letters of the alphabet which have been used in this vocabulary.
522
     * The returned letters may also include specials such as '0-9' (digits) and '!*' (special characters).
523
     * @param $clang content language
0 ignored issues
show
Bug introduced by
The type content was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
524
     * @return array array of letters
525
     */
526
    public function getAlphabet($clang)
527
    {
528
        $chars = $this->getSparql()->queryFirstCharacters($clang, $this->config->getIndexClasses());
529
        $letters = array();
530
        $digits = false;
531
        $specials = false;
532
        foreach ($chars as $char) {
533
            if (preg_match('/\p{L}/u', $char)) {
534
                $letters[] = $char;
535
            } elseif (preg_match('/\d/u', $char)) {
536
                $digits = true;
537
            } else {
538
                $specials = true;
539
            }
540
        }
541
        usort($letters, 'strcoll');
542
        if ($specials) {
543
            $letters[] = '!*';
544
        }
545
546
        if ($digits) {
547
            $letters[] = '0-9';
548
        }
549
550
        return $letters;
551
    }
552
553
    /**
554
     * Searches for concepts with a label starting with the specified letter.
555
     * Also the special tokens '0-9' (digits), '!*' (special characters) and '*'
556
     * (everything) are supported.
557
     * @param $letter letter (or special token) to search for
0 ignored issues
show
Bug introduced by
The type letter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
558
     */
559
    public function searchConceptsAlphabetical($letter, $limit = null, $offset = null, $clang = null)
560
    {
561
        return $this->getSparql()->queryConceptsAlphabetical($letter, $clang, $limit, $offset, $this->config->getIndexClasses(), $this->config->getShowDeprecated(), $this->config->getAlphabeticalListQualifier());
562
    }
563
564
    /**
565
     * Makes a query for the transitive broaders of a concept and returns the concepts hierarchy processed for the view.
566
     * @param string $lang
567
     * @param string $uri
568
     */
569
    public function getBreadCrumbs($lang, $uri)
570
    {
571
        $broaders = $this->getConceptTransitiveBroaders($uri, 1000, true, $lang);
572
        $origCrumbs = $this->getCrumbs($broaders, $uri);
573
        return $this->combineCrumbs($origCrumbs);
574
    }
575
576
    /**
577
     * Takes the crumbs as a parameter and combines the crumbs if the path they form is too long.
578
     * @return array
579
     */
580
    private function combineCrumbs($origCrumbs)
581
    {
582
        $combined = array();
583
        foreach ($origCrumbs as $pathKey => $path) {
584
            $firstToCombine = true;
585
            $combinedPath = array();
586
            foreach ($path as $crumbKey => $crumb) {
587
                if ($crumb->getPrefLabel() === '...') {
588
                    array_push($combinedPath, $crumb);
589
                    if ($firstToCombine) {
590
                        $firstToCombine = false;
591
                    } else {
592
                        unset($origCrumbs[$pathKey][$crumbKey]);
593
                    }
594
                }
595
            }
596
            $combined[] = $combinedPath;
597
        }
598
599
        return array('combined' => $combined, 'breadcrumbs' => $origCrumbs);
600
    }
601
602
    /**
603
     * Recursive function for building the breadcrumb paths for the view.
604
     * @param array $bTresult contains the results of the broaderTransitive query.
605
     * @param string $uri
606
     * @param array $path
607
     */
608
    private function getCrumbs($bTresult, $uri, $path = null)
609
    {
610
        $crumbs = array();
611
        if (!isset($path)) {
612
            $path = array();
613
        }
614
615
        // check that there is no cycle (issue #220)
616
        foreach ($path as $childcrumb) {
617
            if ($childcrumb->getUri() == $uri) {
618
                // found a cycle - short-circuit and stop
619
                return $crumbs;
620
            }
621
        }
622
        if (isset($bTresult[$uri]['direct'])) {
623
            foreach ($bTresult[$uri]['direct'] as $broaderUri) {
624
                $newpath = array_merge($path, array(new Breadcrumb($uri, $bTresult[$uri]['label'])));
625
                if ($uri !== $broaderUri) {
626
                    $crumbs = array_merge($crumbs, $this->getCrumbs($bTresult, $broaderUri, $newpath));
627
                }
628
            }
629
        } else { // we have reached the end of a path and we need to start a new row in the 'stack'
630
            if (isset($bTresult[$uri])) {
631
                $path = array_merge($path, array(new Breadcrumb($uri, $bTresult[$uri]['label'])));
632
            }
633
634
            $index = 1;
635
            $length = sizeof($path);
636
            $limit = $length - 5;
637
            foreach ($path as $crumb) {
638
                if ($length > 5 && $index > $length - $limit) { // displays 5 concepts closest to the concept.
639
                    $crumb->hideLabel();
640
                }
641
                $index++;
642
            }
643
            $crumbs[] = array_reverse($path);
644
        }
645
        return $crumbs;
646
    }
647
648
    /**
649
     * Verify that the requested language is supported by the vocabulary. If not, returns
650
     * the default language of the vocabulary.
651
     * @param string $lang language to check
652
     * @return string language tag that is supported by the vocabulary
653
     */
654
655
    public function verifyVocabularyLanguage($lang)
656
    {
657
        return (in_array($lang, $this->config->getLanguages())) ? $lang : $this->config->getDefaultLanguage();
658
    }
659
660
    /**
661
     * Returns a list of recently changed or entirely new concepts.
662
     * @param string $prop the property uri pointing to timestamps, eg. 'dc:modified'
663
     * @param string $clang content language for the labels
664
     * @param int $offset starting index offset
665
     * @param int $limit maximum number of concepts to return
666
     * @return Array
667
     */
668
    public function getChangeList($prop, $clang, $offset, $limit)
669
    {
670
        $showDeprecated = $this->getConfig()->getShowDeprecatedChanges();
671
        return $this->getSparql()->queryChangeList($prop, $clang, $offset, $limit, $showDeprecated);
672
    }
673
674
    public function getTitle($lang = null)
675
    {
676
        return $this->config->getTitle($lang);
677
    }
678
679
    public function getShortName()
680
    {
681
        return $this->config->getShortName();
682
    }
683
684
    public function getId()
685
    {
686
        return $this->config->getId();
687
    }
688
689
    public function getModifiedDate()
690
    {
691
        $modifiedDate = null;
692
693
        $conceptSchemeURI = $this->getDefaultConceptScheme();
694
        if ($conceptSchemeURI) {
695
            $conceptSchemeGraph = $this->getConceptScheme($conceptSchemeURI);
696
            if (!$conceptSchemeGraph->isEmpty()) {
697
                $literal = $conceptSchemeGraph->getLiteral($conceptSchemeURI, "dc:modified");
698
                if ($literal) {
0 ignored issues
show
introduced by
$literal is of type EasyRdf\Literal, thus it always evaluated to true.
Loading history...
699
                    $modifiedDate = $literal->getValue();
700
                }
701
            }
702
        }
703
704
        return $modifiedDate;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $modifiedDate also could return the type boolean|integer|string which is incompatible with the return type mandated by Modifiable::getModifiedDate() of DateTime|null.
Loading history...
705
    }
706
707
    public function isUseModifiedDate()
708
    {
709
        return $this->getConfig()->isUseModifiedDate();
710
    }
711
}
712