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

TurtleSerializer::getSerializedIndex()   C

Complexity

Conditions 12
Paths 174

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 12.1974

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 26
c 1
b 0
f 0
nc 174
nop 2
dl 0
loc 35
ccs 24
cts 27
cp 0.8889
crap 12.1974
rs 6.35

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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