Completed
Push — master ( d3db5d...0f1d78 )
by Henri
02:25
created

Concept::getGroupProperties()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * Dataobject for a single concept.
5
 */
6
7
class Concept extends VocabularyDataObject
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...
8
{
9
    /**
10
     * Stores a label string if the concept has been found through
11
     * a altLabel/label in a another language than the ui.
12
     */
13
    private $foundby;
14
    /** Type of foundby match: 'alt', 'hidden' or 'lang' */
15
    private $foundbytype;
16
    /** the EasyRdf\Graph object of the concept */
17
    private $graph;
18
    private $clang;
19
20
    /** concept properties that should not be shown to users */
21
    private $DELETED_PROPERTIES = array(
22
        'skosext:broaderGeneric', # these are remnants of bad modeling
23
        'skosext:broaderPartitive', #
24
25
        'skos:hiddenLabel', # because it's supposed to be hidden
26
        'skos:prefLabel', # handled separately by getLabel
27
        'rdfs:label', # handled separately by getLabel
28
29
        'skos:topConceptOf', # because it's too technical, not relevant for users
30
        'skos:inScheme', # should be evident in any case
31
        'skos:member', # this shouldn't be shown on the group page
32
        'dc:created', # handled separately
33
        'dc:modified', # handled separately
34
    );
35
36
    /** related concepts that should be shown to users in the appendix */
37
    private $MAPPING_PROPERTIES = array(
38
        'skos:exactMatch',
39
        'skos:narrowMatch',
40
        'skos:broadMatch',
41
        'skos:closeMatch',
42
        'skos:relatedMatch',
43
        'rdfs:seeAlso',
44
        'owl:sameAs',
45
    );
46
47
    /**
48
     * Initializing the concept object requires the following parameters.
49
     * @param Model $model
50
     * @param Vocabulary $vocab
51
     * @param EasyRdf\Resource $resource
52
     * @param EasyRdf\Graph $graph
53
     */
54
    public function __construct($model, $vocab, $resource, $graph, $clang)
55
    {
56
        parent::__construct($model, $vocab, $resource);
57
        $this->order = array("rdf:type", "dc:isReplacedBy", "skos:definition", "skos:broader", "skos:narrower", "skos:related", "skos:altLabel", "skosmos:memberOf", "skos:note", "skos:scopeNote", "skos:historyNote", "rdfs:comment", "dc11:source", "dc:source", "skos:prefLabel");
58
        $this->graph = $graph;
59
        $this->clang = $clang;
60
        // setting the Punic plugins locale for localized datetime conversions
61
        if ($this->clang && $this->clang !== '') {
62
            Punic\Data::setDefaultLocale($clang);
63
        }
64
65
    }
66
67
    /**
68
     * Returns the concept uri.
69
     * @return string
70
     */
71
    public function getUri()
72
    {
73
        return $this->resource->getUri();
74
    }
75
76
    public function getType()
77
    {
78
        return $this->resource->types();
79
    }
80
81
82
    /**
83
     * Returns a boolean value indicating whether the resource is a group defined in the vocab config as skosmos:groupClass.
84
     * @return boolean
85
     */
86
    public function isGroup() {
87
        $groupClass = $this->getVocab()->getConfig()->getGroupClassURI();
88
        if ($groupClass) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $groupClass of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
89
            $groupClass = EasyRdf\RdfNamespace::shorten($groupClass) !== null ? EasyRdf\RdfNamespace::shorten($groupClass) : $groupClass;
90
            return in_array($groupClass, $this->getType());
91
        }
92
        return false;
93
    }
94
95
    /**
96
     * Returns a boolean value indicating if the concept has been deprecated.
97
     * @return boolean
98
     */
99
    public function getDeprecated()
100
    {
101
        $deprecatedValue = $this->resource->getLiteral('owl:deprecated');
102
        return ($deprecatedValue !== null && filter_var($deprecatedValue->getValue(), FILTER_VALIDATE_BOOLEAN));
103
    }
104
105
    /**
106
     * Returns a label for the concept in the content language or if not possible in any language.
107
     * @return string
108
     */
109
    public function getLabel()
