Completed
Push — master ( 7e8bbb...92890e )
by Osma
08:55
created

Concept::getReverseResources()   C

Complexity

Conditions 13
Paths 5

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 5
nop 1
dl 0
loc 35
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Dataobject for a single concept.
5
 */
6
7
class Concept extends VocabularyDataObject
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
    /** default external properties we are interested in saving/displaying from mapped external objects */
48
    private $DEFAULT_EXT_PROPERTIES = array(
49
        "dc11:title",
50
        "dcterms:title",
51
        "skos:prefLabel",
52
        "skos:exactMatch",
53
        "skos:closeMatch",
54
        "skos:inScheme",
55
        "rdfs:label",
56
        "rdfs:isDefinedBy",
57
        "owl:sameAs",
58
        "rdf:type",
59
        "void:inDataset",
60
        "void:sparqlEndpoint",
61
        "void:uriLookupEndpoint",
62
        "schema:about",
63
        "schema:description",
64
        "schema:inLanguage",
65
        "schema:name",
66
        "schema:isPartOf",
67
        "wdt:P31",
68
        "wdt:P625"
69
    );
70
71
    /**
72
     * Initializing the concept object requires the following parameters.
73
     * @param Model $model
74
     * @param Vocabulary $vocab
75
     * @param EasyRdf\Resource $resource
76
     * @param EasyRdf\Graph $graph
77
     */
78
    public function __construct($model, $vocab, $resource, $graph, $clang)
79
    {
80
        parent::__construct($model, $vocab, $resource);
81
        $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");
82
        $this->graph = $graph;
83
        $this->clang = $clang;
84
        // setting the Punic plugins locale for localized datetime conversions
85
        if ($this->clang && $this->clang !== '') {
86
            Punic\Data::setDefaultLocale($clang);
87
        }
88
89
    }
90
91
    /**
92
     * Returns the concept uri.
93
     * @return string
94
     */
95
    public function getUri()
96
    {
97
        return $this->resource->getUri();
98
    }
99
100
    public function getType()
101
    {
102
        return $this->resource->types();
103
    }
104
105
106
    /**
107
     * Returns a boolean value indicating whether the resource is a group defined in the vocab config as skosmos:groupClass.
108
     * @return boolean
109
     */
110
    public function isGroup() {
111
        $groupClass = $this->getVocab()->getConfig()->getGroupClassURI();
112
        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...
113
            $groupClass = EasyRdf\RdfNamespace::shorten($groupClass) !== null ? EasyRdf\RdfNamespace::shorten($groupClass) : $groupClass;
114
            return in_array($groupClass, $this->getType());
115
        }
116
        return false;
117
    }
118
119
    /**
120
     * Returns a boolean value indicating if the concept has been deprecated.
121
     * @return boolean
122
     */
123
    public function getDeprecated()
124
    {
125
        $deprecatedValue = $this->resource->getLiteral('owl:deprecated');
126
        return ($deprecatedValue !== null && filter_var($deprecatedValue->getValue(), FILTER_VALIDATE_BOOLEAN));
127
    }
128
129
    /**
130
     * Returns a label for the concept in the content language or if not possible in any language.
131
     * @return string
132
     */
133
    public function getLabel()
134
    {
135 View Code Duplication
        foreach ($this->vocab->getConfig()->getLanguageOrder($this->clang) as $fallback) {
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...
136
            if ($this->resource->label($fallback) !== null) {
137
                return $this->resource->label($fallback);
138
            }
139
            // We need to check all the labels in case one of them matches a subtag of the current language
140
            foreach($this->resource->allLiterals('skos:prefLabel') as $label) {
141
                // the label lang code is a subtag of the UI lang eg. en-GB - create a new literal with the main language
142
                if ($label !== null && strpos($label->getLang(), $fallback . '-') === 0) {
143
                    return EasyRdf\Literal::create($label, $fallback);
144
                }
145
            }
146
        }
147
148
        // Last resort: label in any language, including literal with empty language tag
149
        $label = $this->resource->label();
150
        if ($label !== null) {
151
            if (!$label->getLang()) {
152
                return $label->getValue();
153
            }
154
            return EasyRdf\Literal::create($label->getValue(), $label->getLang());
155
        }
156
157
        // empty
158
        return "";
159
    }
