Passed
Branch extract-store (f24e42)
by Konrad
04:37
created

TurtleSerializer::getPName()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8.4953

Importance

Changes 0
Metric Value
cc 7
eloc 15
c 0
b 0
f 0
nc 7
nop 2
dl 0
loc 31
ccs 11
cts 16
cp 0.6875
crap 8.4953
rs 8.8333
1
<?php
2
3
/*
4
 * This file is part of the sweetrdf/InMemoryStoreSqlite package and licensed under
5
 * the terms of the GPL-3 license.
6
 *
7
 * (c) Konrad Abicht <[email protected]>
8
 * (c) Benjamin Nowack
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace sweetrdf\InMemoryStoreSqlite\Serializer;
15
16
use sweetrdf\InMemoryStoreSqlite\NamespaceHelper;
17
use function sweetrdf\InMemoryStoreSqlite\splitURI;
18
19
class TurtleSerializer
20
{
21
    private array $ns = [];
22
    private array $nsp = [];
23
    private int $ns_count = 0;
24
25 23
    public function __construct()
26
    {
27 23
        $this->qualifier = ['rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf'];
0 ignored issues
show
Bug Best Practice introduced by
The property qualifier does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
28
29 23
        $rdf = NamespaceHelper::NAMESPACE_RDF;
30 23
        $this->nsp = [$rdf => 'rdf'];
31 23
        $this->used_ns = [$rdf];
0 ignored issues
show
Bug Best Practice introduced by
The property used_ns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
32 23
        $this->ns = ['rdf' => $rdf];
33 23
    }
34
35
    public function getSerializedTriples($triples, $raw = 0)
36
    {
37
        $index = $this->getSimpleIndex($triples, 0);
38
39
        return $this->getSerializedIndex($index, $raw);
40
    }
41
42
    public function getSimpleIndex($triples, $flatten_objects = 1, $vals = '')
43
    {
44
        $r = [];
45
        foreach ($triples as $t) {
46
            $skip_t = 0;
47
            foreach (['s', 'p', 'o'] as $term) {
48
                $$term = $t[$term];
49
                /* template var */
50
                if (isset($t[$term.'_type']) && ('var' == $t[$term.'_type'])) {
51
                    $val = isset($vals[$$term]) ? $vals[$$term] : '';
52
                    $skip_t = isset($vals[$$term]) ? $skip_t : 1;
53
                    $type = '';
54
                    $type = !$type && isset($vals[$$term.' type']) ? $vals[$$term.' type'] : $type;
55
                    $type = !$type && preg_match('/^\_\:/', $val) ? 'bnode' : $type;
56
                    if ('o' == $term) {
57
                        $type = !$type && (preg_match('/\s/s', $val) || !preg_match('/\:/', $val)) ? 'literal' : $type;
58
                        $type = !$type && !preg_match('/[\/]/', $val) ? 'literal' : $type;
59
                    }
60
                    $type = !$type ? 'uri' : $type;
61
                    $t[$term.'_type'] = $type;
62
                    $$term = $val;
63
                }
64
            }
65
            if ($skip_t) {
66
                continue;
67
            }
68
            if (!isset($r[$s])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $s seems to be never defined.
Loading history...
69
                $r[$s] = [];
70
            }
71
            if (!isset($r[$s][$p])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $p seems to be never defined.
Loading history...
72
                $r[$s][$p] = [];
73
            }
74
            if ($flatten_objects) {
75
                if (!\in_array($o, $r[$s][$p])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.
Loading history...
76
                    $r[$s][$p][] = $o;
77
                }
78
            } else {
79
                $o = ['value' => $o];
80
                foreach (['lang', 'type', 'datatype'] as $suffix) {
81
                    if (isset($t['o_'.$suffix]) && $t['o_'.$suffix]) {
82
                        $o[$suffix] = $t['o_'.$suffix];
83
                    } elseif (isset($t['o '.$suffix]) && $t['o '.$suffix]) {
84
                        $o[$suffix] = $t['o '.$suffix];
85
                    }
86
                }
87
                if (!\in_array($o, $r[$s][$p])) {
88
                    $r[$s][$p][] = $o;
89
                }
90
            }
91
        }
92
93
        return $r;
94
    }
95
96
    /**
97
     * @todo port to NamespaceHelper
98
     */
99 23
    public function getPNameNamespace($v, $connector = ':')
100
    {
101 23
        $re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]+)$/i';
102 23
        if (':' != $connector) {
103
            $connectors = ['\:', '\-', '\_', '\.'];
104
            $chars = implode('', array_diff($connectors, [$connector]));
105
            $re = '/^([a-z0-9'.$chars.']+)\\'.$connector.'([a-z0-9\_\-\.\%]+)$/i';
106
        }
107 23
        if (!preg_match($re, $v, $m)) {
108 23
            return 0;
109
        }
110
        if (!isset($this->ns[$m[1]])) {
111
            return 0;
112
        }
113
114
        return $this->ns[$m[1]];
115
    }
116
117
    /**
118
     * @todo port to NamespaceHelper
119
     */
120 23
    public function getPName($v, $connector = ':')
121
    {
122
        /* is already a pname */
123 23
        $ns = $this->getPNameNamespace($v, $connector);
124 23
        if ($ns) {
125
            if (!\in_array($ns, $this->used_ns)) {
126
                $this->used_ns[] = $ns;
0 ignored issues
show
Bug Best Practice introduced by
The property used_ns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
127
            }
128
129
            return $v;
130
        }
131
        /* new pname */
132 23
        $parts = splitURI($v);
133 23
        if ($parts) {
134
            /* known prefix */
135 23
            foreach ($this->ns as $prefix => $ns) {
136 23
                if ($parts[0] == $ns) {
137 23
                    if (!\in_array($ns, $this->used_ns)) {
138
                        $this->used_ns[] = $ns;
139
                    }
140
141 23
                    return $prefix.$connector.$parts[1];
142
                }
143
            }
144
            /* new prefix */
145 23
            $prefix = $this->getPrefix($parts[0]);
146
147 23
            return $prefix.$connector.$parts[1];
148
        }
149
150
        return $v;
151
    }
