Passed
Push — master ( 4e8b13...a3a48f )
by Konrad
04:16
created

SPARQLPlusParser   F

Complexity

Total Complexity 63

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Test Coverage

Coverage 88.54%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 98
c 1
b 0
f 0
dl 0
loc 197
ccs 85
cts 96
cp 0.8854
rs 3.36
wmc 63

7 Methods

Rating   Name   Duplication   Size   Complexity  
B xResultVar() 0 21 11
B xSolutionModifier() 0 14 8
C xDeleteQuery() 0 44 15
A xQuery() 0 11 4
A xLoadQuery() 0 12 4
C xInsertQuery() 0 44 14
B xGroupClause() 0 23 7

How to fix   Complexity   

Complex Class

Complex classes like SPARQLPlusParser 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.

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 SPARQLPlusParser, and based on these observations, apply Extract Interface, too.

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\Parser;
15
16
class SPARQLPlusParser extends SPARQLParser
17
{
18
    /* +1 */
19
20 94
    protected function xQuery($v)
21
    {
22 94
        list($r, $v) = $this->xPrologue($v);
23 94
        foreach (['Select', 'Construct', 'Describe', 'Ask', 'Insert', 'Delete', 'Load'] as $type) {
24 94
            $m = 'x'.$type.'Query';
25 94
            if ((list($r, $v) = $this->$m($v)) && $r) {
26 93
                return [$r, $v];
27
            }
28
        }
29
30 4
        return [0, $v];
31
    }
32
33
    /* +3 */
34
35 46
    protected function xResultVar($v)
36
    {
37 46
        $aggregate = '';
38
        /* aggregate */
39 46
        if ($sub_r = $this->x('\(?(AVG|COUNT|MAX|MIN|SUM)\s*\(\s*([^\)]+)\)\s+AS\s+([^\s\)]+)\)?', $v)) {
40 16
            $aggregate = $sub_r[1];
41 16
            $result_var = $sub_r[3];
42 16
            $v = $sub_r[2].$sub_r[4];
43
        }
44 46
        if ($sub_r && (list($sub_r, $sub_v) = $this->xVar($result_var)) && $sub_r) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result_var does not seem to be defined for all execution paths leading up to this point.
Loading history...
45 16
            $result_var = $sub_r['value'];
46
        }
47
        /* * or var */
48 46
        if ((list($sub_r, $sub_v) = $this->x('\*', $v)) && $sub_r) {
49 2
            return [['var' => '*', 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''], $sub_v];
50
        }
51 46
        if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
52 42
            return [['var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''], $sub_v];
53
        }
54
55 46
        return [0, $v];
56
    }
57
58
    /* +4 */
59
60 4
    protected function xLoadQuery($v)
61
    {
62 4
        if ($sub_r = $this->x('LOAD\s+', $v)) {
63
            $sub_v = $sub_r[1];
64
            if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
65
                $r = ['type' => 'load', 'url' => $sub_r, 'target_graph' => ''];
66
67
                return [$r, $sub_v];
68
            }
69
        }
70
71 4
        return [0, $v];
72
    }
73
74
    /* +5 */
75
76 90
    protected function xInsertQuery($v)
77
    {
78 90
        if ($sub_r = $this->x('INSERT\s+', $v)) {
79 90
            $r = [
80
                'type' => 'insert',
81
                'dataset' => [],
82
            ];
83 90
            $sub_v = $sub_r[1];
84
            /* target */
85 90
            if ($sub_r = $this->x('INTO\s+', $sub_v)) {
86 90
                $sub_v = $sub_r[1];
87 90
                if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
88 90
                    $r['target_graph'] = $sub_r;
89
                    /* CONSTRUCT keyword, optional */
90 90
                    if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
91 1
                        $sub_v = $sub_r[1];
92
                    }
93
                    /* construct template */
94 90
                    if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && \is_array($sub_r)) {
95 89
                        $r['construct_triples'] = $sub_r;
96
                    } else {
97 1
                        $this->logger->error('Construct Template not found');
98
99 1
                        return [0, $v];
100
                    }
101
                    /* dataset */
102 89
                    while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
103
                        $r['dataset'][] = $sub_r;
104
                    }
105
                    /* where */
106 89
                    if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
107
                        $r['pattern'] = $sub_r;
108
                    }
109
                    /* solution modifier */
110 89
                    if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
111
                        $r = array_merge($r, $sub_r);
112
                    }
113
114 89
                    return [$r, $sub_v];
115
                }
116
            }
117
        }
118
119 11
        return [0, $v];
120
    }
121
122
    /* +6 */
123
124 12
    protected function xDeleteQuery($v): array
125
    {
126 12
        if ($sub_r = $this->x('DELETE\s+', $v)) {
127 8
            $r = [
128
                'type' => 'delete',
129
                'target_graphs' => [],
130
            ];
131 8
            $sub_v = $sub_r[1];
132
            /* target */
133
            do {
134 8
                $proceed = false;
135 8
                if ($sub_r = $this->x('FROM\s+', $sub_v)) {
136 5
                    $sub_v = $sub_r[1];
137 5
                    if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
138 5
                        $r['target_graphs'][] = $sub_r;
139 5
                        $proceed = 1;
140
                    }
141
                }
142 8
            } while ($proceed);
0 ignored issues
show
Bug Best Practice introduced by
The expression $proceed of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
143
            /* CONSTRUCT keyword, optional */
144 8
            if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
145
                $sub_v = $sub_r[1];
146
            }
147
            /* construct template */
148 8
            if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && \is_array($sub_r)) {
149 4
                $r['construct_triples'] = $sub_r;
150
                /* dataset */
151 4
                while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
152
                    $r['dataset'][] = $sub_r;
153
                }
154
                /* where */
155 4
                if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
156 2
                    $r['pattern'] = $sub_r;
157
                }
158
                /* solution modifier */
159 4
                if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
160
                    $r = array_merge($r, $sub_r);
161
                }
162
            }
163
164 8
            return [$r, $sub_v];
165
        }
166
167 4
        return [0, $v];
168
    }
169
170
    /* +7 */
171
172 93
    protected function xSolutionModifier($v): array
173
    {
174 93
        $r = [];
175 93
        if ((list($sub_r, $sub_v) = $this->xGroupClause($v)) && $sub_r) {
176 7
            $r['group_infos'] = $sub_r;
177
        }
178 93
        if ((list($sub_r, $sub_v) = $this->xOrderClause($sub_v)) && $sub_r) {
179 4
            $r['order_infos'] = $sub_r;
180
        }
181 93
        while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
182 3
            $r = array_merge($r, $sub_r);
183
        }
184
185 93
        return ($v == $sub_v) ? [0, $v] : [$r, $sub_v];
186
    }
187
188
    /* +8 */
189
190 93
    protected function xGroupClause($v): array
191
    {
192 93
        if ($sub_r = $this->x('GROUP BY\s+', $v)) {
193 8
            $sub_v = $sub_r[1];
194 8
            $r = [];
195
            do {
196 8
                $proceed = 0;
197 8
                if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
198 7
                    $r[] = $sub_r;
199 7
                    $proceed = 1;
200 7
                    if ($sub_r = $this->x('\,', $sub_v)) {
201
                        $sub_v = $sub_r[1];
202
                    }
203
                }
204 8
            } while ($proceed);
205 8
            if (\count($r)) {
206 7
                return [$r, $sub_v];
207
            } else {
208 1
                $this->logger->error('No columns specified in GROUP BY clause.');
209
            }
210
        }
211
212 92
        return [0, $v];
213
    }
214
}
215