160
161
    public function hasXlLabel($prop = 'prefLabel')
162
    {
163
        if ($this->resource->hasProperty('skosxl:' . $prop)) {
164
            return true;
165
        }
166
        return false;
167
    }
168
169
    public function getXlLabel()
170
    {
171
        $labels = $this->resource->allResources('skosxl:prefLabel');
172
        foreach($labels as $labres) {
173
            $label = $labres->getLiteral('skosxl:literalForm');
174
            if ($label !== null && $label->getLang() == $this->clang) {
175
                return new LabelSkosXL($this->model, $labres);
176
            }
177
        }
178
        return null;
179
    }
180
181
    /**
182
     * Returns a notation for the concept or null if it has not been defined.
183
     * @return string eg. '999'
184
     */
185
    public function getNotation()
186
    {
187
        $notation = $this->resource->get('skos:notation');
188
        if ($this->vocab->getConfig()->showNotation() && $notation !== null) {
189
            return $notation->getValue();
190
        }
191
192
        return null;
193
    }
194
195
    /**
196
     * Returns the Vocabulary object or undefined if that is not available.
197
     * @return Vocabulary
198
     */
199
    public function getVocab()
200
    {
201
        return $this->vocab;
202
    }
203
204
    /**
205
     * Returns the vocabulary shortname string or id if that is not available.
206
     * @return string
207
     */
208
    public function getShortName()
209
    {
210
        return $this->vocab ? $this->vocab->getShortName() : null;
211
    }
212
213
    /**
214
     * Returns the vocabulary shortname string or id if that is not available.
215
     * @return string
216
     */
217
    public function getVocabTitle()
218
    {
219
        return $this->vocab ? $this->vocab->getTitle() : null;
220
    }
221
222
    /**
223
     * Setter for the $clang property.
224
     * @param string $clang language code eg. 'en'
225
     */
226
    public function setContentLang($clang)
227
    {
228
        $this->clang = $clang;
229
    }
230
231
    public function getContentLang()
232
    {
233
        return $this->clang;
234
    }
235
236
    /**
237
     * Setter for the $foundby property.
238
     * @param string $label label that was matched
239
     * @param string $type type of match: 'alt', 'hidden', or 'lang'
240
     */
241
    public function setFoundBy($label, $type)
242
    {
243
        $this->foundby = $label;
244
        $this->foundbytype = $type;
245
    }
246
247
    /**
248
     * Getter for the $foundby property.
249
     * @return string
250
     */
251
    public function getFoundBy()
252
    {
253
        return $this->foundby;
254
    }
255
256
    /**
257
     * Getter for the $foundbytype property.
258
     * @return string
259
     */
260
    public function getFoundByType()
261
    {
262
        return $this->foundbytype;
263
    }
264
265
    /**
266
     * Processes a single external resource i.e., adds the properties from
267
     * 1) $this->$DEFAULT_EXT_PROPERTIES
268
     * 2) VocabConfig external properties
269
     * 3) Possible plugin defined external properties
270
     * to $this->graph
271
     * @param EasyRdf\Resource $res
272
     */
273
    public function processExternalResource($res)