110
    {
111
        $lang = $this->clang;
112
        // 1. label in current language
113
        if ($this->resource->label($lang) !== null) {
114
            return $this->resource->label($lang);
115
        }
116
117
        // 2. label in the vocabulary default language
118 View Code Duplication
        if ($this->resource->label($this->vocab->getConfig()->getDefaultLanguage()) !== null) {
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...
119
            return $this->resource->label($this->vocab->getConfig()->getDefaultLanguage());
120
        }
121
122
        // 3. label in a subtag of the current language
123
        // We need to check all the labels in case one of them matches a subtag of the current language
124
        foreach($this->resource->allLiterals('skos:prefLabel') as $label) {
125
            // the label lang code is a subtag of the UI lang eg. en-GB - create a new literal with the main language
126
            if ($label !== null && strpos($label->getLang(), $lang . '-') === 0) {
127
                return EasyRdf\Literal::create($label, $lang);
128
            }
129
        }
130
131
        // 4. label in any language, including literal with empty language tag
132
        $label = $this->resource->label();
133
        if ($label !== null) {
134
            return $label->getLang() ? $label->getValue() . " (" . $label->getLang() . ")" : $label->getValue();
135
        }
136
137
        // empty
138
        return "";
139
    }
140
141
    public function hasXlLabel($prop = 'prefLabel')
142
    {
143
        if ($this->resource->hasProperty('skosxl:' . $prop)) {
144
            return true;
145
        }
146
        return false;
147
    }
148
149
    public function getXlLabel()
150
    {
151
        $labels = $this->resource->allResources('skosxl:prefLabel');
152
        foreach($labels as $labres) {
153
            $label = $labres->getLiteral('skosxl:literalForm');
154
            if ($label->getLang() == $this->clang) {
155
                return new LabelSkosXL($this->model, $labres);
156
            }
157
        }
158
        return null;
159
    }
160
161
    /**
162
     * Returns a notation for the concept or null if it has not been defined.
163
     * @return string eg. '999'
164
     */
165
    public function getNotation()
166
    {
167
        $notation = $this->resource->get('skos:notation');
168
        if ($this->vocab->getConfig()->showNotation() && $notation !== null) {
169
            return $notation->getValue();
170
        }
171
172
        return null;
173
    }
174
175
    /**
176
     * Returns the Vocabulary object or undefined if that is not available.
177
     * @return Vocabulary
178
     */
179
    public function getVocab()
180
    {
181
        return $this->vocab;
182
    }
183
184
    /**
185
     * Returns the vocabulary shortname string or id if that is not available.
186
     * @return string
187
     */
188
    public function getShortName()
189
    {
190
        return $this->vocab ? $this->vocab->getShortName() : null;
191
    }
192
193
    /**
194
     * Returns the vocabulary shortname string or id if that is not available.
195
     * @return string
196
     */
197
    public function getVocabTitle()
198
    {
199
        return $this->vocab ? $this->vocab->getTitle() : null;
200
    }
201
202
    /**
203
     * Setter for the $clang property.
204
     * @param string $clang language code eg. 'en'
205
     */
206
    public function setContentLang($clang)
207
    {
208
        $this->clang = $clang;
209
    }
210
211
    public function getContentLang()
212
    {
213
        return $this->clang;
214
    }
215
216
    /**
217
     * Setter for the $foundby property.
218
     * @param string $label label that was matched
219
     * @param string $type type of match: 'alt', 'hidden', or 'lang'
220
     */
221
    public function setFoundBy($label, $type)
222
    {
223
        $this->foundby = $label;
224
        $this->foundbytype = $type;
225
    }
226
227
    /**
228
     * Getter for the $foundby property.
229
     * @return string
230
     */
231
    public function getFoundBy()
232
    {
233
        return $this->foundby;
234
    }
235
236
    /**
237
     * Getter for the $foundbytype property.
238
     * @return string
239
     */
240
    public function getFoundByType()
241
    {
242
        return $this->foundbytype;
243
    }
244
245
    public function getMappingProperties()
