1 |
<? |
2 |
|
3 |
// =========================================================== |
4 |
class AbstractQueryStatement { |
5 |
|
6 |
var $sql_in_base; |
7 |
var $sql_out_build; |
8 |
var $sql_out_ready; |
9 |
|
10 |
var $bool_built; |
11 |
var $bool_ready_good; |
12 |
var $bool_hasToBeMapped; |
13 |
|
14 |
var $criterias; |
15 |
var $orders; |
16 |
var $limits; |
17 |
|
18 |
var $map; |
19 |
var $data; |
20 |
var $crud; |
21 |
|
22 |
|
23 |
|
24 |
// ---------------------------------------------------- |
25 |
function AbstractQueryStatement($map = array()) { |
26 |
|
27 |
$this->sql_in_base = ''; |
28 |
$this->sql_out_build = ''; |
29 |
$this->sql_out_ready = ''; |
30 |
|
31 |
$this->bool_built = 0; |
32 |
$this->bool_ready_good = 0; |
33 |
$this->bool_hasToBeMapped = 0; |
34 |
|
35 |
$this->criterias = array(); |
36 |
$this->orders = array(); |
37 |
$this->limits = array(); |
38 |
|
39 |
$this->map = array(); |
40 |
$this->data = array(); |
41 |
$this->crud = ''; |
42 |
/* |
43 |
if (count($map)) { |
44 |
$this->setMap($map); |
45 |
} |
46 |
*/ |
47 |
} |
48 |
|
49 |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
50 |
// getter- and setter-methods |
51 |
|
52 |
function setQuery($sql) { |
53 |
|
54 |
// strip bounding whitespaces |
55 |
$sql = trim($sql); |
56 |
|
57 |
// strip trailing semicolon, if present |
58 |
if (substr($sql, -1) == ';') { |
59 |
$sql = substr($sql, 0, -1); |
60 |
} |
61 |
|
62 |
// set sql-string locally |
63 |
$this->sql_in_base = $sql; |
64 |
} |
65 |
|
66 |
function setMap($map = array()) { |
67 |
if (count($map)) { |
68 |
$this->bool_hasToBeMapped = 1; |
69 |
|
70 |
// determine type of map, TODO: don't pass PDLAttributes in here any more!!! |
71 |
reset($map); |
72 |
if (strtolower(get_class(current($map))) == 'pdlmodelattribute') { |
73 |
while($attribute =& current($map)) { |
74 |
$attributename = $attribute->name; |
75 |
$mapname = $attribute->map_name; |
76 |
print $attributename . "," . $mapname . "<br>"; |
77 |
$map_new[$attributename] = $mapname; |
78 |
next($map); |
79 |
} |
80 |
$map = $map_new; |
81 |
} |
82 |
$this->map = $map; |
83 |
} else { |
84 |
$this->bool_hasToBeMapped = 0; |
85 |
} |
86 |
} |
87 |
|
88 |
function setData($data = array()) { |
89 |
if (count($data)) { |
90 |
$this->bool_data_set = 1; |
91 |
$this->data = $data; |
92 |
} else { |
93 |
$this->bool_data_set = 0; |
94 |
} |
95 |
} |
96 |
|
97 |
function setSql_createFromMap($map) { |
98 |
$this->sql_in_base = $sql; |
99 |
$this->setMap($map); |
100 |
} |
101 |
|
102 |
function getSql() { |
103 |
if (!$this->bool_built) { $this->_build(); } |
104 |
if ($this->bool_ready_good) { |
105 |
return $this->sql_out_ready; |
106 |
} |
107 |
} |
108 |
|
109 |
|
110 |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
111 |
// processor-methods |
112 |
|
113 |
function addCriteria($argument, $logicalOperator = 'AND') { |
114 |
$criteria = array('argument' => $argument, 'logicalOperator' => $logicalOperator); |
115 |
array_push($this->criterias, $criteria); |
116 |
} |
117 |
|
118 |
function addOrder($argument, $modifier = 'ASC') { |
119 |
$order = array('argument' => $argument, 'modifier' => $modifier); |
120 |
array_push($this->orders, $order); |
121 |
} |
122 |
|
123 |
function addLimit($argument) { |
124 |
$limit = array('argument' => $argument); |
125 |
array_push($this->limits, $limit); |
126 |
} |
127 |
|
128 |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
129 |
// builder-methods |
130 |
|
131 |
function _build() { |
132 |
|
133 |
$this->sql_out_build = $this->sql_in_base; |
134 |
$bool_whereAppended = 0; |
135 |
|
136 |
|
137 |
// . . . . . . . . . . . . . . . . . . . |
138 |
// 1. determine type of query (CRUD) |
139 |
|
140 |
// determine "CRUD" (create, retrieve, update, delete) |
141 |
$this->crud = ""; |
142 |
if (stristr($this->sql_out_build, 'INSERT INTO')) { $this->crud = "C"; } |
143 |
if (stristr($this->sql_out_build, 'SELECT')) { $this->crud = "R"; } |
144 |
if (stristr($this->sql_out_build, 'UPDATE')) { $this->crud = "U"; } |
145 |
if (stristr($this->sql_out_build, 'DELETE')) { $this->crud = "D"; } |
146 |
|
147 |
|
148 |
// . . . . . . . . . . . . . . . . . . . |
149 |
// 2. decoration |
150 |
|
151 |
// --- |
152 |
// criterias |
153 |
if (count($this->criterias)) { |
154 |
|
155 |
// do we need a "WHERE"? |
156 |
// HACK: do more sophisticated, for now, no "where" can appear in data regularly!!! :-( |
157 |
if (!stristr($this->sql_out_build, 'where')) { |
158 |
$bool_whereAppended = 1; |
159 |
$this->sql_out_build .= ' WHERE '; |
160 |
} |
161 |
|
162 |
$criteriastring = ''; |
163 |
$bool_first = 1; |
164 |
reset($this->criterias); |
165 |
while($criteria = current($this->criterias)) { |
166 |
if (!$bool_first || !$bool_whereAppended) { |
167 |
$criteriastring .= ' ' . $criteria['logicalOperator'] . ' '; |
168 |
} |
169 |
$criteriastring .= $criteria['argument']; |
170 |
next($this->criterias); |
171 |
$bool_first = 0; |
172 |
} |
173 |
$this->sql_out_build .= $criteriastring; |
174 |
|
175 |
} |
176 |
|
177 |
// --- |
178 |
// orders |
179 |
if (count($this->orders)) { |
180 |
$orderstring = ' order BY '; |
181 |
$orderlist = array(); |
182 |
reset($this->orders); |
183 |
while($order = current($this->orders)) { |
184 |
array_push($orderlist, $order['argument'] . ' ' . $order['modifier']); |
185 |
next($this->orders); |
186 |
} |
187 |
$orderstring .= join($orderlist, ', '); |
188 |
$this->sql_out_build .= $orderstring; |
189 |
} |
190 |
|
191 |
// --- |
192 |
// limits |
193 |
if (count($this->limits)) { |
194 |
$limitstring = ' LIMIT '; |
195 |
$limitlist = array(); |
196 |
reset($this->limits); |
197 |
while($limit = current($this->limits)) { |
198 |
array_push($limitlist, $limit['argument']); |
199 |
next($this->limits); |
200 |
} |
201 |
$limitstring .= join($limitlist, ', '); |
202 |
$this->sql_out_build .= $limitstring; |
203 |
} |
204 |
|
205 |
|
206 |
// . . . . . . . . . . . . . . . . . . . |
207 |
// 3. mapping |
208 |
|
209 |
// if we have ... |
210 |
if ($this->bool_hasToBeMapped) { |
211 |
// ... we should check for having a map ... |
212 |
if ($this->map) { |
213 |
// ... if we do, start mapping! |
214 |
$this->_doMapping(); |
215 |
} else { |
216 |
// ... trigger an error! |
217 |
print "<font color=\"red\">In \"SqlStatement->_build()\" there is an \"bool_hasToBeMapped\", but no \"map\".</font><br>"; |
218 |
} |
219 |
|
220 |
} |
221 |
|
222 |
// finish sql-statement with semicolon |
223 |
$this->sql_out_build .= ';'; |
224 |
|
225 |
// set "ready"-statement |
226 |
$this->sql_out_ready = $this->sql_out_build; |
227 |
|
228 |
// analyze, what we've built |
229 |
$this->_analyzeOutputQuery(); |
230 |
|
231 |
} |
232 |
|
233 |
|
234 |
function _doMapping() { |
235 |
|
236 |
// HACK/TODO: |
237 |
// right now we use here "PDLModelAttribute"-objects for building our map, we should definitely not! |
238 |
// (logically yes, but not physically, since this is "lib_database_sql.php.inc", |
239 |
// which has got absolutely nothing to do with "DataStore" or "PDL" - stuff!!!) |
240 |
|
241 |
$list_attributes = array(); |
242 |
$list_columns = array(); |
243 |
$map = array(); |
244 |
$map_values = array(); |
245 |
|
246 |
// - - - - - - - - - - - - - - - - - - - - - |
247 |
// 1. build attribute-list, column-list and mapping-table |
248 |
while(list($attributename, $mapname) = each($this->map)) { |
249 |
|
250 |
// bugfix: before we continue, we should check if "$map_value" is valid, else: skip this |
251 |
if ($mapname) { |
252 |
// attribute |
253 |
array_push($list_attributes, $attributename); |
254 |
// column |
255 |
//$meta_sql = $attribute['meta_sql']; |
256 |
array_push($list_columns, $mapname); |
257 |
// map |
258 |
// was: |
259 |
// $map[$map_key] = $mapname; |
260 |
// is: |
261 |
// now we have two different kinds of maps here: |
262 |
// a) the "normal" map, which maps attribute-names to map-names (for "SELECT"s) |
263 |
$map[$attributename] = $mapname; |
264 |
// b) the "value" map, which maps attribute-names to attribute-values (for "INSERT"s or "UPDATE"s) |
265 |
if ( ($this->crud == 'C') || ($this->crud == 'U') ) { |
266 |
if (!$this->bool_data_set) { |
267 |
print "<font color=\"red\">_doMapping: \"INSERT\"- or \"UPDATE\"-query requested, but no data was set. Further object-operations will be aborted.</font><br>"; |
268 |
exit; |
269 |
} |
270 |
$map_values[$attributename] = $this->data[$attributename]; |
271 |
} |
272 |
} |
273 |
//next($this->map); |
274 |
} |
275 |
|
276 |
//print "out_build: " . $this->sql_out_build . "<br>"; |
277 |
|
278 |
// - - - - - - - - - - - - - - - - - - - - - |
279 |
// 2. build attribute- and column-list |
280 |
$wrkString = $this->sql_out_build; |
281 |
while( list($attribute_name, $map_name) = each($map) ) { |
282 |
$this->sql_out_build = str_replace(':' . $attribute_name, $map_name, $this->sql_out_build); |
283 |
} |
284 |
if ( ($this->crud == 'C') || ($this->crud == 'U') ) { |
285 |
if (count($map_values)) { |
286 |
$use_list_attributes = array_keys($map_values); |
287 |
$use_list_values = array_values($map_values); |
288 |
|
289 |
modifyArray($use_list_attributes, array('prefix' => '/(!', 'postfix' => ')(\W)/')); |
290 |
modifyArray($use_list_values, array('prefix' => "'", 'postfix' => "'\\2")); |
291 |
|
292 |
/* |
293 |
while( list($attribute_name, $attribute_value) = each($map_values) ) { |
294 |
$map_values_use['!' . $attribute_name] = $attribute_value; |
295 |
//$this->sql_out_build = str_replace('!' . $attribute_name, "'" . $attribute_value . "'", $this->sql_out_build); |
296 |
} |
297 |
*/ |
298 |
$this->sql_out_build = preg_replace($use_list_attributes, $use_list_values, $this->sql_out_build); |
299 |
|
300 |
} |
301 |
} |
302 |
|
303 |
//print "out_build: " . $this->sql_out_build . "<br>"; |
304 |
|
305 |
// out now: |
306 |
//$wrkString = ereg_replace("[[:<:]]" . $key . "[[:>:]]", $value, $wrkString); |
307 |
|
308 |
} |
309 |
|
310 |
|
311 |
// ---------------------------------------------------- |
312 |
function _analyzeOutputQuery() { |
313 |
|
314 |
// we assume a "good" query |
315 |
$bool_good = 1; |
316 |
|
317 |
// get ready query |
318 |
$oq = $this->sql_out_build; |
319 |
|
320 |
// replace all value-stuff |
321 |
//$oq = str_replace('', '', $oq); |
322 |
|
323 |
// check for unmapped items |
324 |
if (preg_match('/(:\w+)/', $oq, $regs)) { |
325 |
print "<font color=\"red\">_analyzeOutputQuery: Detected unmapped item(s) in query \"$oq\", query will be set invalid.</font><br>"; |
326 |
print "Item(s) was/were: \"{$regs[1]}\".</font><br>"; |
327 |
$bool_good = 0; |
328 |
} |
329 |
|
330 |
// check for deletes without criteria ("where") |
331 |
if ( (stristr($oq, 'DELETE FROM')) && (!stristr($oq, 'WHERE')) ) { |
332 |
print "<font color=\"red\">_analyzeOutputQuery: Detected \"DELETE\" without \"WHERE\" in query \"$oq\", query will be set invalid.</font><br>"; |
333 |
$bool_good = 0; |
334 |
} |
335 |
|
336 |
// set "bool_ready_good" if the query is valid |
337 |
$this->bool_ready_good = $bool_good; |
338 |
|
339 |
} |
340 |
|
341 |
|
342 |
} |
343 |
|
344 |
?> |