274
    {
275
        $exGraph = $res->getGraph();
276
        // catch external subjects that have $res as object
277
        $extSubjects = $exGraph->resourcesMatching("schema:about", $res);
278
279
        $propList =  array_unique(array_merge(
280
            $this->DEFAULT_EXT_PROPERTIES,
281
            $this->getVocab()->getConfig()->getExtProperties(),
282
            $this->getVocab()->getConfig()->getPlugins()->getExtProperties()
283
        ));
284
285
        $seen = array();
286
        $this->addExternalTriplesToGraph($res, $seen, $propList);
287
        foreach ($extSubjects as $extSubject) {
288
            if ($extSubject->isBNode() && array_key_exists($extSubject->getUri(), $seen)) {
0 ignored issues
show
Bug introduced by
The method isBNode cannot be called on $extSubject (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...
Bug introduced by
The method getUri cannot be called on $extSubject (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...
289
                // already processed, skip
290
                continue;
291
            }
292
            $seen[$extSubject->getUri()] = 1;
0 ignored issues
show
Bug introduced by
The method getUri cannot be called on $extSubject (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...
293
            $this->addExternalTriplesToGraph($extSubject, $seen, $propList);
0 ignored issues
show
Documentation introduced by
$extSubject is of type resource, but the function expects a object<EasyRdf\Resource>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
294
        }
295
296
    }
297
298
    /**
299
     * Adds resource properties to $this->graph
300
     * @param EasyRdf\Resource $res
301
     * @param string[] $seen Processed resources so far
302
     * @param string[] $props (optional) limit to these property URIs
303
     */
304
    private function addExternalTriplesToGraph($res, &$seen, $props=null)
305
    {
306
        if (array_key_exists($res->getUri(), $seen) && $seen[$res->getUri()] === 0) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $seen[$res->getUri()] (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
307
            return;
308
        }
309
        $seen[$res->getUri()] = 0;
310
311
        if ($res->isBNode() || is_null($props)) {
312
            foreach ($res->propertyUris() as $prop) {
313
                $this->addPropertyValues($res, $prop, $seen);
314
            }
315
        }
316
        else {
317
            foreach ($props as $prop) {
318
                if ($res->hasProperty($prop)) {
319
                    $this->addPropertyValues($res, $prop, $seen);
320
                }
321
            }
322
        }
323
    }
324
325
    /**
326
     * Adds values of a single single property of a resource to $this->graph
327
     * implements Concise Bounded Description definition
328
     * @param EasyRdf\Resource $res
329
     * @param string $prop
330
     * @param string[] $seen Processed resources so far
331
     */
332
    private function addPropertyValues($res, $prop, &$seen)
333
    {
334
        $resList = $res->allResources('<' . $prop . '>');
335
336
        foreach ($resList as $res2) {
337
            if ($res2->isBNode()) {
338
                $this->addExternalTriplesToGraph($res2, $seen);
339
            }
340
            $this->graph->addResource($res, $prop, $res2);
341
            $this->addResourceReifications($res, $prop, $res2, $seen);
342
        }
343
344
        $litList = $res->allLiterals('<' . $prop . '>');
345
346
        foreach ($litList as $lit) {
347
            $this->graph->addLiteral($res, $prop, $lit);
348
            $this->addLiteralReifications($res, $prop, $lit, $seen);
349
        }
350
    }
351
352
    /**
353
     * Adds reifications of a triple having a literal object to $this->graph
354
     * @param EasyRdf\Resource $sub
355
     * @param string $pred
356
     * @param EasyRdf\Literal $obj
357
     * @param string[] $seen Processed resources so far
358
     */
359
    private function addLiteralReifications($sub, $pred, $obj, &$seen)
360
    {
361
        $pos_reifs = $sub->getGraph()->resourcesMatching("rdf:subject", $sub);
362
        foreach ($pos_reifs as $pos_reif) {
363
            $lit = $pos_reif->getLiteral("rdf:object", $obj->getLang());
0 ignored issues
show
Bug introduced by
The method getLiteral cannot be called on $pos_reif (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...
364
365 View Code Duplication
            if (!is_null($lit) && $lit->getValue() === $obj->getValue() &&
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...
366
                $pos_reif->isA("rdf:Statement") &&
0 ignored issues
show
Bug introduced by
The method isA cannot be called on $pos_reif (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...
367
                $pos_reif->hasProperty("rdf:predicate", new EasyRdf\Resource($pred, $sub->getGraph())))
0 ignored issues
show
Bug introduced by
The method hasProperty cannot be called on $pos_reif (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...
368
            {
369
                $this->addExternalTriplesToGraph($pos_reif, $seen);
0 ignored issues
show
Documentation introduced by
$pos_reif is of type resource, but the function expects a object<EasyRdf\Resource>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
370
            }
371
        }
372
    }
373
374
    /**
375
     * Adds reifications of a triple having a resource object to $this->graph
376
     * @param EasyRdf\Resource $sub
377
     * @param string $pred
378
     * @param EasyRdf\Resource $obj
379
     * @param string[] $seen Processed resources so far
380
     */
381
    private function addResourceReifications($sub, $pred, $obj, &$seen)
382
    {
383
        $pos_reifs = $sub->getGraph()->resourcesMatching("rdf:subject", $sub);
384
        foreach ($pos_reifs as $pos_reif) {
385 View Code Duplication
            if ($pos_reif->isA("rdf:Statement") &&
0 ignored issues
show
Bug introduced by
The method isA cannot be called on $pos_reif (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...
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...
386
                $pos_reif->hasProperty("rdf:object", $obj) &&
0 ignored issues
show
Bug introduced by
The method hasProperty cannot be called on $pos_reif (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...
387
                $pos_reif->hasProperty("rdf:predicate", new EasyRdf\Resource($pred, $sub->getGraph())))
0 ignored issues
show
Bug introduced by
The method hasProperty cannot be called on $pos_reif (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...
388
            {
389
                $this->addExternalTriplesToGraph($pos_reif, $seen);
0 ignored issues
show
Documentation introduced by
$pos_reif is of type resource, but the function expects a object<EasyRdf\Resource>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
390
            }
391
        }
392
    }
393
394
    public function getMappingProperties()
395
    {
396
        $ret = array();
397
398
        $longUris = $this->resource->propertyUris();
399
        foreach ($longUris as &$prop) {
400 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...
401
                // shortening property labels if possible
402
                $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop);
403
            } else {
404
                $sprop = "<$prop>";
405
            }
406
            // EasyRdf requires full URIs to be in angle brackets
407
408
            if (in_array($prop, $this->MAPPING_PROPERTIES) && !in_array($prop, $this->DELETED_PROPERTIES)) {
409
                $propres = new EasyRdf\Resource($prop, $this->graph);
410
                $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); // current language
411
                $propobj = new ConceptProperty($prop, $proplabel);
412
                if ($propobj->getLabel() !== null) {
413
                    // only display properties for which we have a label
414
                    $ret[$prop] = $propobj;
415
                }
416
417
                // Iterating through every resource and adding these to the data object.
418
                foreach ($this->resource->allResources($sprop) as $val) {
419
                    if (isset($ret[$prop])) {
420
                        // checking if the target vocabulary can be found at the skosmos endpoint
421
                        $exuri = $val->getUri();
422
                        // if multiple vocabularies are found, the following method will return in priority the current vocabulary of the concept
423
                        $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...
424
                        // if not querying the uri itself
425
                        if (!$exvoc) {
426
                            $response = null;
427
                            // if told to do so in the vocabulary configuration
428
                            if ($this->vocab->getConfig()->getExternalResourcesLoading()) {
429
                                $response = $this->model->getResourceFromUri($exuri);
430
                            }
431
432 View Code Duplication
                            if ($response) {
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...
433
                                $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $response, $prop), $this->clang);
434
435
                                $this->processExternalResource($response);
436
437
                                continue;
438
                            }
439
                        }
440
                        $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
441
                    }
442
                }
443
            }
444
        }
445
446
        // sorting the properties to a order preferred in the Skosmos concept page.
447
        $ret = $this->arbitrarySort($ret);
448
449
        return $ret;
450
    }
451
452
    /**
453
     * Iterates over all the properties of the concept and returns those in an array.
454
     * @return array
455
     */
456
    public function getProperties()
457
    {
458
        $properties = array();
459
        $narrowersByUri = array();
460
        $inCollection = array();
461
        $membersArray = array();
462
        $longUris = $this->resource->propertyUris();
463
        $duplicates = array();
464
        $ret = array();
465
466
        // looking for collections and linking those with their narrower concepts
467
        if ($this->vocab->getConfig()->getArrayClassURI() !== null) {
468
            $collections = $this->graph->allOfType($this->vocab->getConfig()->getArrayClassURI());
469
            if (sizeof($collections) > 0) {
470
                // indexing the narrowers once to avoid iterating all of them with every collection
471
                foreach ($this->resource->allResources('skos:narrower') as $narrower) {
472
                    $narrowersByUri[$narrower->getUri()] = $narrower;
473
                }
474
475
                foreach ($collections as $coll) {
476
                    $currCollMembers = $this->getCollectionMembers($coll, $narrowersByUri);
477
                    foreach ($currCollMembers as $collection) {
478
                        if ($collection->getSubMembers()) {
479
                            $submembers = $collection->getSubMembers();
480
                            foreach ($submembers as $member) {
481
                                $inCollection[$member->getUri()] = true;
482
                            }
483
484
                        }
485
                    }
486
487
                    if (isset($collection) && $collection->getSubMembers()) {
488
                        $membersArray = array_merge($currCollMembers, $membersArray);
489
                    }
490
491
                }
492
                $properties['skos:narrower'] = $membersArray;
493
            }
494
        }
495
496
        foreach ($longUris as &$prop) {
497
            // storing full URI without brackets in a separate variable
498
            $longUri = $prop;
499 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...
500
                // shortening property labels if possible
501
                $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop);
502
            } else {
503
                $sprop = "<$prop>";
504
            }
505
            // EasyRdf requires full URIs to be in angle brackets
506
507
            if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) {
508
                // retrieve property label and super properties from the current vocabulary first
509
                $propres = new EasyRdf\Resource($prop, $this->graph);
510
                $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label();
511
512
                // if not found in current vocabulary, look up in the default graph to be able
513
                // to read an ontology loaded in a separate graph
514
                // note that this imply that the property has an rdf:type declared for the query to work
515
                if(!$proplabel) {
516
                    $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang());
517
                    
518
                    $defaultPropLabel = $this->model->getDefaultSparql()->queryLabel($longUri, '');
519
520
					if($envLangLabels) {
521
						$proplabel = $envLangLabels[$this->getEnvLang()];
522
                    } else {
523
						if($defaultPropLabel) {
524
							$proplabel = $defaultPropLabel[''];
525
						}
526
					}
527
                }
528
529
                // look for superproperties in the current graph
530
                $superprops = array();
531
                foreach ($this->graph->allResources($prop, 'rdfs:subPropertyOf') as $subi) {
532
                    $superprops[] = $subi->getUri();
533
                }
534
535
                // also look up superprops in the default graph if not found in current vocabulary
536
                if(!$superprops || empty($superprops)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $superprops of type array 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...
537
                    $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri);
538
                }
539
540
                // we're reading only one super property, even if there are multiple ones
541
                $superprop = ($superprops)?$superprops[0]:null;
542
                if ($superprop) {
543
                    $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop;
544
                }
545
                $sort_by_notation = $this->vocab->getConfig()->sortByNotation();
546
                $propobj = new ConceptProperty($prop, $proplabel, $superprop, $sort_by_notation);
547
548
                if ($propobj->getLabel() !== null) {
549
                    // only display properties for which we have a label
550
                    $ret[$prop] = $propobj;
551
                }
552
553
                // searching for subproperties of literals too
554
                if($superprops) {
555
                    foreach ($superprops as $subi) {
556
                        $suburi = EasyRdf\RdfNamespace::shorten($subi) ? EasyRdf\RdfNamespace::shorten($subi) : $subi;
557
                        $duplicates[$suburi] = $prop;
558
                    }
559
                }
560
561
                // Iterating through every literal and adding these to the data object.
562
                foreach ($this->resource->allLiterals($sprop) as $val) {
563
                    $literal = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $val, $prop);
564
                    // only add literals when they match the content/hit language or have no language defined
565
                    if (isset($ret[$prop]) && ($literal->getLang() === $this->clang || $literal->getLang() === null)) {
566
                        $ret[$prop]->addValue($literal);
567
                    }
568
569
                }
570
571
                // Iterating through every resource and adding these to the data object.
572
                foreach ($this->resource->allResources($sprop) as $val) {
573
                    // skipping narrower concepts which are already shown in a collection
574
                    if ($sprop === 'skos:narrower' && array_key_exists($val->getUri(), $inCollection)) {
575
                        continue;
576
                    }
577
578
                    // hiding rdf:type property if it's just skos:Concept
579
                    if ($sprop === 'rdf:type' && $val->shorten() === 'skos:Concept') {
580
                        continue;
581
                    }
582
583
                    // handled by getMappingProperties()
584
                    if (in_array($sprop, $this->MAPPING_PROPERTIES)) {
585
                        continue;
586
                    }
587
588
                    if (isset($ret[$prop])) {
589
                        // checking if the property value is not in the current vocabulary
590
                        $exvoc = $this->model->guessVocabularyFromURI($val->getUri());
591 View Code Duplication
                        if ($exvoc && $exvoc->getId() !== $this->vocab->getId()) {
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...
592
                            $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
593
                            continue;
594
                        }
595
                        $ret[$prop]->addValue(new ConceptPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang);
596
                    }
597
598
                }
599
            }