246
    {
247
        $ret = array();
248
249
        $longUris = $this->resource->propertyUris();
250
        foreach ($longUris as &$prop) {
251 View Code Duplication
            if (EasyRdf\RdfNamespace::shorten($prop) !== null) {
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...
252
                // shortening property labels if possible
253
                $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop);
254
            } else {
255
                $sprop = "<$prop>";
256
            }
257
            // EasyRdf requires full URIs to be in angle brackets
258
259
            if (in_array($prop, $this->MAPPING_PROPERTIES) && !in_array($prop, $this->DELETED_PROPERTIES)) {
260
                $propres = new EasyRdf\Resource($prop, $this->graph);
261
                $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); // current language
262
                $propobj = new ConceptProperty($prop, $proplabel);
263
                if ($propobj->getLabel() !== null) {
264
                    // only display properties for which we have a label
265
                    $ret[$prop] = $propobj;
266
                }
267
268
                // Iterating through every resource and adding these to the data object.
269
                foreach ($this->resource->allResources($sprop) as $val) {
270
                    if (isset($ret[$prop])) {
271
                        // checking if the target vocabulary can be found at the skosmos endpoint
272
                        $exuri = $val->getUri();
273
                        // if multiple vocabularies are found, the following method will return in priority the current vocabulary of the concept
274
                        $exvoc = $this->model->guessVocabularyFromURI($exuri, $this->vocab->getId());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $exvoc is correct as $this->model->guessVocab... $this->vocab->getId()) (which targets Model::guessVocabularyFromURI()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
275
                        // if not querying the uri itself
276
                        if (!$exvoc) {
277
                            $response = null;
278
                            // if told to do so in the vocabulary configuration
279
                            if ($this->vocab->getConfig()->getExternalResourcesLoading()) {
280
                                $response = $this->model->getResourceFromUri($exuri);
281
                            }
282
283
                            if ($response) {
284
                                $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $response, $prop), $this->clang);
285
                                continue;
286
                            }
287
                        }
288
                        $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
289
                    }
290
                }
291
            }
292
        }
293
294
        // sorting the properties to a order preferred in the Skosmos concept page.
295
        $ret = $this->arbitrarySort($ret);
296
297
        return $ret;
298
    }
299
300
    /**
301
     * Iterates over all the properties of the concept and returns those in an array.
302
     * @return array
303
     */
304
    public function getProperties()
305
    {
306
        $properties = array();
307
        $narrowersByUri = array();
308
        $inCollection = array();
309
        $membersArray = array();
310
        $longUris = $this->resource->propertyUris();
311
        $duplicates = array();
312
        $ret = array();
313
314
        // looking for collections and linking those with their narrower concepts
315
        if ($this->vocab->getConfig()->getArrayClassURI() !== null) {
316
            $collections = $this->graph->allOfType($this->vocab->getConfig()->getArrayClassURI());
317
            if (sizeof($collections) > 0) {
318
                // indexing the narrowers once to avoid iterating all of them with every collection
319
                foreach ($this->resource->allResources('skos:narrower') as $narrower) {
320
                    $narrowersByUri[$narrower->getUri()] = $narrower;
321
                }
322
323
                foreach ($collections as $coll) {
324
                    $currCollMembers = $this->getCollectionMembers($coll, $narrowersByUri);
325
                    foreach ($currCollMembers as $collection) {
326
                        if ($collection->getSubMembers()) {
327
                            $submembers = $collection->getSubMembers();
328
                            foreach ($submembers as $member) {
329
                                $inCollection[$member->getUri()] = true;
330
                            }
331
332
                        }
333
                    }
334
335
                    if (isset($collection) && $collection->getSubMembers()) {
336
                        $membersArray = array_merge($currCollMembers, $membersArray);
337
                    }
338
339
                }
340
                $properties['skos:narrower'] = $membersArray;
341
            }
342
        }
343
344
        foreach ($longUris as &$prop) {
345 View Code Duplication
            if (EasyRdf\RdfNamespace::shorten($prop) !== null) {
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...
346
                // shortening property labels if possible
347
                $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop);
348
            } else {
349
                $sprop = "<$prop>";
350
            }
351
            // EasyRdf requires full URIs to be in angle brackets
352
353
            if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) {
354
                $propres = new EasyRdf\Resource($prop, $this->graph);
355
                $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label();
356
                $superprop = $propres->get('rdfs:subPropertyOf') ? $propres->get('rdfs:subPropertyOf')->getURI() : null;
357
                if ($superprop) {
358
                    $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop;
359
                }
360
                $propobj = new ConceptProperty($prop, $proplabel, $superprop);
361
362
                if ($propobj->getLabel() !== null) {
363
                    // only display properties for which we have a label
364
                    $ret[$prop] = $propobj;
365
                }
366
367
                // searching for subproperties of literals too
368
                foreach ($this->graph->allResources($prop, 'rdfs:subPropertyOf') as $subi) {
369
                    $suburi = EasyRdf\RdfNamespace::shorten($subi->getUri()) ? EasyRdf\RdfNamespace::shorten($subi->getUri()) : $subi->getUri();
370
                    $duplicates[$suburi] = $prop;
371
                }
372
373
                // Iterating through every literal and adding these to the data object.
374
                foreach ($this->resource->allLiterals($sprop) as $val) {
375
                    $literal = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $val, $prop);
376
                    // only add literals when they match the content/hit language or have no language defined
377
                    if (isset($ret[$prop]) && ($literal->getLang() === $this->clang || $literal->getLang() === null)) {
378
                        $ret[$prop]->addValue($literal);
379
                    }
380
381
                }
