1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SMW\Query\Language; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Description of a collection of many descriptions, all of which |
7
|
|
|
* must be satisfied (AND, conjunction). |
8
|
|
|
* |
9
|
|
|
* Corresponds to conjunction in OWL and SPARQL. Not available in RDFS. |
10
|
|
|
* |
11
|
|
|
* @license GNU GPL v2+ |
12
|
|
|
* @since 1.6 |
13
|
|
|
* |
14
|
|
|
* @author Markus Krötzsch |
15
|
|
|
*/ |
16
|
|
|
class Conjunction extends Description { |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* @var Description[] |
20
|
|
|
*/ |
21
|
|
|
protected $descriptions = array(); |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @since 1.6 |
25
|
|
|
* |
26
|
|
|
* @param array $descriptions |
27
|
|
|
*/ |
28
|
84 |
|
public function __construct( array $descriptions = array() ) { |
29
|
84 |
|
foreach ( $descriptions as $description ) { |
30
|
82 |
|
$this->addDescription( $description ); |
31
|
|
|
} |
32
|
84 |
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @see Description::getFingerprint |
36
|
|
|
* @since 2.5 |
37
|
|
|
* |
38
|
|
|
* @return string |
39
|
|
|
*/ |
40
|
83 |
|
public function getFingerprint() { |
41
|
|
|
|
42
|
83 |
|
if ( $this->fingerprint !== null ) { |
43
|
78 |
|
return $this->fingerprint; |
44
|
|
|
} |
45
|
|
|
|
46
|
83 |
|
$fingerprint = array(); |
47
|
|
|
|
48
|
|
|
// Filter equal signatures |
49
|
83 |
|
foreach ( $this->descriptions as $description ) { |
50
|
83 |
|
$fingerprint[$description->getFingerprint()] = true; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
// Sorting to generate a constant fingerprint independent of its |
54
|
|
|
// position within a conjunction ( [Foo]][[Bar]], [[Bar]][[Foo]]) |
|
|
|
|
55
|
83 |
|
ksort( $fingerprint ); |
56
|
|
|
|
57
|
83 |
|
return $this->fingerprint = 'C:' . md5( implode( '|', array_keys( $fingerprint ) ) ); |
58
|
|
|
} |
59
|
|
|
|
60
|
79 |
|
public function getDescriptions() { |
61
|
79 |
|
return $this->descriptions; |
62
|
|
|
} |
63
|
|
|
|
64
|
83 |
|
public function addDescription( Description $description ) { |
65
|
|
|
|
66
|
83 |
|
$this->fingerprint = null; |
67
|
|
|
|
68
|
83 |
|
if ( ! ( $description instanceof ThingDescription ) ) { |
69
|
83 |
|
if ( $description instanceof Conjunction ) { // absorb sub-conjunctions |
70
|
4 |
|
foreach ( $description->getDescriptions() as $subdesc ) { |
71
|
4 |
|
$this->descriptions[$subdesc->getFingerprint()] = $subdesc; |
72
|
|
|
} |
73
|
|
|
} else { |
74
|
83 |
|
$this->descriptions[$description->getFingerprint()] = $description; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
// move print descriptions downwards |
78
|
|
|
///TODO: This may not be a good solution, since it does modify $description and since it does not react to future changes |
79
|
83 |
|
$this->m_printreqs = array_merge( $this->m_printreqs, $description->getPrintRequests() ); |
80
|
83 |
|
$description->setPrintRequests( array() ); |
81
|
|
|
} |
82
|
|
|
|
83
|
83 |
|
$fingerprint = $this->getFingerprint(); |
84
|
|
|
|
85
|
83 |
|
foreach ( $this->descriptions as $description ) { |
86
|
83 |
|
$description->setMembership( $fingerprint ); |
87
|
|
|
} |
88
|
83 |
|
} |
89
|
|
|
|
90
|
32 |
|
public function getQueryString( $asvalue = false ) { |
91
|
32 |
|
$result = ''; |
92
|
|
|
|
93
|
32 |
|
foreach ( $this->descriptions as $desc ) { |
94
|
32 |
|
$result .= ( $result ? ' ' : '' ) . $desc->getQueryString( false ); |
95
|
|
|
} |
96
|
|
|
|
97
|
32 |
|
if ( $result === '' ) { |
98
|
|
|
return $asvalue ? '+' : ''; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
// <q> not needed for stand-alone conjunctions (AND binds stronger than OR) |
102
|
32 |
|
return $asvalue ? " <q>{$result}</q> " : $result; |
103
|
|
|
} |
104
|
|
|
|
105
|
2 |
|
public function isSingleton() { |
106
|
2 |
|
foreach ( $this->descriptions as $d ) { |
107
|
2 |
|
if ( $d->isSingleton() ) { |
108
|
2 |
|
return true; |
109
|
|
|
} |
110
|
|
|
} |
111
|
1 |
|
return false; |
112
|
|
|
} |
113
|
|
|
|
114
|
26 |
|
public function getSize() { |
115
|
26 |
|
$size = 0; |
116
|
|
|
|
117
|
26 |
|
foreach ( $this->descriptions as $desc ) { |
118
|
26 |
|
$size += $desc->getSize(); |
119
|
|
|
} |
120
|
|
|
|
121
|
26 |
|
return $size; |
122
|
|
|
} |
123
|
|
|
|
124
|
26 |
|
public function getDepth() { |
125
|
26 |
|
$depth = 0; |
126
|
|
|
|
127
|
26 |
|
foreach ( $this->descriptions as $desc ) { |
128
|
26 |
|
$depth = max( $depth, $desc->getDepth() ); |
129
|
|
|
} |
130
|
|
|
|
131
|
26 |
|
return $depth; |
132
|
|
|
} |
133
|
|
|
|
134
|
4 |
|
public function getQueryFeatures() { |
135
|
4 |
|
$result = SMW_CONJUNCTION_QUERY; |
136
|
|
|
|
137
|
4 |
|
foreach ( $this->descriptions as $desc ) { |
138
|
4 |
|
$result = $result | $desc->getQueryFeatures(); |
139
|
|
|
} |
140
|
|
|
|
141
|
4 |
|
return $result; |
142
|
|
|
} |
143
|
|
|
|
144
|
73 |
|
public function prune( &$maxsize, &$maxdepth, &$log ) { |
145
|
73 |
|
if ( $maxsize <= 0 ) { |
146
|
1 |
|
$log[] = $this->getQueryString(); |
147
|
1 |
|
return new ThingDescription(); |
148
|
|
|
} |
149
|
|
|
|
150
|
73 |
|
$prunelog = array(); |
151
|
73 |
|
$newdepth = $maxdepth; |
152
|
73 |
|
$result = new Conjunction(); |
153
|
|
|
|
154
|
73 |
|
foreach ( $this->descriptions as $desc ) { |
155
|
73 |
|
$restdepth = $maxdepth; |
156
|
73 |
|
$result->addDescription( $desc->prune( $maxsize, $restdepth, $prunelog ) ); |
157
|
73 |
|
$newdepth = min( $newdepth, $restdepth ); |
158
|
|
|
} |
159
|
|
|
|
160
|
73 |
|
if ( count( $result->getDescriptions() ) > 0 ) { |
161
|
73 |
|
$log = array_merge( $log, $prunelog ); |
162
|
73 |
|
$maxdepth = $newdepth; |
163
|
|
|
|
164
|
73 |
|
if ( count( $result->getDescriptions() ) == 1 ) { // simplify unary conjunctions! |
165
|
3 |
|
$descriptions = $result->getDescriptions(); |
166
|
3 |
|
$result = array_shift( $descriptions ); |
167
|
|
|
} |
168
|
|
|
|
169
|
73 |
|
$result->setPrintRequests( $this->getPrintRequests() ); |
170
|
|
|
|
171
|
73 |
|
return $result; |
172
|
|
|
} else { |
173
|
|
|
$log[] = $this->getQueryString(); |
174
|
|
|
|
175
|
|
|
$result = new ThingDescription(); |
176
|
|
|
$result->setPrintRequests( $this->getPrintRequests() ); |
177
|
|
|
|
178
|
|
|
return $result; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.