Completed
Push — master ( dc909a...874630 )
by Jakob
02:14
created

Mapper::cleanString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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 View Code Duplication
                        if (isset($mapping['unique'])) {
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...
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 View Code Duplication
                        if (isset($mapping['unique'])) {
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...
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)
178
    {
179
        try {
180
            $rdf = \EasyRdf_Graph::newAndLoad($url, $format);
181
            return $rdf->resource($uri ? $uri : $url);
182
        } catch (\Exception $e) {
183
            return;
184
        }
185
    }
186
187
    /**
188
     * Get a list of RDF object URIs.
189
     */
190
    public static function getURIs(\EasyRDF_Resource $subject, $predicate, $pattern = null)
191
    {
192
        $uris = [];
193
        foreach ($subject->allResources($predicate) as $object) {
194
            if (!$object->isBNode()) {
195
                $object = $object->getUri();
196
                if (!$pattern or preg_match($pattern, $object)) {
197
                    $uris[] = $object;
198
                }
199
            }
200
        }
201
        return $uris;
202
    }
203
}
204