382
383
                // Iterating through every resource and adding these to the data object.
384
                foreach ($this->resource->allResources($sprop) as $val) {
385
                    // skipping narrower concepts which are already shown in a collection
386
                    if ($sprop === 'skos:narrower' && array_key_exists($val->getUri(), $inCollection)) {
387
                        continue;
388
                    }
389
390
                    // hiding rdf:type property if it's just skos:Concept
391
                    if ($sprop === 'rdf:type' && $val->shorten() === 'skos:Concept') {
392
                        continue;
393
                    }
394
395
                    // handled by getMappingProperties()
396
                    if (in_array($sprop, $this->MAPPING_PROPERTIES)) {
397
                        continue;
398
                    }
399
400
                    if (isset($ret[$prop])) {
401
                        // checking if the property value is not in the current vocabulary
402
                        $exvoc = $this->model->guessVocabularyFromURI($val->getUri());
403
                        if ($exvoc && $exvoc->getId() !== $this->vocab->getId()) {
404
                            $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
405
                            continue;
406
                        }
407
                        $ret[$prop]->addValue(new ConceptPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
408
                    }
409
410
                }
411
            }
412
        }
413
        // adding narrowers part of a collection
414
        foreach ($properties as $prop => $values) {
415
            foreach ($values as $value) {
416
                $ret[$prop]->addValue($value, $this->clang);
417
            }
418
        }
419
420
        foreach ($ret as $key => $prop) {
421
            if (sizeof($prop->getValues()) === 0) {
422
                unset($ret[$key]);
423
            }
424
        }
425
426
        $ret = $this->removeDuplicatePropertyValues($ret, $duplicates);
427
        // sorting the properties to the order preferred in the Skosmos concept page.
428
        $ret = $this->arbitrarySort($ret);
429
        return $ret;
430
    }
431
432
    /**
433
     * Removes properties that have duplicate values.
434
     * @param $ret the array of properties generated by getProperties
435
     * @param $duplicates array of properties found are a subProperty of a another property
436
     * @return array of ConceptProperties
437
     */
438
    public function removeDuplicatePropertyValues($ret, $duplicates)
439
    {
440
        $propertyValues = array();
441
442
        foreach ($ret as $prop) {
443
            foreach ($prop->getValues() as $value) {
444
                $label = $value->getLabel();
445
                $propertyValues[(method_exists($label, 'getValue')) ? $label->getValue() : $label][] = $value->getType();
446
            }
447
        }
448
449
        foreach ($propertyValues as $value => $propnames) {
450
            // if there are multiple properties with the same string value.
451
            if (count($propnames) > 1) {
452
                foreach ($propnames as $property) {
453
                    // if there is a more accurate property delete the more generic one.
454
                    if (isset($duplicates[$property])) {
455
                        unset($ret[$property]);
456
                    }
457
                }
458
459
            }
460
        }
461
        return $ret;
462
    }