600
        }
601
        // adding narrowers part of a collection
602
        foreach ($properties as $prop => $values) {
603
            foreach ($values as $value) {
604
                $ret[$prop]->addValue($value, $this->clang);
605
            }
606
        }
607
608
        foreach ($ret as $key => $prop) {
609
            if (sizeof($prop->getValues()) === 0) {
610
                unset($ret[$key]);
611
            }
612
        }
613
614
        $ret = $this->removeDuplicatePropertyValues($ret, $duplicates);
615
        // sorting the properties to the order preferred in the Skosmos concept page.
616
        $ret = $this->arbitrarySort($ret);
617
        return $ret;
618
    }
619
620
    /**
621
     * Removes properties that have duplicate values.
622
     * @param $ret the array of properties generated by getProperties
623
     * @param $duplicates array of properties found are a subProperty of a another property
624
     * @return array of ConceptProperties
625
     */
626
    public function removeDuplicatePropertyValues($ret, $duplicates)
627
    {
628
        $propertyValues = array();
629
630
        foreach ($ret as $prop) {
631
            foreach ($prop->getValues() as $value) {
632
                $label = $value->getLabel();
633
                $propertyValues[(method_exists($label, 'getValue')) ? $label->getValue() : $label][] = $value->getType();
634
            }
635
        }
636
637
        foreach ($propertyValues as $value => $propnames) {
638
            // if there are multiple properties with the same string value.
639
            if (count($propnames) > 1) {
640
                foreach ($propnames as $property) {
641
                    // if there is a more accurate property delete the more generic one.
642
                    if (isset($duplicates[$property])) {
643
                        unset($ret[$property]);
644
                    }
645
                }
646
647
            }
648
        }
649
        return $ret;
650
    }
