Completed
Pull Request — master (#1165)
by
unknown
02:38
created

VocabularyConfig   F

Complexity

Total Complexity 90

Size/Duplication

Total Lines 592
Duplicated Lines 5.07 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 0
Metric Value
dl 30
loc 592
rs 2
c 0
b 0
f 0
wmc 90
lcom 2
cbo 7

38 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 39 8
A getDefaultLanguage() 0 15 3
A getAlphabeticalFull() 0 4 1
A getShortName() 0 9 2
A getFeedbackRecipient() 0 5 2
A getTitle() 0 4 1
A sortByNotation() 0 4 1
A showChangeList() 0 4 1
B getDataURLs() 0 42 7
A getMainConceptSchemeURI() 0 9 2
A getGroupClassURI() 0 9 2
A getArrayClassURI() 0 9 2
A getAdditionalSearchProperties() 15 15 3
A hasMultiLingualProperty() 0 17 4
A getShowHierarchy() 0 4 1
A showConceptSchemesInHierarchy() 0 4 1
A getExternalResourcesLoading() 0 4 1
A getShowLangCodes() 0 4 1
A searchByNotation() 0 4 1
A getMarcSourceCode() 0 4 1
A getIndexClasses() 0 4 1
A getExtProperties() 0 4 1
A getLanguages() 0 12 2
A getPluginParameters() 0 3 1
B getDefaultSidebarView() 0 19 7
A getId() 0 14 2
A getShowStatistics() 0 3 1
A getPlugins() 0 4 1
A getHierarchyProperty() 15 15 4
A showNotation() 0 4 1
A showAlphabeticalIndex() 0 4 1
A getAlphabeticalListQualifier() 0 4 1
A getShowDeprecated() 0 4 1
A getShowDeprecatedChanges() 0 4 1
A getTypes() 0 11 3
B getLanguageOrder() 0 24 8
A isUseModifiedDate() 0 4 1
B getPropertyOrder() 0 28 8

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like VocabularyConfig often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use VocabularyConfig, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * VocabularyConfig provides access to the vocabulary configuration defined in config.ttl.
5
 */
6
class VocabularyConfig extends BaseConfig
7
{
8
    private $plugins;
9
    private $pluginParameters;
10
    private $languageOrderCache = array();
11
12
    const DEFAULT_PROPERTY_ORDER = array("rdf:type", "dc:isReplacedBy",
13
    "skos:definition", "skos:broader", "isothes:broaderGeneric",
14
    "isothes:broaderPartitive", "isothes:broaderInstantial",
15
    "skos:narrower", "isothes:narrowerGeneric", "isothes:narrowerPartitive",
16
    "isothes:narrowerInstantial", "skos:related", "skos:altLabel",
17
    "skos:note", "skos:scopeNote", "skos:historyNote", "rdfs:comment",
18
    "dc11:source", "dc:source", "skosmos:memberOf", "skosmos:memberOfArray");
19
20
    const ISO25964_PROPERTY_ORDER = array("rdf:type", "dc:isReplacedBy",
21
    // ISO 25964 allows placing all text fields (inc. SN and DEF) together
22
    // so we will do that, except for HN, which is clearly administrative
23
    "skos:note", "skos:scopeNote", "skos:definition", "rdfs:comment",
24
    "dc11:source", "dc:source", "skos:altLabel", "skos:broader",
25
    "isothes:broaderGeneric", "isothes:broaderPartitive",
26
    "isothes:broaderInstantial", "skos:narrower", "isothes:narrowerGeneric",
27
    "isothes:narrowerPartitive", "isothes:narrowerInstantial",
28
    "skos:related", "skos:historyNote", "skosmos:memberOf",
29
    "skosmos:memberOfArray");
30
31
    public function __construct($resource, $globalPlugins=array())
32
    {
33
        $this->resource = $resource;
34
        $plugins = $this->resource->allLiterals('skosmos:usePlugin');
35
        $pluginArray = array();
36
        if ($plugins) {
37
            foreach ($plugins as $pluginlit) {
38
                $pluginArray[] = $pluginlit->getValue();
39
            }
40
        }
41
        $this->plugins = new PluginRegister(array_merge($globalPlugins, $pluginArray));
42
        // Get parameterized plugins defined as resources and their respective parameters
43
        $pluginResources = $this->resource->allResources('skosmos:useParamPlugin');
44
        $this->pluginParameters = array();
45
        if ($pluginResources) {
46
            foreach ($pluginResources as $pluginResource) {
47
                $pluginName = $pluginResource->getLiteral('skosmos:usePlugin')->getValue();
48
                $this->pluginParameters[$pluginName] = array();
49
50
                $pluginParams = $pluginResource->allResources('skosmos:parameters');
51
                foreach ($pluginParams as $parameter) {
52
53
                    $paramLiterals = $parameter->allLiterals('schema:value');
54
                    foreach ($paramLiterals as $paramLiteral) {
55
                        $paramName = $parameter->getLiteral('schema:propertyID')->getValue();
56
                        $paramValue = $paramLiteral->getValue();
57
                        $paramLang = $paramLiteral->getLang();
58
                        if ($paramLang) {
59
                            $paramName .= '_' . $paramLang;
60
                        }
61
                        $this->pluginParameters[$pluginName][$paramName] = $paramValue;
62
                    }
63
                }
64
                $pluginArray[] = $pluginName;
65
            }
66
            $this->plugins = new PluginRegister(array_merge($globalPlugins, $pluginArray));
67
        }
68
69
    }
70
71
    /**
72
     * Get the default language of this vocabulary
73
     * @return string default language, e.g. 'en'
74
     */
75
76
    public function getDefaultLanguage()
77
    {
78
        $deflang = $this->resource->getLiteral('skosmos:defaultLanguage');
79
        if ($deflang) {
80
            return $deflang->getValue();
81
        }
82
83
        $langs = $this->getLanguages();
84
        $deflang = reset($langs); // picking the first one from the list with reset since the keys are not numeric
85
        if (sizeof($langs) > 1) {
86
            trigger_error("Default language for vocabulary '" . $this->getShortName() . "' unknown, choosing '$deflang'.", E_USER_WARNING);
87
        }
88
89
        return $deflang;
90
    }
91
92
    /**
93
     * Whether the alphabetical index is small enough to be shown all at once.
94
     * @return boolean true if all concepts can be shown at once.
95
     */
96
    public function getAlphabeticalFull()
97
    {
98
        return $this->getBoolean('skosmos:fullAlphabeticalIndex');
99
    }
100
101
    /**
102
     * Returns a short name for a vocabulary if configured. If that has not been set
103
     * using vocabId as a fallback.
104
     * @return string
105
     */
106
    public function getShortName()
107
    {
108
        $shortname = $this->getLiteral('skosmos:shortName');
109
        if ($shortname)
110
          return $shortname;
111
112
        // if no shortname exists fall back to the id
113
        return $this->getId();
114
    }
115
116
    /**
117
     * Get the vocabulary feedback e-mail address and return it.
118
     *
119
     * @return string e-mail address or null if not defined.
120
     */
121
    public function getFeedbackRecipient()
122
    {
123
        $email = $this->resource->get('skosmos:feedbackRecipient');
124
        return isset($email) ? $email->getValue() : null;
125
    }
126
127
    /**
128
     * Returns the human readable vocabulary title.
129
     * @return string the title of the vocabulary
130
     */
131
    public function getTitle($lang = null)
132
    {
133
        return $this->getLiteral('dc:title', false, $lang);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

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...
134
    }
135
136
    /**
137
     * Returns a boolean value set in the config.ttl config.
138
     * @return boolean
139
     */
140
    public function sortByNotation()
141
    {
142
        return $this->getBoolean('skosmos:sortByNotation');
143
    }
144
145
    /**
146
     * Returns a boolean value set in the config.ttl config.
147
     * @return boolean
148
     */
149
    public function showChangeList()
150
    {
151
        return $this->getBoolean('skosmos:showChangeList');
152
    }
153
154
    /**
155
     * get the URLs from which the vocabulary data can be downloaded
156
     * @return array Array with MIME type as key, URL as value
157
     */
158
    public function getDataURLs()
159
    {
160
        $ret = array();
161
        $urls = $this->resource->allResources("void:dataDump");
162
        foreach ($urls as $url) {
163
            // first try dc:format and dc11:format
164
            $mimetypelit = $url->getLiteral('dc:format');
165
            if ($mimetypelit === null) {
166
                $mimetypelit = $url->getLiteral('dc11:format');
167
            }
168
169
            if ($mimetypelit !== null) {
170
                $mimetype = $mimetypelit->getValue();
171
            } else {
172
                $format = EasyRdf\Format::guessFormat(null, $url->getURI());
173
                if ($format === null) {
174
                    trigger_error("Could not guess format for <$url>.", E_USER_WARNING);
175
                    continue;
176
                }
177
                $mimetypes = array_keys($format->getMimeTypes());
178
                $mimetype = $mimetypes[0];
179
            }
180
181
            $langLit = $url->getLiteral('dc:language');
182
183
            if ($langLit != null) {
184
                //when the mimetype has language variants
185
                $dataUrlLang = $langLit->getValue();
186
187
                if (!isset($ret[$mimetype])) {
188
                  $arr = array();
189
                } else {
190
                  $arr = $ret[$mimetype];
191
                }
192
                $arr[$dataUrlLang] = $url->getURI();
193
                $ret[$mimetype] = $arr;
194
            } else {
195
                $ret[$mimetype] = $url->getURI();
196
            }
197
        }
198
        return $ret;
199
    }
200
201
    /**
202
     * Returns the main Concept Scheme URI of that Vocabulary,
203
     * or null if not set.
204
     * @return string concept scheme URI or null
205
     */
206
207
    public function getMainConceptSchemeURI()
208
    {
209
        $val = $this->resource->getResource("skosmos:mainConceptScheme");
210
        if ($val) {
211
            return $val->getURI();
212
        }
213
214
        return null;
215
    }
216
217
    /**
218
     * Returns the class URI used for concept groups in this vocabulary,
219
     * or null if not set.
220
     * @return string group class URI or null
221
     */
222
223
    public function getGroupClassURI()
224
    {
225
        $val = $this->resource->getResource("skosmos:groupClass");
226
        if ($val) {
227
            return $val->getURI();
228
        }
229
230
        return null;
231
    }
232
233
    /**
234
     * Returns the class URI used for thesaurus arrays in this vocabulary,
235
     * or null if not set.
236
     * @return string array class URI or null
237
     */
238
239
    public function getArrayClassURI()
240
    {
241
        $val = $this->resource->getResource("skosmos:arrayClass");
242
        if ($val) {
243
            return $val->getURI();
244
        }
245
246
        return null;
247
    }
248
249
    /**
250
     * Returns custom properties displayed on the search page if configured.
251
     * @return array array class URI or null
252
     */
253
254 View Code Duplication
    public function getAdditionalSearchProperties()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
255
    {
256
        $resources = $this->resource->allResources("skosmos:showPropertyInSearch");
257
        $ret = array();
258
        foreach ($resources as $res) {
259
            $prop = $res->getURI();
260
            if (EasyRdf\RdfNamespace::shorten($prop) !== null) // shortening property labels if possible
261
            {
262
                $prop = EasyRdf\RdfNamespace::shorten($prop);
263
            }
264
265
            $ret[] = $prop;
266
        }
267
        return $ret;
268
    }
269
270
    /**
271
     * Queries whether the property should be shown with all the label language variations.
272
     * @param string $property
273
     * @return boolean
274
     */
275
    public function hasMultiLingualProperty($property)
276
    {
277
        $resources = $this->resource->allResources("skosmos:hasMultiLingualProperty");
278
        foreach ($resources as $res) {
279
            $prop = $res->getURI();
280
            if (EasyRdf\RdfNamespace::shorten($prop) !== null) // shortening property labels if possible
281
            {
282
                $prop = EasyRdf\RdfNamespace::shorten($prop);
283
            }
284
285
            if ($prop === $property) {
286
                return true;
287
            }
288
289
        }
290
        return false;
291
    }
292
293
    /**
294
     * Returns a boolean value set in the config.ttl config.
295
     * @return boolean
296
     */
297
    public function getShowHierarchy()
298
    {
299
        return $this->getBoolean('skosmos:showTopConcepts');
300
    }
301
302
    /**
303
     * Returns a boolean value set in the config.ttl config.
304
     * @return boolean
305
     */
306
    public function showConceptSchemesInHierarchy()
307
    {
308
        return $this->getBoolean('skosmos:conceptSchemesInHierarchy');
309
    }
310
311
    /**
312
     * Returns a boolean value set in the config.ttl config.
313
     * @return boolean defaults to true if fetching hasn't been explicitly denied.
314
     */
315
    public function getExternalResourcesLoading()
316
    {
317
        return $this->getBoolean('skosmos:loadExternalResources', true);
318
    }
319
320
    /**
321
     * Returns a boolean value set in the config.ttl config.
322
     * @return boolean
323
     */
324
    public function getShowLangCodes()
325
    {
326
        return $this->getBoolean('skosmos:explicitLanguageTags');
327
    }
328
329
    /**
330
     * Returns a boolean value set in the config.ttl config.
331
     * @return boolean
332
     */
333
    public function searchByNotation()
334
    {
335
        return $this->getBoolean('skosmos:searchByNotation');
336
    }
337
338
    /**
339
     * Returns skosmos:marcSourcecode value set in config.ttl.
340
     * @return string marcsource name
341
     */
342
    public function getMarcSourceCode($lang = null)
343
    {
344
        return $this->getLiteral('skosmos:marcSourceCode', false, $lang);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

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...
345
    }
346
347
    /**
348
     * Returns a boolean value set in the config.ttl config.
349
     * @return array array of concept class URIs (can be empty)
350
     */
351
    public function getIndexClasses()
352
    {
353
        return $this->getResources("skosmos:indexShowClass");
354
    }
355
356
    /**
357
     * Returns skosmos:externalProperty values set in the config.ttl config.
358
     * @return array array of external property URIs (can be empty)
359
     */
360
    public function getExtProperties()
361
    {
362
        return $this->getResources("skosmos:externalProperty");
363
    }
364
365
    /**
366
     * Get the languages supported by this vocabulary
367
     * @return array languages supported by this vocabulary (as language tag strings)
368
     */
369
    public function getLanguages()
370
    {
371
        $langs = $this->resource->allLiterals('skosmos:language');
372
        $ret = array();
373
        foreach ($langs as $lang) {
374
            $langlit = Punic\Language::getName($lang->getValue(), $this->getEnvLang());
375
            $ret[$langlit] = $lang->getValue();
376
        }
377
        ksort($ret);
378
379
        return $ret;
380
    }
381
382
    /**
383
     * Returns the plugin parameters
384
     * @return string plugin parameters or null
385
     */
386
    public function getPluginParameters() {
387
        return json_encode($this->pluginParameters, true);
388
    }
389
390
    /**
391
     * Returns the vocabulary default sidebar view.
392
     * @return string name of the view
393
     */
394
    public function getDefaultSidebarView()
395
    {
396
        $defview = $this->resource->getLiteral('skosmos:defaultSidebarView');
397
        if ($defview) {
398
            $value = $defview->getValue();
399
            if ($value === 'groups' || $value === 'hierarchy') {
400
                return $value;
401
            }
402
403
        }
404
        if ($this->showAlphabeticalIndex() === false) {
405
            if ($this->getShowHierarchy()) {
406
                return 'hierarchy';
407
            } else if ($this->getGroupClassURI()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getGroupClassURI() 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...
408
                return 'groups';
409
            }
410
        }
411
        return 'alphabetical'; // if not defined displaying the alphabetical index
412
    }
413
414
    /**
415
     * Extracts the vocabulary id string from the baseuri of the vocabulary.
416
     * @return string identifier eg. 'mesh'.
417
     */
418
    public function getId()
419
    {
420
        $uriparts = explode("#", $this->resource->getURI());
421
        if (count($uriparts) != 1)
422
        // hash namespace
423
        {
424
            return $uriparts[1];
425
        }
426
427
        // slash namespace
428
        $uriparts = explode("/", $this->resource->getURI());
429
430
        return $uriparts[count($uriparts) - 1];
431
    }
432
433
    public function getShowStatistics() {
434
        return $this->getBoolean('skosmos:showStatistics', true);
435
    }
436
437
    public function getPlugins()
438
    {
439
        return $this->plugins;
440
    }
441
442
    /**
443
     * Returns the property/properties used for visualizing concept hierarchies.
444
     * @return array array class URI or null
445
     */
446
447 View Code Duplication
    public function getHierarchyProperty()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
448
    {
449
        $resources = $this->resource->allResources("skosmos:hierarchyProperty");
450
        $ret = array();
451
        foreach ($resources as $res) {
452
            $prop = $res->getURI();
453
            if (EasyRdf\RdfNamespace::shorten($prop) !== null) // prefixing if possible
454
            {
455
                $prop = EasyRdf\RdfNamespace::shorten($prop);
456
            }
457
458
            $ret[] = $prop;
459
        }
460
        return empty($ret) ? array('skos:broader') : $ret;
461
    }
462
463
    /**
464
     * Returns a boolean value set in the config.ttl config.
465
     * @return boolean
466
     */
467
    public function showNotation()
468
    {
469
        return $this->getBoolean('skosmos:showNotation', true);
470
    }
471
472
    /**
473
     * Returns a boolean value set in the config.ttl config.
474
     * @return boolean
475
     */
476
    public function showAlphabeticalIndex()
477
    {
478
        return $this->getBoolean('skosmos:showAlphabeticalIndex', true);
479
    }
480
481
    /**
482
     * Returns the alphabetical list qualifier in this vocabulary,
483
     * or null if not set.
484
     * @return EasyRdf\Resource|null alphabetical list qualifier resource or null
485
     */
486
    public function getAlphabeticalListQualifier()
487
    {
488
        return $this->resource->getResource('skosmos:alphabeticalListQualifier');
489
    }
490
491
    /**
492
     * Returns a boolean value set in the config.ttl config.
493
     * @return boolean
494
     */
495
    public function getShowDeprecated()
496
    {
497
        return $this->getBoolean('skosmos:showDeprecated', false);
498
    }
499
500
    /**
501
     * Returns a boolean value set in the config.ttl config.
502
     * @return boolean
503
     */
504
    public function getShowDeprecatedChanges()
505
    {
506
        return $this->getBoolean('skosmos:showDeprecatedChanges', false);
507
    }
508
509
    /**
510
     * Returns the vocabulary dc:type value(s) with their labels and uris, if set in the vocabulary configuration.
511
     * @return array of objects or an empty array
512
     */
513
    public function getTypes($lang = null)
514
    {
515
        $resources = $this->resource->allResources("dc:type");
516
        $ret = array();
517
        foreach ($resources as $res) {
518
            $prop = $res->getURI();
519
            $label = $res->label($lang) ? $res->label($lang) : $res->label($this->getDefaultLanguage());
520
            $ret[] = array('uri' => $prop, 'prefLabel' =>  $label->getValue());
521
        }
522
        return $ret;
523
    }
524
525
    /**
526
     * Returns an array of fallback languages that is ordered by priority and
527
     * defined in the vocabulary configuration as a collection.
528
     * Additionally, the chosen content language is inserted with the highest priority
529
     * and the vocab default language is inserted with the lowest priority.
530
     * @param string $clang
531
     * @return array of language code strings
532
     */
533
    public function getLanguageOrder($clang)
534
    {
535
        if (array_key_exists($clang, $this->languageOrderCache)) {
536
            return $this->languageOrderCache[$clang];
537
        }
538
        $ret = array($clang);
539
        $fallbacks = !empty($this->resource->get('skosmos:fallbackLanguages')) ? $this->resource->get('skosmos:fallbackLanguages') : array();
540
        foreach ($fallbacks as $lang) {
541
            if (!in_array($lang, $ret)) {
542
                $ret[] = (string)$lang; // Literal to string conversion
543
            }
544
        }
545
        if (!in_array($this->getDefaultLanguage(), $ret)) {
546
            $ret[] = (string)$this->getDefaultLanguage();
547
        }
548
        foreach ($this->getLanguages() as $lang) {
549
            if (!in_array($lang, $ret)) {
550
                $ret[] = $lang;
551
            }
552
        }
553
        // store in cache so this doesn't have to be computed again
554
        $this->languageOrderCache[$clang] = $ret;
555
        return $ret;
556
    }
557
558
    /**
559
     * @return boolean
560
     */
561
    public function isUseModifiedDate()
562
    {
563
        return $this->getBoolean('skosmos:useModifiedDate', false);
564
    }
565
566
    /**
567
     * @return array
568
     */
569
    public function getPropertyOrder()
570
    {
571
        $order = $this->getResource()->getResource('skosmos:propertyOrder');
572
        if ($order === null) {
573
            return self::DEFAULT_PROPERTY_ORDER;
574
        }
575
576
        $short = EasyRdf\RdfNamespace::shorten($order);
577
        if ($short == 'skosmos:iso25964PropertyOrder') {
578
            return self::ISO25964_PROPERTY_ORDER;
579
        } elseif ($short == 'skosmos:defaultPropertyOrder') {
580
            return self::DEFAULT_PROPERTY_ORDER;
581
        }
582
        
583
        // check for custom order definition
584
        $orderList = $order->getResource('rdf:value');
585
        if ($orderList !== null && $orderList instanceof EasyRdf\Collection) {
586
            $ret = array();
587
            foreach ($orderList as $prop) {
588
                $short = $prop->shorten();
589
                $ret[] = ($short !== null) ? $short : $prop->getURI();
590
            }
591
            return $ret;
592
        }
593
        
594
        trigger_error("Property order for vocabulary '{$this->getShortName()}' unknown, using default order", E_USER_WARNING);
595
        return self::DEFAULT_PROPERTY_ORDER;
596
    }
597
}
598