463
464
    /**
465
     * Gets the creation date and modification date if available.
466
     * @return String containing the date information in a human readable format.
467
     */
468
    public function getDate()
469
    {
470
        $ret = '';
471
        $created = '';
472
        $modified = '';
473
        try {
474
            // finding the created properties
475
            if ($this->resource->get('dc:created')) {
476
                $created = $this->resource->get('dc:created')->getValue();
477
            }
478
479
            // finding the modified properties
480
            if ($this->resource->get('dc:modified')) {
481
                $modified = $this->resource->get('dc:modified')->getValue();
482
            }
483
484
            // making a human readable string from the timestamps
485
            if ($created != '') {
486
                $ret = gettext('skosmos:created') . ' ' . (Punic\Calendar::formatDate($created, 'short'));
487
            }
488
489
            if ($modified != '') {
490
                if ($created != '') {
491
                    $ret .= ', ' . gettext('skosmos:modified') . ' ' . (Punic\Calendar::formatDate($modified, 'short'));
492
                } else {
493
                    $ret .= ' ' . ucfirst(gettext('skosmos:modified')) . ' ' . (Punic\Calendar::formatDate($modified, 'short'));
494
                }
495
496
            }
497
        } catch (Exception $e) {
498
            trigger_error($e->getMessage(), E_USER_WARNING);
499
            $ret = '';
500
            if ($this->resource->get('dc:modified')) {
501
                $modified = (string) $this->resource->get('dc:modified');
502
                $ret = gettext('skosmos:modified') . ' ' . $modified; 
503
            }
504
            if ($this->resource->get('dc:created')) {
505
                $created .= (string) $this->resource->get('dc:created');
506
                $ret .= ' ' . gettext('skosmos:created') . ' ' . $created; 
507
            }
508
        }
509
        return $ret;
510
    }
511
512
    /**
513
     * Gets the members of a specific collection.
514
     * @param $coll
515
     * @param array containing all narrowers as EasyRdf\Resource
516
     * @return array containing ConceptPropertyValue objects
517
     */
518
    private function getCollectionMembers($coll, $narrowers)
519
    {
520
        $membersArray = array();
521
        $collLabel = $coll->label()->getValue($this->clang) ? $coll->label($this->clang) : $coll->label();
522
        if ($collLabel) {
523
            $collLabel = $collLabel->getValue();
524
        }
525
526
        $membersArray[$collLabel] = new ConceptPropertyValue($this->model, $this->vocab, $coll, 'skos:narrower', $this->clang);
527
        foreach ($coll->allResources('skos:member') as $member) {
528
            if (array_key_exists($member->getUri(), $narrowers)) {
529
                $narrower = $narrowers[$member->getUri()];
530
                if (isset($narrower)) {
531
                    $membersArray[$collLabel]->addSubMember(new ConceptPropertyValue($this->model, $this->vocab, $narrower, 'skos:member', $this->clang), $this->clang);
532
                }
533
534
            }
535
        }
536
537
        return $membersArray;
538
    }
539
540
    /**
541
     * Gets the groups the concept belongs to.
542
     */
543
    public function getGroupProperties()
544
    {
545
        return $this->getReverseResources(false);
546
    }
547
548
    /**
549
     * Gets the groups/arrays the concept belongs to.
550
     */