651
652
    /**
653
     * Gets the creation date and modification date if available.
654
     * @return String containing the date information in a human readable format.
655
     */
656
    public function getDate()
657
    {
658
        $ret = '';
659
        $created = '';
660
        $modified = '';
661
        try {
662
            // finding the created properties
663
            if ($this->resource->get('dc:created')) {
664
                $created = $this->resource->get('dc:created')->getValue();
665
            }
666
667
            // finding the modified properties
668
            if ($this->resource->get('dc:modified')) {
669
                $modified = $this->resource->get('dc:modified')->getValue();
670
            }
671
672
            // making a human readable string from the timestamps
673
            if ($created != '') {
674
                $ret = gettext('skosmos:created') . ' ' . (Punic\Calendar::formatDate($created, 'short'));
675
            }
676
677
            if ($modified != '') {
678
                if ($created != '') {
679
                    $ret .= ', ' . gettext('skosmos:modified') . ' ' . (Punic\Calendar::formatDate($modified, 'short'));
680
                } else {
681
                    $ret .= ' ' . ucfirst(gettext('skosmos:modified')) . ' ' . (Punic\Calendar::formatDate($modified, 'short'));
682
                }
683
684
            }
685
        } catch (Exception $e) {
686
            trigger_error($e->getMessage(), E_USER_WARNING);
687
            $ret = '';
688
            if ($this->resource->get('dc:modified')) {
689
                $modified = (string) $this->resource->get('dc:modified');
690
                $ret = gettext('skosmos:modified') . ' ' . $modified;
691
            }
692
            if ($this->resource->get('dc:created')) {
693
                $created .= (string) $this->resource->get('dc:created');
694
                $ret .= ' ' . gettext('skosmos:created') . ' ' . $created;
695
            }
696
        }
697
        return $ret;
698
    }
