Mapper::getURIs()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 7
c 0
b 0
f 0
nc 4
nop 3
dl 0
loc 12
rs 9.6111
1
<?php declare(strict_types = 1);
2
3
namespace JSKOS\RDF;
4
5
use JSKOS\Resource;
6
7
/**
8
 * Mapper maps RDF data to JSKOS based on a set of mapping rules.
9
 *
10
 * The rules define which RDF properties will be used to fill which JSKOS
11
 * fields. The rules further include two special keys:
12
 *
13
 * `_ns` provides a list of RDF prefixes and namespace. Namespaces are
14
 * applied *globally* for all mapping instances.
15
 *
16
 * `_defaultLanguage` defines the default language ("und" if not set).
17
 * This field can be also be used at individual mappings.
18
 *
19
 * RDF data must be provided as EasyRdf_Resource.
20
 *
21
 * @license LGPL
22
 * @author Jakob Voß
23
 */
24
class Mapper
25
{
26
    /**
27
     * The mapping rules.
28
     */
29
    protected $rules;
30
31
    /**
32
     * Default language for literals without language tag.
33
     */
34
    protected $defaultLanguage;
35
36
    /**
37
     * Allowed JSKOS class names
38
     */
39
    public static $JSKOSClasses = [
40
        'Concept',
41
        'ConceptScheme',
42
        'ConceptType',
43
        'ConceptBundle',
44
        'Concordance',
45
        'Mapping'
46
    ];
47
48
    /**
49
     * Create a new mapping based on rules.
50
     */
51
    public function __construct(array $rules = null)
52
    {
53
        if ($rules === null) {
54
            $rules = json_decode(file_get_contents(__DIR__."/rdf2jskos.json"), true);
55
        }
56
57
        if (isset($rules['_ns'])) {
58
            foreach ($rules['_ns'] as $prefix => $namespace) {
59
                # TODO: warn if prefix is already defined with different namespace!
60
                \EasyRdf_Namespace::set($prefix, $namespace);
61
            }
62
        }
63
64
        if (isset($rules['_defaultLanguage'])) {
65
            $this->defaultLanguage = $rules['_defaultLanguage'];
66
        } else {
67
            $this->defaultLanguage = 'und';
68
        }
69
70
        foreach ($rules as $field => $config) {
71
            if (substr($field, 0, 1) != '_') {
72
                $this->rules[$field] = $config;
73
            }
74
        }
75
    }
76
77
    /**
78
     * Apply mapping via extraction of data from an RDF resource and add
79
     * resulting data to a JSKOS Resource.
80
     *
81
     * @param EasyRdf_Resource $rdf
0 ignored issues
show
Bug introduced by
The type JSKOS\RDF\EasyRdf_Resource was not found. Did you mean EasyRdf_Resource? If so, make sure to prefix the type with \.
Loading history...
82
     * @param PrettyJsonSerializable $jskos
0 ignored issues
show
Bug introduced by
The type JSKOS\RDF\PrettyJsonSerializable was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
83
     */
84
    public function applyAtResource(\EasyRdf_Resource $rdf, Resource $jskos)
85
    {
86
        #error_log($rdf->getGraph()->dump('text'));
87
        #error_log(print_r($this->rules,1));
88
89
        foreach ($this->rules as $property => $mapping) {
90
            $type = $mapping['type'];
91
            if (isset($mapping['jskos']) && in_array($mapping['jskos'], static::$JSKOSClasses)) {
92
                $class = '\JSKOS\\'.$mapping['jskos'];
93
            } else {
94
                $class = null;
95
            }
96
97
            foreach ($mapping['properties'] as $rdfProperty) {
98
                if ($type == 'URI') {
99
                    foreach (static::getURIs($rdf, $rdfProperty) as $uri) {
100
                        if (isset($class)) {
101
                            $uri = new $class(['uri'=>$uri]);
102
                        }
103
                        if (isset($mapping['unique'])) {
104
                            $jskos->$property = $uri;
105
                        } else {
106
                            if (empty($jskos->$property)) {
107
                                $jskos->$property = [];
108
                            }
109
                            $jskos->$property[] = $uri;
110
                        }
111
                    }
112
                } elseif ($type == 'literal') {
113
                    foreach ($rdf->allLiterals($rdfProperty) as $literal) {
114
                        $value = static::cleanString($literal);
115
                        if (!isset($value)) {
116
                            continue;
117
                        }
118
119
                        if ($literal->getLang()) {
120
                            $language = $literal->getLang();
121
                        } elseif (isset($mapping['_defaultLanguage'])) {
122
                            $language = $mapping['_defaultLanguage'];
123
                        } else {
124
                            $language = $this->defaultLanguage;
125
                        }
126
127
                        $languageMap = isset($jskos->$property) ? $jskos->$property : [];
128
129
                        if (isset($mapping['unique'])) {
130
                            $languageMap[$language] = $value;
131
                        } else {
132
                            $list = $languageMap[$language] ?? [];
133
                            $list[] = $value;
134
                            $languageMap[$language] = $list;
135
                        }
136
137
                        $jskos->$property = $languageMap;
138
                    }
139
                } elseif ($type == 'plain') {
140
                    foreach ($rdf->allLiterals($rdfProperty) as $literal) {
141
                        $value = static::cleanString($literal);
142
                        if (!isset($value)) {
143
                            continue;
144
                        }
145
146
                        if (isset($mapping['pattern']) && !preg_match($mapping['pattern'], $value)) {
147
                            continue;
148
                        }
149
                        if (isset($mapping['unique'])) {
150
                            $jskos->$property = $value;
151
                        } else {
152
                            if (empty($jskos->$property)) {
153
                                $jskos->$property = [$value];
154
                            } else {
155
                                $jskos->$property[] = $value;
156
                            }
157
                        }
158
                    }
159
                }
160
            }
161
        }
162
    }
163
164
    /**
165
     * Clean up a string value by trimming whitespace and mapping empty strings to null.
166
     */
167
    public static function cleanString($string)
168
    {
169
        $string = trim((string)$string);
170
        return $string !== "" ? $string : null;
171
    }
172
173
    /**
174
     * Silently try to load RDF from an URL.
175
     * @return EasyRdf_Resource|null
176
     */
177
    public static function loadRDF($url, $uri = null, $format = null, $forceHttp = false)
178
    {
179
        try {
180
            $rdf = \EasyRdf_Graph::newAndLoad($url, $format);
181
            if ($forceHttp) {
182
                $turtle = $rdf->serialise('turtle');
183
                $turtle = str_replace("<https://","<http://", $turtle);
184
                $graph = new \EasyRdf_Graph();
185
                $graph->parse($turtle, 'turtle');
186
                $rdf = $graph;
187
            }
188
            return $rdf->resource($uri ? $uri : $url);
189
        } catch (\Exception $e) {
190
            return;
191
        }
192
    }
193
194
    /**
195
     * Get a list of RDF object URIs.
196
     */
197
    public static function getURIs(\EasyRDF_Resource $subject, $predicate, $pattern = null)
198
    {
199
        $uris = [];
200
        foreach ($subject->allResources($predicate) as $object) {
201
            if (!$object->isBNode()) {
202
                $object = $object->getUri();
203
                if (!$pattern or preg_match($pattern, $object)) {
204
                    $uris[] = $object;
205
                }
206
            }
207
        }
208
        return $uris;
209
    }
210
}
211