152
153
    /**
154
     * @todo port to NamespaceHelper
155
     */
156 23
    public function getPrefix($ns)
157
    {
158 23
        if (!isset($this->nsp[$ns])) {
159 23
            $this->ns['ns'.$this->ns_count] = $ns;
160 23
            $this->nsp[$ns] = 'ns'.$this->ns_count;
161 23
            ++$this->ns_count;
162
        }
163 23
        if (!\in_array($ns, $this->used_ns)) {
164 23
            $this->used_ns[] = $ns;
0 ignored issues
show
Bug Best Practice introduced by
The property used_ns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
165
        }
166
167 23
        return $this->nsp[$ns];
168
    }
169
170 23
    public function getTerm($v, $term = '', $qualifier = '')
171
    {
172 23
        if (!\is_array($v)) {
173 23
            if (preg_match('/^\_\:/', $v)) {
174 23
                return $v;
175
            }
176 23
            if (('p' === $term) && ($pn = $this->getPName($v))) {
177 23
                return $pn;
178
            }
179
            if (
180 23
                ('o' === $term)
181 23
                && \in_array($qualifier, $this->qualifier)
182 23
                && ($pn = $this->getPName($v))
183
            ) {
184 23
                return $pn;
185
            }
186 23
            if (preg_match('/^[a-z0-9]+\:[^\s]*$/isu', $v)) {
187 23
                return '<'.$v.'>';
188
            }
189
190 23
            return $this->getTerm(['type' => 'literal', 'value' => $v], $term, $qualifier);
191
        }
192 23
        if (!isset($v['type']) || ('literal' != $v['type'])) {
193
            return $this->getTerm($v['value'], $term, $qualifier);
194
        }
195
        /* literal */
196 23
        $quot = '"';
197 23
        if (false !== preg_match('/\"/', $v['value'])) {
198 23
            $quot = "'";
199 23
            if (false !== preg_match('/\'/', $v['value']) || false !== preg_match('/[\x0d\x0a]/', $v['value'])) {
200 23
                $quot = '"""';
201
                if (
202 23
                    false !== preg_match('/\"\"\"/', $v['value'])
203
                    || false !== preg_match('/\"$/', $v['value'])
204 23
                    || false !== preg_match('/^\"/', $v['value'])
205
                ) {
206 23
                    $quot = "'''";
207 23
                    $v['value'] = preg_replace("/'$/", "' ", $v['value']);
208 23
                    $v['value'] = preg_replace("/^'/", " '", $v['value']);
209 23
                    $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
210
                }
211
            }
212
        }
213 23
        if ((1 == \strlen($quot)) && false !== preg_match('/[\x0d\x0a]/', $v['value'])) {
214
            $quot = $quot.$quot.$quot;
215
        }
216 23
        $suffix = isset($v['lang']) && $v['lang'] ? '@'.$v['lang'] : '';
217 23
        $suffix = isset($v['datatype']) && $v['datatype'] ? '^^'.$this->getTerm($v['datatype'], 'dt') : $suffix;
218
219 23
        return $quot.$v['value'].$quot.$suffix;
220
    }
221
222 23
    public function getHead()
223
    {
224 23
        $r = '';
225 23
        $nl = "\n";
226 23
        foreach ($this->used_ns as $v) {
227 23
            $r .= $r ? $nl : '';
228 23
            foreach ($this->ns as $prefix => $ns) {
229 23
                if ($ns != $v) {
230 23
                    continue;
231
                }
232 23
                $r .= '@prefix '.$prefix.': <'.$v.'> .';
233 23
                break;
234
            }
235
        }
236
237 23
        return $r;
238
    }
239
240 23
    public function getSerializedIndex($index, $raw = 0)
241
    {
242 23
        $r = '';
243 23
        $nl = "\n";
244 23
        foreach ($index as $s => $ps) {
245 23
            $r .= $r ? ' .'.$nl.$nl : '';
246 23
            $s = $this->getTerm($s, 's');
247 23
            $r .= $s;
248 23
            $first_p = 1;
249 23
            foreach ($ps as $p => $os) {
250 23
                if (!$os) {
251
                    continue;
252
                }
253 23
                $p = $this->getTerm($p, 'p');
254 23
                $r .= $first_p ? ' ' : ' ;'.$nl.str_pad('', \strlen($s) + 1);
255 23
                $r .= $p;
256 23
                $first_o = 1;
257 23
                if (!\is_array($os)) {/* single literal o */
258
                    $os = [['value' => $os, 'type' => 'literal']];
259
                }
260 23
                foreach ($os as $o) {
261 23
                    $r .= $first_o ? ' ' : ' ,'.$nl.str_pad('', \strlen($s) + \strlen($p) + 2);
262 23
                    $o = $this->getTerm($o, 'o', $p);
263 23
                    $r .= $o;
264 23
                    $first_o = 0;
265
                }
266 23
                $first_p = 0;
267
            }
268
        }
269 23
        $r .= $r ? ' .' : '';
270 23
        if ($raw) {
271
            return $r;
272
        }
273
274 23
        return $r ? $this->getHead().$nl.$nl.$r : '';
275
    }
276
}
277