699
700
    /**
701
     * Gets the members of a specific collection.
702
     * @param $coll
703
     * @param array containing all narrowers as EasyRdf\Resource
704
     * @return array containing ConceptPropertyValue objects
705
     */
706
    private function getCollectionMembers($coll, $narrowers)
707
    {
708
        $membersArray = array();
709
        if ($coll->label()) {
710
            $collLabel = $coll->label()->getValue($this->clang) ? $coll->label($this->clang) : $coll->label();
711
            if ($collLabel) {
712
                $collLabel = $collLabel->getValue();
713
            }
714
        } else {
715
            $collLabel = $coll->getUri();
716
        }
717
        $membersArray[$collLabel] = new ConceptPropertyValue($this->model, $this->vocab, $coll, 'skos:narrower', $this->clang);
718
        foreach ($coll->allResources('skos:member') as $member) {
719
            if (array_key_exists($member->getUri(), $narrowers)) {
720
                $narrower = $narrowers[$member->getUri()];
721
                if (isset($narrower)) {
722
                    $membersArray[$collLabel]->addSubMember(new ConceptPropertyValue($this->model, $this->vocab, $narrower, 'skos:member', $this->clang), $this->clang);
723
                }
724
725
            }
726
        }
727
728
        return $membersArray;
729
    }