551
    public function getReverseResources($includeArrays) {
552
        $groups = array();
553
        $reverseResources = $this->graph->resourcesMatching('skos:member', $this->resource);
554
        if (isset($reverseResources)) {
555
            $arrayClassURI = $this->vocab !== null ? $this->vocab->getConfig()->getArrayClassURI() : null;
556
            $arrayClass = $arrayClassURI !== null ? EasyRdf\RdfNamespace::shorten($arrayClassURI) : null;
557
            $superGroups = $this->resource->all('isothes:superGroup');
558
            $superGroupUris = array_map(function($obj) { return $obj->getUri(); }, $superGroups);
559
            foreach ($reverseResources as $reverseResource) {
560
                if (in_array($arrayClass, $reverseResource->types()) === $includeArrays) {
0 ignored issues
show
Bug introduced by
The method types cannot be called on $reverseResource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
561
                    // not adding the memberOf if the reverse resource is already covered by isothes:superGroup see issue #433
562
                    if (in_array($reverseResource->getUri(), $superGroupUris)) {
0 ignored issues
show
Bug introduced by
The method getUri cannot be called on $reverseResource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
563
                        continue;
564
                    }
565
                    $property = in_array($arrayClass, $reverseResource->types()) ? "skosmos:memberOfArray" : "skosmos:memberOf";
0 ignored issues
show
Bug introduced by
The method types cannot be called on $reverseResource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
566
                    $collLabel = $reverseResource->label($this->clang) ? $reverseResource->label($this->clang) : $reverseResource->label();
0 ignored issues
show
Bug introduced by
The method label cannot be called on $reverseResource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
567
                    if ($collLabel) {
568
                        $collLabel = $collLabel->getValue();
569
                    }
570
571
                    $groups[$collLabel] = new ConceptPropertyValue($this->model, $this->vocab, $reverseResource, $property, $this->clang);
572
                    ksort($groups);
573
                    $super = $this->graph->resourcesMatching('skos:member', $reverseResource);
574
                    while (isset($super) && !empty($super)) {
575
                        foreach ($super as $res) {
576
                            $superprop = new ConceptPropertyValue($this->model, $this->vocab, $res, 'skosmos:memberOfSuper', $this->clang);
577
                            array_unshift($groups, $superprop);
578
                            $super = $this->graph->resourcesMatching('skos:member', $res);
579
                        }
580
                    }
581
                }
582
            }
583
        }
584
        return $groups;
585
    }
586
587
    public function getArrayProperties() {
588
        return $this->getReverseResources(true);
589
    }
590
591
    /**
592
     * Reads the literal language code and gets a name for it from Punic or alternatively
593
     * tries to search for a gettext translation.
594
     * @param EasyRdf\Literal $lit
595
     * @return string e.g. 'English'
596
     */
597
    private function literalLanguageToString($lit) {
598
        // using empty string as the language literal when there is no langcode set
599
        $langName = '';
600
        if ($lit->getLang() !== null) {
601
            $langName = Punic\Language::getName($lit->getLang(), $this->getEnvLang()) !== $lit->getLang() ? Punic\Language::getName($lit->getLang(), $this->getEnvLang()) : gettext($lit->getLang());
602
        }
603
        return $langName;
604
    }
605
606
    /**
607
     * Gets the values for the property in question in all other languages than the ui language.
608
     */
609
    public function getForeignLabels()
610
    {
611
        $prefLabels = $this->resource->allLiterals('skos:prefLabel');
612
        $labels = array_merge($prefLabels, $this->resource->allLiterals('skos:altLabel'));
613
        $ret = array();
614
        foreach ($labels as $lit) {
615
            // filtering away subsets of the current language eg. en vs en-GB
616
            if ($lit->getLang() != $this->clang && strpos($lit->getLang(), $this->getEnvLang() . '-') !== 0) {
617
                $prop = in_array($lit, $prefLabels) ? 'skos:prefLabel' : 'skos:altLabel';
618
                $ret[$this->literalLanguageToString($lit)][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $prop);
619
            }
620
        }
621
        ksort($ret);
622
        return $ret;
623
    }
624
625
    /**
626
     * Gets the values for the property in question in all other languages than the ui language.
627
     * @param string $property
628
     */
629
    public function getAllLabels($property)
630
    {
631
        $labels = array();
632
        // shortening property labels if possible, EasyRdf requires full URIs to be in angle brackets
633
        $property = (EasyRdf\RdfNamespace::shorten($property) !== null) ? EasyRdf\RdfNamespace::shorten($property) : "<$property>";
634
        foreach ($this->resource->allLiterals($property) as $lit) {
635
            $labels[Punic\Language::getName($lit->getLang(), $this->getEnvLang())][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $property);
636
        }
637
        ksort($labels);
638
        return $labels;
639
    }
640
}
641