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 classes like Concept 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 Concept, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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 | /** |
||
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) { |
||
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 | foreach ($this->vocab->getConfig()->getLanguageOrder($this->clang) as $fallback) { |
||
112 | if ($this->resource->label($fallback) !== null) { |
||
113 | return $this->resource->label($fallback); |
||
114 | } |
||
115 | // We need to check all the labels in case one of them matches a subtag of the current language |
||
116 | foreach($this->resource->allLiterals('skos:prefLabel') as $label) { |
||
117 | // the label lang code is a subtag of the UI lang eg. en-GB - create a new literal with the main language |
||
118 | if ($label !== null && strpos($label->getLang(), $fallback . '-') === 0) { |
||
119 | return EasyRdf\Literal::create($label, $fallback); |
||
120 | } |
||
121 | } |
||
122 | } |
||
123 | |||
124 | // Last resort: label in any language, including literal with empty language tag |
||
125 | $label = $this->resource->label(); |
||
126 | if ($label !== null) { |
||
127 | if (!$label->getLang()) { |
||
128 | return $label->getValue(); |
||
129 | } |
||
130 | return EasyRdf\Literal::create($label->getValue(), $label->getLang()); |
||
131 | |||
132 | |||
133 | // empty |
||
134 | return ""; |
||
135 | } |
||
136 | |||
137 | public function hasXlLabel($prop = 'prefLabel') |
||
138 | { |
||
139 | if ($this->resource->hasProperty('skosxl:' . $prop)) { |
||
140 | return true; |
||
141 | } |
||
142 | return false; |
||
143 | } |
||
144 | |||
145 | public function getXlLabel() |
||
146 | { |
||
147 | $labels = $this->resource->allResources('skosxl:prefLabel'); |
||
148 | foreach($labels as $labres) { |
||
149 | $label = $labres->getLiteral('skosxl:literalForm'); |
||
150 | if ($label !== null && $label->getLang() == $this->clang) { |
||
151 | return new LabelSkosXL($this->model, $labres); |
||
152 | } |
||
153 | } |
||
154 | return null; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Returns a notation for the concept or null if it has not been defined. |
||
159 | * @return string eg. '999' |
||
160 | */ |
||
161 | public function getNotation() |
||
162 | { |
||
163 | $notation = $this->resource->get('skos:notation'); |
||
164 | if ($this->vocab->getConfig()->showNotation() && $notation !== null) { |
||
165 | return $notation->getValue(); |
||
166 | } |
||
167 | |||
168 | return null; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Returns the Vocabulary object or undefined if that is not available. |
||
173 | * @return Vocabulary |
||
174 | */ |
||
175 | public function getVocab() |
||
176 | { |
||
177 | return $this->vocab; |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Returns the vocabulary shortname string or id if that is not available. |
||
182 | * @return string |
||
183 | */ |
||
184 | public function getShortName() |
||
185 | { |
||
186 | return $this->vocab ? $this->vocab->getShortName() : null; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Returns the vocabulary shortname string or id if that is not available. |
||
191 | * @return string |
||
192 | */ |
||
193 | public function getVocabTitle() |
||
194 | { |
||
195 | return $this->vocab ? $this->vocab->getTitle() : null; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Setter for the $clang property. |
||
200 | * @param string $clang language code eg. 'en' |
||
201 | */ |
||
202 | public function setContentLang($clang) |
||
203 | { |
||
204 | $this->clang = $clang; |
||
205 | } |
||
206 | |||
207 | public function getContentLang() |
||
208 | { |
||
209 | return $this->clang; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Setter for the $foundby property. |
||
214 | * @param string $label label that was matched |
||
215 | * @param string $type type of match: 'alt', 'hidden', or 'lang' |
||
216 | */ |
||
217 | public function setFoundBy($label, $type) |
||
218 | { |
||
219 | $this->foundby = $label; |
||
220 | $this->foundbytype = $type; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * Getter for the $foundby property. |
||
225 | * @return string |
||
226 | */ |
||
227 | public function getFoundBy() |
||
228 | { |
||
229 | return $this->foundby; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Getter for the $foundbytype property. |
||
234 | * @return string |
||
235 | */ |
||
236 | public function getFoundByType() |
||
237 | { |
||
238 | return $this->foundbytype; |
||
239 | } |
||
240 | |||
241 | public function getMappingProperties() |
||
242 | { |
||
243 | $ret = array(); |
||
244 | |||
245 | $longUris = $this->resource->propertyUris(); |
||
246 | foreach ($longUris as &$prop) { |
||
247 | if (EasyRdf\RdfNamespace::shorten($prop) !== null) { |
||
248 | // shortening property labels if possible |
||
249 | $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop); |
||
250 | } else { |
||
251 | $sprop = "<$prop>"; |
||
252 | } |
||
253 | // EasyRdf requires full URIs to be in angle brackets |
||
254 | |||
255 | if (in_array($prop, $this->MAPPING_PROPERTIES) && !in_array($prop, $this->DELETED_PROPERTIES)) { |
||
256 | $propres = new EasyRdf\Resource($prop, $this->graph); |
||
257 | $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); // current language |
||
258 | $propobj = new ConceptProperty($prop, $proplabel); |
||
259 | if ($propobj->getLabel() !== null) { |
||
260 | // only display properties for which we have a label |
||
261 | $ret[$prop] = $propobj; |
||
262 | } |
||
263 | |||
264 | // Iterating through every resource and adding these to the data object. |
||
265 | foreach ($this->resource->allResources($sprop) as $val) { |
||
266 | if (isset($ret[$prop])) { |
||
267 | // checking if the target vocabulary can be found at the skosmos endpoint |
||
268 | $exuri = $val->getUri(); |
||
269 | // if multiple vocabularies are found, the following method will return in priority the current vocabulary of the concept |
||
270 | $exvoc = $this->model->guessVocabularyFromURI($exuri, $this->vocab->getId()); |
||
271 | // if not querying the uri itself |
||
272 | if (!$exvoc) { |
||
273 | $response = null; |
||
274 | // if told to do so in the vocabulary configuration |
||
275 | if ($this->vocab->getConfig()->getExternalResourcesLoading()) { |
||
276 | $response = $this->model->getResourceFromUri($exuri); |
||
277 | } |
||
278 | |||
279 | if ($response) { |
||
280 | $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $response, $prop), $this->clang); |
||
281 | continue; |
||
282 | } |
||
283 | } |
||
284 | $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang); |
||
285 | } |
||
286 | } |
||
287 | } |
||
288 | } |
||
289 | |||
290 | // sorting the properties to a order preferred in the Skosmos concept page. |
||
291 | $ret = $this->arbitrarySort($ret); |
||
292 | |||
293 | return $ret; |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Iterates over all the properties of the concept and returns those in an array. |
||
298 | * @return array |
||
299 | */ |
||
300 | public function getProperties() |
||
301 | { |
||
302 | $properties = array(); |
||
303 | $narrowersByUri = array(); |
||
304 | $inCollection = array(); |
||
305 | $membersArray = array(); |
||
306 | $longUris = $this->resource->propertyUris(); |
||
307 | $duplicates = array(); |
||
308 | $ret = array(); |
||
309 | |||
310 | // looking for collections and linking those with their narrower concepts |
||
311 | if ($this->vocab->getConfig()->getArrayClassURI() !== null) { |
||
312 | $collections = $this->graph->allOfType($this->vocab->getConfig()->getArrayClassURI()); |
||
313 | if (sizeof($collections) > 0) { |
||
314 | // indexing the narrowers once to avoid iterating all of them with every collection |
||
315 | foreach ($this->resource->allResources('skos:narrower') as $narrower) { |
||
316 | $narrowersByUri[$narrower->getUri()] = $narrower; |
||
317 | } |
||
318 | |||
319 | foreach ($collections as $coll) { |
||
320 | $currCollMembers = $this->getCollectionMembers($coll, $narrowersByUri); |
||
321 | foreach ($currCollMembers as $collection) { |
||
322 | if ($collection->getSubMembers()) { |
||
323 | $submembers = $collection->getSubMembers(); |
||
324 | foreach ($submembers as $member) { |
||
325 | $inCollection[$member->getUri()] = true; |
||
326 | } |
||
327 | |||
328 | } |
||
329 | } |
||
330 | |||
331 | if (isset($collection) && $collection->getSubMembers()) { |
||
332 | $membersArray = array_merge($currCollMembers, $membersArray); |
||
333 | } |
||
334 | |||
335 | } |
||
336 | $properties['skos:narrower'] = $membersArray; |
||
337 | } |
||
338 | } |
||
339 | |||
340 | foreach ($longUris as &$prop) { |
||
341 | // storing full URI without brackets in a separate variable |
||
342 | $longUri = $prop; |
||
343 | if (EasyRdf\RdfNamespace::shorten($prop) !== null) { |
||
344 | // shortening property labels if possible |
||
345 | $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop); |
||
346 | } else { |
||
347 | $sprop = "<$prop>"; |
||
348 | } |
||
349 | // EasyRdf requires full URIs to be in angle brackets |
||
350 | |||
351 | if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) { |
||
352 | // retrieve property label and super properties from the current vocabulary first |
||
353 | $propres = new EasyRdf\Resource($prop, $this->graph); |
||
354 | $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); |
||
355 | |||
356 | // if not found in current vocabulary, look up in the default graph to be able |
||
357 | // to read an ontology loaded in a separate graph |
||
358 | // note that this imply that the property has an rdf:type declared for the query to work |
||
359 | if(!$proplabel) { |
||
360 | $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang()); |
||
361 | $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->model->getDefaultSparql()->queryLabel($longUri, '')['']; |
||
362 | } |
||
363 | |||
364 | // look for superproperties in the current graph |
||
365 | $superprops = array(); |
||
366 | foreach ($this->graph->allResources($prop, 'rdfs:subPropertyOf') as $subi) { |
||
367 | $superprops[] = $subi->getUri(); |
||
368 | } |
||
369 | |||
370 | // also look up superprops in the default graph if not found in current vocabulary |
||
371 | if(!$superprops || empty($superprops)) { |
||
372 | $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri); |
||
373 | } |
||
374 | |||
375 | // we're reading only one super property, even if there are multiple ones |
||
376 | $superprop = ($superprops)?$superprops[0]:null; |
||
377 | if ($superprop) { |
||
378 | $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop; |
||
379 | } |
||
380 | $propobj = new ConceptProperty($prop, $proplabel, $superprop); |
||
381 | |||
382 | if ($propobj->getLabel() !== null) { |
||
383 | // only display properties for which we have a label |
||
384 | $ret[$prop] = $propobj; |
||
385 | } |
||
386 | |||
387 | // searching for subproperties of literals too |
||
388 | if($superprops) { |
||
389 | foreach ($superprops as $subi) { |
||
390 | $suburi = EasyRdf\RdfNamespace::shorten($subi) ? EasyRdf\RdfNamespace::shorten($subi) : $subi; |
||
391 | $duplicates[$suburi] = $prop; |
||
392 | } |
||
393 | } |
||
394 | |||
395 | // Iterating through every literal and adding these to the data object. |
||
396 | foreach ($this->resource->allLiterals($sprop) as $val) { |
||
397 | $literal = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $val, $prop); |
||
398 | // only add literals when they match the content/hit language or have no language defined |
||
399 | if (isset($ret[$prop]) && ($literal->getLang() === $this->clang || $literal->getLang() === null)) { |
||
400 | $ret[$prop]->addValue($literal); |
||
401 | } |
||
402 | |||
403 | } |
||
404 | |||
405 | // Iterating through every resource and adding these to the data object. |
||
406 | foreach ($this->resource->allResources($sprop) as $val) { |
||
407 | // skipping narrower concepts which are already shown in a collection |
||
408 | if ($sprop === 'skos:narrower' && array_key_exists($val->getUri(), $inCollection)) { |
||
409 | continue; |
||
410 | } |
||
411 | |||
412 | // hiding rdf:type property if it's just skos:Concept |
||
413 | if ($sprop === 'rdf:type' && $val->shorten() === 'skos:Concept') { |
||
414 | continue; |
||
415 | } |
||
416 | |||
417 | // handled by getMappingProperties() |
||
418 | if (in_array($sprop, $this->MAPPING_PROPERTIES)) { |
||
419 | continue; |
||
420 | } |
||
421 | |||
422 | if (isset($ret[$prop])) { |
||
423 | // checking if the property value is not in the current vocabulary |
||
424 | $exvoc = $this->model->guessVocabularyFromURI($val->getUri()); |
||
425 | if ($exvoc && $exvoc->getId() !== $this->vocab->getId()) { |
||
426 | $ret[$prop]->addValue(new ConceptMappingPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang); |
||
427 | continue; |
||
428 | } |
||
429 | $ret[$prop]->addValue(new ConceptPropertyValue($this->model, $this->vocab, $val, $prop, $this->clang), $this->clang); |
||
430 | } |
||
431 | |||
432 | } |
||
433 | } |
||
434 | } |
||
435 | // adding narrowers part of a collection |
||
436 | foreach ($properties as $prop => $values) { |
||
437 | foreach ($values as $value) { |
||
438 | $ret[$prop]->addValue($value, $this->clang); |
||
439 | } |
||
440 | } |
||
441 | |||
442 | foreach ($ret as $key => $prop) { |
||
443 | if (sizeof($prop->getValues()) === 0) { |
||
444 | unset($ret[$key]); |
||
445 | } |
||
446 | } |
||
447 | |||
448 | $ret = $this->removeDuplicatePropertyValues($ret, $duplicates); |
||
449 | // sorting the properties to the order preferred in the Skosmos concept page. |
||
450 | $ret = $this->arbitrarySort($ret); |
||
451 | return $ret; |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * Removes properties that have duplicate values. |
||
456 | * @param $ret the array of properties generated by getProperties |
||
457 | * @param $duplicates array of properties found are a subProperty of a another property |
||
458 | * @return array of ConceptProperties |
||
459 | */ |
||
460 | public function removeDuplicatePropertyValues($ret, $duplicates) |
||
461 | { |
||
462 | $propertyValues = array(); |
||
463 | |||
464 | foreach ($ret as $prop) { |
||
465 | foreach ($prop->getValues() as $value) { |
||
466 | $label = $value->getLabel(); |
||
467 | $propertyValues[(method_exists($label, 'getValue')) ? $label->getValue() : $label][] = $value->getType(); |
||
468 | } |
||
469 | } |
||
470 | |||
471 | foreach ($propertyValues as $value => $propnames) { |
||
472 | // if there are multiple properties with the same string value. |
||
473 | if (count($propnames) > 1) { |
||
474 | foreach ($propnames as $property) { |
||
475 | // if there is a more accurate property delete the more generic one. |
||
476 | if (isset($duplicates[$property])) { |
||
477 | unset($ret[$property]); |
||
478 | } |
||
479 | } |
||
480 | |||
481 | } |
||
482 | } |
||
483 | return $ret; |
||
484 | } |
||
485 | |||
486 | /** |
||
487 | * Gets the creation date and modification date if available. |
||
488 | * @return String containing the date information in a human readable format. |
||
489 | */ |
||
490 | public function getDate() |
||
491 | { |
||
492 | $ret = ''; |
||
493 | $created = ''; |
||
494 | $modified = ''; |
||
495 | try { |
||
496 | // finding the created properties |
||
497 | if ($this->resource->get('dc:created')) { |
||
498 | $created = $this->resource->get('dc:created')->getValue(); |
||
499 | } |
||
500 | |||
501 | // finding the modified properties |
||
502 | if ($this->resource->get('dc:modified')) { |
||
503 | $modified = $this->resource->get('dc:modified')->getValue(); |
||
504 | } |
||
505 | |||
506 | // making a human readable string from the timestamps |
||
507 | if ($created != '') { |
||
508 | $ret = gettext('skosmos:created') . ' ' . (Punic\Calendar::formatDate($created, 'short')); |
||
509 | } |
||
510 | |||
511 | if ($modified != '') { |
||
512 | if ($created != '') { |
||
513 | $ret .= ', ' . gettext('skosmos:modified') . ' ' . (Punic\Calendar::formatDate($modified, 'short')); |
||
514 | } else { |
||
515 | $ret .= ' ' . ucfirst(gettext('skosmos:modified')) . ' ' . (Punic\Calendar::formatDate($modified, 'short')); |
||
516 | } |
||
517 | |||
518 | } |
||
519 | } catch (Exception $e) { |
||
520 | trigger_error($e->getMessage(), E_USER_WARNING); |
||
521 | $ret = ''; |
||
522 | if ($this->resource->get('dc:modified')) { |
||
523 | $modified = (string) $this->resource->get('dc:modified'); |
||
524 | $ret = gettext('skosmos:modified') . ' ' . $modified; |
||
525 | } |
||
526 | if ($this->resource->get('dc:created')) { |
||
527 | $created .= (string) $this->resource->get('dc:created'); |
||
528 | $ret .= ' ' . gettext('skosmos:created') . ' ' . $created; |
||
529 | } |
||
530 | } |
||
531 | return $ret; |
||
532 | } |
||
533 | |||
534 | /** |
||
535 | * Gets the members of a specific collection. |
||
536 | * @param $coll |
||
537 | * @param array containing all narrowers as EasyRdf\Resource |
||
538 | * @return array containing ConceptPropertyValue objects |
||
539 | */ |
||
540 | private function getCollectionMembers($coll, $narrowers) |
||
541 | { |
||
542 | $membersArray = array(); |
||
543 | $collLabel = $coll->label()->getValue($this->clang) ? $coll->label($this->clang) : $coll->label(); |
||
544 | if ($collLabel) { |
||
545 | $collLabel = $collLabel->getValue(); |
||
546 | } |
||
547 | |||
548 | $membersArray[$collLabel] = new ConceptPropertyValue($this->model, $this->vocab, $coll, 'skos:narrower', $this->clang); |
||
549 | foreach ($coll->allResources('skos:member') as $member) { |
||
550 | if (array_key_exists($member->getUri(), $narrowers)) { |
||
551 | $narrower = $narrowers[$member->getUri()]; |
||
552 | if (isset($narrower)) { |
||
553 | $membersArray[$collLabel]->addSubMember(new ConceptPropertyValue($this->model, $this->vocab, $narrower, 'skos:member', $this->clang), $this->clang); |
||
554 | } |
||
555 | |||
556 | } |
||
557 | } |
||
558 | |||
559 | return $membersArray; |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * Gets the groups the concept belongs to. |
||
564 | */ |
||
565 | public function getGroupProperties() |
||
566 | { |
||
567 | return $this->getReverseResources(false); |
||
568 | } |
||
569 | |||
570 | /** |
||
571 | * Gets the groups/arrays the concept belongs to. |
||
572 | */ |
||
573 | public function getReverseResources($includeArrays) { |
||
574 | $groups = array(); |
||
575 | $reverseResources = $this->graph->resourcesMatching('skos:member', $this->resource); |
||
576 | if (isset($reverseResources)) { |
||
577 | $arrayClassURI = $this->vocab !== null ? $this->vocab->getConfig()->getArrayClassURI() : null; |
||
578 | $arrayClass = $arrayClassURI !== null ? EasyRdf\RdfNamespace::shorten($arrayClassURI) : null; |
||
579 | $superGroups = $this->resource->all('isothes:superGroup'); |
||
580 | $superGroupUris = array_map(function($obj) { return $obj->getUri(); }, $superGroups); |
||
581 | foreach ($reverseResources as $reverseResource) { |
||
582 | if (in_array($arrayClass, $reverseResource->types()) === $includeArrays) { |
||
583 | // not adding the memberOf if the reverse resource is already covered by isothes:superGroup see issue #433 |
||
584 | if (in_array($reverseResource->getUri(), $superGroupUris)) { |
||
585 | continue; |
||
586 | } |
||
587 | $property = in_array($arrayClass, $reverseResource->types()) ? "skosmos:memberOfArray" : "skosmos:memberOf"; |
||
588 | $collLabel = $reverseResource->label($this->clang) ? $reverseResource->label($this->clang) : $reverseResource->label(); |
||
589 | if ($collLabel) { |
||
590 | $collLabel = $collLabel->getValue(); |
||
591 | } |
||
592 | |||
593 | $groups[$collLabel] = new ConceptPropertyValue($this->model, $this->vocab, $reverseResource, $property, $this->clang); |
||
594 | ksort($groups); |
||
595 | $super = $this->graph->resourcesMatching('skos:member', $reverseResource); |
||
596 | while (isset($super) && !empty($super)) { |
||
597 | foreach ($super as $res) { |
||
598 | $superprop = new ConceptPropertyValue($this->model, $this->vocab, $res, 'skosmos:memberOfSuper', $this->clang); |
||
599 | array_unshift($groups, $superprop); |
||
600 | $super = $this->graph->resourcesMatching('skos:member', $res); |
||
601 | } |
||
602 | } |
||
603 | } |
||
604 | } |
||
605 | } |
||
606 | return $groups; |
||
607 | } |
||
608 | |||
609 | public function getArrayProperties() { |
||
610 | return $this->getReverseResources(true); |
||
611 | } |
||
612 | |||
613 | /** |
||
614 | * Reads the literal language code and gets a name for it from Punic or alternatively |
||
615 | * tries to search for a gettext translation. |
||
616 | * @param EasyRdf\Literal $lit |
||
617 | * @return string e.g. 'English' |
||
618 | */ |
||
619 | private function literalLanguageToString($lit) { |
||
620 | // using empty string as the language literal when there is no langcode set |
||
621 | $langName = ''; |
||
622 | if ($lit->getLang() !== null) { |
||
623 | $langName = Punic\Language::getName($lit->getLang(), $this->getEnvLang()) !== $lit->getLang() ? Punic\Language::getName($lit->getLang(), $this->getEnvLang()) : gettext($lit->getLang()); |
||
624 | } |
||
625 | return $langName; |
||
626 | } |
||
627 | |||
628 | /** |
||
629 | * Gets the values for the property in question in all other languages than the ui language. |
||
630 | */ |
||
631 | public function getForeignLabels() |
||
632 | { |
||
633 | $prefLabels = $this->resource->allLiterals('skos:prefLabel'); |
||
634 | $labels = array_merge($prefLabels, $this->resource->allLiterals('skos:altLabel')); |
||
635 | $ret = array(); |
||
636 | foreach ($labels as $lit) { |
||
637 | // filtering away subsets of the current language eg. en vs en-GB |
||
638 | if ($lit->getLang() != $this->clang && strpos($lit->getLang(), $this->getEnvLang() . '-') !== 0) { |
||
639 | $prop = in_array($lit, $prefLabels) ? 'skos:prefLabel' : 'skos:altLabel'; |
||
640 | $ret[$this->literalLanguageToString($lit)][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $prop); |
||
641 | } |
||
642 | } |
||
643 | ksort($ret); |
||
644 | return $ret; |
||
645 | } |
||
646 | |||
647 | /** |
||
648 | * Gets the values for the property in question in all other languages than the ui language. |
||
649 | * @param string $property |
||
650 | */ |
||
651 | public function getAllLabels($property) |
||
652 | { |
||
653 | $labels = array(); |
||
654 | // shortening property labels if possible, EasyRdf requires full URIs to be in angle brackets |
||
655 | $property = (EasyRdf\RdfNamespace::shorten($property) !== null) ? EasyRdf\RdfNamespace::shorten($property) : "<$property>"; |
||
656 | foreach ($this->resource->allLiterals($property) as $lit) { |
||
657 | $labels[Punic\Language::getName($lit->getLang(), $this->getEnvLang())][] = new ConceptPropertyValueLiteral($this->model, $this->vocab, $this->resource, $lit, $property); |
||
658 | } |
||
659 | ksort($labels); |
||
660 | return $labels; |
||
661 | } |
||
662 | } |
||
663 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.