730
731
    /**
732
     * Gets the groups the concept belongs to.
733
     */
734
    public function getGroupProperties()
735
    {
736
        return $this->getCollections(false);
737
    }
738
739
    /**
740
     * Gets the groups/arrays the concept belongs to.
741
     */
742
    private function getCollections($includeArrays) {
743
        $groups = array();
744
        $collections = $this->graph->resourcesMatching('skos:member', $this->resource);
745
        if (isset($collections)) {
746
            $arrayClassURI = $this->vocab !== null ? $this->vocab->getConfig()->getArrayClassURI() : null;
747
            $arrayClass = $arrayClassURI !== null ? EasyRdf\RdfNamespace::shorten($arrayClassURI) : null;
748
            $superGroups = $this->resource->all('isothes:superGroup');
749
            $superGroupUris = array_map(function($obj) { return $obj->getUri(); }, $superGroups);
750
            foreach ($collections as $collection) {
751
                if (in_array($arrayClass, $collection->types()) === $includeArrays) {
0 ignored issues
show
Bug introduced by
The method types cannot be called on $collection (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...
752
                    // not adding the memberOf if the reverse resource is already covered by isothes:superGroup see issue #433
753
                    if (in_array($collection->getUri(), $superGroupUris)) {
0 ignored issues
show
Bug introduced by
The method getUri cannot be called on $collection (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...
754
                        continue;
755
                    }
756
                    $property = in_array($arrayClass, $collection->types()) ? "skosmos:memberOfArray" : "skosmos:memberOf";
0 ignored issues
show
Bug introduced by
The method types cannot be called on $collection (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...
757
                    $collLabel = $collection->label($this->clang) ? $collection->label($this->clang) : $collection->label();
0 ignored issues
show
Bug introduced by
The method label cannot be called on $collection (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...
758
                    if ($collLabel) {
759
                        $collLabel = $collLabel->getValue();
760
                    }
761
762
                    $group = new ConceptPropertyValue($this->model, $this->vocab, $collection, $property, $this->clang);
763
                    $groups[$collLabel] = array($group);
764
765
                    $res = $collection;
766
                    while($super = $this->graph->resourcesMatching('skos:member', $res)) {
767 View Code Duplication
                        foreach ($super as $res) {
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...
768
                            $superprop = new ConceptPropertyValue($this->model, $this->vocab, $res, 'skosmos:memberOfSuper', $this->clang);
769
                            array_unshift($groups[$collLabel], $superprop);
770
                        }
771
                    }
772
                }
773
            }
774
        }
775
        uksort($groups, 'strcoll');
776
        return $groups;
777
    }
778
779
    public function getArrayProperties() {
780
        return $this->getCollections(true);
781
    }
782
783
    /**
784
     * Reads the literal language code and gets a name for it from Punic or alternatively
785
     * tries to search for a gettext translation.
786
     * @param EasyRdf\Literal $lit
787
     * @return string e.g. 'English'
788
     */
789
    private function literalLanguageToString($lit) {
790
        // using empty string as the language literal when there is no langcode set
791
        $langName = '';
792
        if ($lit->getLang() !== null) {
793
            $langName = Punic\Language::getName($lit->getLang(), $this->getEnvLang()) !== $lit->getLang() ? Punic\Language::getName($lit->getLang(), $this->getEnvLang()) : gettext($lit->getLang());
794
        }
795
        return $langName;
796
    }
797
798
    /**
799
     * Gets the values for the property in question in all other languages than the ui language.
800
     */
801
    public function getForeignLabels()
802
    {
803
        $prefLabels = $this->resource->allLiterals('skos:prefLabel');
804
        $labels = array_merge($prefLabels, $this->resource->allLiterals('skos:altLabel'));
805
        $ret = array();
806
        foreach ($labels as $lit) {
807
            // filtering away subsets of the current language eg. en vs en-GB
808
            if ($lit->getLang() != $this->clang && strpos($lit->getLang(), $this->getEnvLang() . '-') !== 0) {
809
                $prop = in_array($lit, $prefLabels) ? 'skos:prefLabel' : 'skos:altLabel';
810
                $ret[$this->literalLanguageToString($lit)][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $prop);
811
            }
812
        }
813
        ksort($ret);
814
        return $ret;
815
    }
816
817
    /**
818
     * Gets the values for the property in question in all other languages than the ui language.
819
     * @param string $property
820
     */
821
    public function getAllLabels($property)
822
    {
823
        $labels = array();
824
        // shortening property labels if possible, EasyRdf requires full URIs to be in angle brackets
825
        $property = (EasyRdf\RdfNamespace::shorten($property) !== null) ? EasyRdf\RdfNamespace::shorten($property) : "<$property>";
826
        foreach ($this->resource->allLiterals($property) as $lit) {
827
            $labels[Punic\Language::getName($lit->getLang(), $this->getEnvLang())][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $property);
828
        }
829
        ksort($labels);
830
        return $labels;
831
    }
832
833
    /**
834
     * Dump concept graph as JSON-LD.
835
     */
836
    public function dumpJsonLd() {
837
        $context = array(
838
            'skos' => EasyRdf\RdfNamespace::get("skos"),
839
            'isothes' => EasyRdf\RdfNamespace::get("isothes"),
840
            'rdfs' => EasyRdf\RdfNamespace::get("rdfs"),
841
            'owl' =>EasyRdf\RdfNamespace::get("owl"),
842
            'dct' => EasyRdf\RdfNamespace::get("dcterms"),
843
            'dc11' => EasyRdf\RdfNamespace::get("dc11"),
844
            'uri' => '@id',
845
            'type' => '@type',
846
            'lang' => '@language',
847
            'value' => '@value',
848
            'graph' => '@graph',
849
            'label' => 'rdfs:label',
850
            'prefLabel' => 'skos:prefLabel',
851
            'altLabel' => 'skos:altLabel',
852
            'hiddenLabel' => 'skos:hiddenLabel',
853
            'broader' => 'skos:broader',
854
            'narrower' => 'skos:narrower',
855
            'related' => 'skos:related',
856
            'inScheme' => 'skos:inScheme',
857
            'schema' => EasyRdf\RdfNamespace::get("schema"),
858
            'wd' => EasyRdf\RdfNamespace::get("wd"),
859
            'wdt' => EasyRdf\RdfNamespace::get("wdt"),
860
        );
861
        $vocabPrefix = preg_replace('/\W+/', '', $this->vocab->getId()); // strip non-word characters
862
        $vocabUriSpace = $this->vocab->getUriSpace();
863
864
        if (!in_array($vocabUriSpace, $context, true)) {
865
            if (!isset($context[$vocabPrefix])) {
866
                $context[$vocabPrefix] = $vocabUriSpace;
867
            }
868
            else if ($context[$vocabPrefix] !== $vocabUriSpace) {
869
                $i = 2;
870
                while (isset($context[$vocabPrefix . $i]) && $context[$vocabPrefix . $i] !== $vocabUriSpace) {
871
                    $i += 1;
872
                }
873
                $context[$vocabPrefix . $i] = $vocabUriSpace;
874
            }
875
        }
876
        $compactJsonLD = \ML\JsonLD\JsonLD::compact($this->graph->serialise('jsonld'), json_encode($context));
877
        $results = \ML\JsonLD\JsonLD::toString($compactJsonLD);
878
879
        return $results;
880
    }
881
}
882