86c89cdaea859f25a7c56d7b624b90c88b2870a2
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Database / QueryGenerator.php
1 <?php
2 namespace TYPO3\CMS\Core\Database;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Backend\Utility\IconUtility;
20
21 /**
22 * Class for generating front end for building queries
23 *
24 * @author Christian Jul Jensen <christian@typo3.com>
25 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
26 * @coauthor Jo Hasenau <info@cybercraft.de>
27 */
28 class QueryGenerator {
29
30 /**
31 * @var array
32 */
33 public $lang = array(
34 'OR' => 'or',
35 'AND' => 'and',
36 'comparison' => array(
37 // Type = text offset = 0
38 '0_' => 'contains',
39 '1_' => 'does not contain',
40 '2_' => 'starts with',
41 '3_' => 'does not start with',
42 '4_' => 'ends with',
43 '5_' => 'does not end with',
44 '6_' => 'equals',
45 '7_' => 'does not equal',
46 // Type = number , offset = 32
47 '32_' => 'equals',
48 '33_' => 'does not equal',
49 '34_' => 'is greater than',
50 '35_' => 'is less than',
51 '36_' => 'is between',
52 '37_' => 'is not between',
53 '38_' => 'is in list',
54 '39_' => 'is not in list',
55 '40_' => 'binary AND equals',
56 '41_' => 'binary AND does not equal',
57 '42_' => 'binary OR equals',
58 '43_' => 'binary OR does not equal',
59 // Type = multiple, relation, files , offset = 64
60 '64_' => 'equals',
61 '65_' => 'does not equal',
62 '66_' => 'contains',
63 '67_' => 'does not contain',
64 '68_' => 'is in list',
65 '69_' => 'is not in list',
66 '70_' => 'binary AND equals',
67 '71_' => 'binary AND does not equal',
68 '72_' => 'binary OR equals',
69 '73_' => 'binary OR does not equal',
70 // Type = date,time offset = 96
71 '96_' => 'equals',
72 '97_' => 'does not equal',
73 '98_' => 'is greater than',
74 '99_' => 'is less than',
75 '100_' => 'is between',
76 '101_' => 'is not between',
77 '102_' => 'binary AND equals',
78 '103_' => 'binary AND does not equal',
79 '104_' => 'binary OR equals',
80 '105_' => 'binary OR does not equal',
81 // Type = boolean, offset = 128
82 '128_' => 'is True',
83 '129_' => 'is False',
84 // Type = binary , offset = 160
85 '160_' => 'equals',
86 '161_' => 'does not equal',
87 '162_' => 'contains',
88 '163_' => 'does not contain'
89 )
90 );
91
92 /**
93 * @var array
94 */
95 public $compSQL = array(
96 // Type = text offset = 0
97 '0' => '#FIELD# LIKE \'%#VALUE#%\'',
98 '1' => '#FIELD# NOT LIKE \'%#VALUE#%\'',
99 '2' => '#FIELD# LIKE \'#VALUE#%\'',
100 '3' => '#FIELD# NOT LIKE \'#VALUE#%\'',
101 '4' => '#FIELD# LIKE \'%#VALUE#\'',
102 '5' => '#FIELD# NOT LIKE \'%#VALUE#\'',
103 '6' => '#FIELD# = \'#VALUE#\'',
104 '7' => '#FIELD# != \'#VALUE#\'',
105 // Type = number, offset = 32
106 '32' => '#FIELD# = \'#VALUE#\'',
107 '33' => '#FIELD# != \'#VALUE#\'',
108 '34' => '#FIELD# > #VALUE#',
109 '35' => '#FIELD# < #VALUE#',
110 '36' => '#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#',
111 '37' => 'NOT (#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#)',
112 '38' => '#FIELD# IN (#VALUE#)',
113 '39' => '#FIELD# NOT IN (#VALUE#)',
114 '40' => '(#FIELD# & #VALUE#)=#VALUE#',
115 '41' => '(#FIELD# & #VALUE#)!=#VALUE#',
116 '42' => '(#FIELD# | #VALUE#)=#VALUE#',
117 '43' => '(#FIELD# | #VALUE#)!=#VALUE#',
118 // Type = multiple, relation, files , offset = 64
119 '64' => '#FIELD# = \'#VALUE#\'',
120 '65' => '#FIELD# != \'#VALUE#\'',
121 '66' => '#FIELD# LIKE \'%#VALUE#%\' AND #FIELD# LIKE \'%#VALUE1#%\'',
122 '67' => '(#FIELD# NOT LIKE \'%#VALUE#%\' OR #FIELD# NOT LIKE \'%#VALUE1#%\')',
123 '68' => '#FIELD# IN (#VALUE#)',
124 '69' => '#FIELD# NOT IN (#VALUE#)',
125 '70' => '(#FIELD# & #VALUE#)=#VALUE#',
126 '71' => '(#FIELD# & #VALUE#)!=#VALUE#',
127 '72' => '(#FIELD# | #VALUE#)=#VALUE#',
128 '73' => '(#FIELD# | #VALUE#)!=#VALUE#',
129 // Type = date, offset = 32
130 '96' => '#FIELD# = \'#VALUE#\'',
131 '97' => '#FIELD# != \'#VALUE#\'',
132 '98' => '#FIELD# > #VALUE#',
133 '99' => '#FIELD# < #VALUE#',
134 '100' => '#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#',
135 '101' => 'NOT (#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#)',
136 '102' => '(#FIELD# & #VALUE#)=#VALUE#',
137 '103' => '(#FIELD# & #VALUE#)!=#VALUE#',
138 '104' => '(#FIELD# | #VALUE#)=#VALUE#',
139 '105' => '(#FIELD# | #VALUE#)!=#VALUE#',
140 // Type = boolean, offset = 128
141 '128' => '#FIELD# = \'1\'',
142 '129' => '#FIELD# != \'1\'',
143 // Type = binary = 160
144 '160' => '#FIELD# = \'#VALUE#\'',
145 '161' => '#FIELD# != \'#VALUE#\'',
146 '162' => '(#FIELD# & #VALUE#)=#VALUE#',
147 '163' => '(#FIELD# & #VALUE#)=0'
148 );
149
150 /**
151 * @var array
152 */
153 public $comp_offsets = array(
154 'text' => 0,
155 'number' => 1,
156 'multiple' => 2,
157 'relation' => 2,
158 'files' => 2,
159 'date' => 3,
160 'time' => 3,
161 'boolean' => 4,
162 'binary' => 5
163 );
164
165 /**
166 * @var string
167 */
168 public $noWrap = ' nowrap';
169
170 /**
171 * Form data name prefix
172 *
173 * @var string
174 */
175 public $name;
176
177 /**
178 * Table for the query
179 *
180 * @var string
181 */
182 public $table;
183
184 /**
185 * Field list
186 *
187 * @var string
188 */
189 public $fieldList;
190
191 /**
192 * Array of the fields possible
193 *
194 * @var array
195 */
196 public $fields = array();
197
198 /**
199 * @var array
200 */
201 public $extFieldLists = array();
202
203 /**
204 * The query config
205 *
206 * @var array
207 */
208 public $queryConfig = array();
209
210 /**
211 * @var bool
212 */
213 public $enablePrefix = FALSE;
214
215 /**
216 * @var bool
217 */
218 public $enableQueryParts = FALSE;
219
220 /**
221 * @var string
222 */
223 public $extJSCODE = '';
224
225 /**
226 * @var string
227 */
228 protected $formName = '';
229
230 /**
231 * Make a list of fields for current table
232 *
233 * @return string Separated list of fields
234 */
235 public function makeFieldList() {
236 $fieldListArr = array();
237 if (is_array($GLOBALS['TCA'][$this->table])) {
238 $fieldListArr = array_keys($GLOBALS['TCA'][$this->table]['columns']);
239 $fieldListArr[] = 'uid';
240 $fieldListArr[] = 'pid';
241 $fieldListArr[] = 'deleted';
242 if ($GLOBALS['TCA'][$this->table]['ctrl']['tstamp']) {
243 $fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['tstamp'];
244 }
245 if ($GLOBALS['TCA'][$this->table]['ctrl']['crdate']) {
246 $fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['crdate'];
247 }
248 if ($GLOBALS['TCA'][$this->table]['ctrl']['cruser_id']) {
249 $fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['cruser_id'];
250 }
251 if ($GLOBALS['TCA'][$this->table]['ctrl']['sortby']) {
252 $fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['sortby'];
253 }
254 }
255 return implode(',', $fieldListArr);
256 }
257
258 /**
259 * Init function
260 *
261 * @param string $name The name
262 * @param string $table The table name
263 * @param string $fieldList The field list
264 * @return void
265 */
266 public function init($name, $table, $fieldList = '') {
267 // Analysing the fields in the table.
268 if (is_array($GLOBALS['TCA'][$table])) {
269 $this->name = $name;
270 $this->table = $table;
271 $this->fieldList = $fieldList ? $fieldList : $this->makeFieldList();
272 $fieldArr = GeneralUtility::trimExplode(',', $this->fieldList, TRUE);
273 foreach ($fieldArr as $fieldName) {
274 $fC = $GLOBALS['TCA'][$this->table]['columns'][$fieldName];
275 $this->fields[$fieldName] = $fC['config'];
276 $this->fields[$fieldName]['exclude'] = $fC['exclude'];
277 if (is_array($fC) && $fC['label']) {
278 $this->fields[$fieldName]['label'] = rtrim(trim($GLOBALS['LANG']->sL($fC['label'])), ':');
279 switch ($this->fields[$fieldName]['type']) {
280 case 'input':
281 if (preg_match('/int|year/i', $this->fields[$fieldName]['eval'])) {
282 $this->fields[$fieldName]['type'] = 'number';
283 } elseif (preg_match('/time/i', $this->fields[$fieldName]['eval'])) {
284 $this->fields[$fieldName]['type'] = 'time';
285 } elseif (preg_match('/date/i', $this->fields[$fieldName]['eval'])) {
286 $this->fields[$fieldName]['type'] = 'date';
287 } else {
288 $this->fields[$fieldName]['type'] = 'text';
289 }
290 break;
291 case 'check':
292 if (!$this->fields[$fieldName]['items'] || count($this->fields[$fieldName]['items']) <= 1) {
293 $this->fields[$fieldName]['type'] = 'boolean';
294 } else {
295 $this->fields[$fieldName]['type'] = 'binary';
296 }
297 break;
298 case 'radio':
299 $this->fields[$fieldName]['type'] = 'multiple';
300 break;
301 case 'select':
302 $this->fields[$fieldName]['type'] = 'multiple';
303 if ($this->fields[$fieldName]['foreign_table']) {
304 $this->fields[$fieldName]['type'] = 'relation';
305 }
306 if ($this->fields[$fieldName]['special']) {
307 $this->fields[$fieldName]['type'] = 'text';
308 }
309 break;
310 case 'group':
311 $this->fields[$fieldName]['type'] = 'files';
312 if ($this->fields[$fieldName]['internal_type'] == 'db') {
313 $this->fields[$fieldName]['type'] = 'relation';
314 }
315 break;
316 case 'user':
317 case 'flex':
318 case 'passthrough':
319 case 'none':
320 case 'text':
321 default:
322 $this->fields[$fieldName]['type'] = 'text';
323 }
324 } else {
325 $this->fields[$fieldName]['label'] = '[FIELD: ' . $fieldName . ']';
326 switch ($fieldName) {
327 case 'pid':
328 $this->fields[$fieldName]['type'] = 'relation';
329 $this->fields[$fieldName]['allowed'] = 'pages';
330 break;
331 case 'cruser_id':
332 $this->fields[$fieldName]['type'] = 'relation';
333 $this->fields[$fieldName]['allowed'] = 'be_users';
334 break;
335 case 'tstamp':
336 case 'crdate':
337 $this->fields[$fieldName]['type'] = 'time';
338 break;
339 case 'deleted':
340 $this->fields[$fieldName]['type'] = 'boolean';
341 break;
342 default:
343 $this->fields[$fieldName]['type'] = 'number';
344 }
345 }
346 }
347 }
348 /* // EXAMPLE:
349 $this->queryConfig = array(
350 array(
351 'operator' => 'AND',
352 'type' => 'FIELD_spaceBefore',
353 ),
354 array(
355 'operator' => 'AND',
356 'type' => 'FIELD_records',
357 'negate' => 1,
358 'inputValue' => 'foo foo'
359 ),
360 array(
361 'type' => 'newlevel',
362 'nl' => array(
363 array(
364 'operator' => 'AND',
365 'type' => 'FIELD_spaceBefore',
366 'negate' => 1,
367 'inputValue' => 'foo foo'
368 ),
369 array(
370 'operator' => 'AND',
371 'type' => 'FIELD_records',
372 'negate' => 1,
373 'inputValue' => 'foo foo'
374 )
375 )
376 ),
377 array(
378 'operator' => 'OR',
379 'type' => 'FIELD_maillist',
380 )
381 );
382 */
383 $this->initUserDef();
384 }
385
386 /**
387 * Set and clean up external lists
388 *
389 * @param string $name The name
390 * @param string $list The list
391 * @param string $force
392 * @return void
393 */
394 public function setAndCleanUpExternalLists($name, $list, $force = '') {
395 $fields = array_unique(GeneralUtility::trimExplode(',', $list . ',' . $force, TRUE));
396 $reList = array();
397 foreach ($fields as $fieldName) {
398 if ($this->fields[$fieldName]) {
399 $reList[] = $fieldName;
400 }
401 }
402 $this->extFieldLists[$name] = implode(',', $reList);
403 }
404
405 /**
406 * Process data
407 *
408 * @param string $qC Query config
409 * @return void
410 */
411 public function procesData($qC = '') {
412 $this->queryConfig = $qC;
413 $POST = GeneralUtility::_POST();
414 // If delete...
415 if ($POST['qG_del']) {
416 // Initialize array to work on, save special parameters
417 $ssArr = $this->getSubscript($POST['qG_del']);
418 $workArr = &$this->queryConfig;
419 $ssArrSize = sizeof($ssArr) - 1;
420 for ($i = 0; $i < $ssArrSize; $i++) {
421 $workArr = &$workArr[$ssArr[$i]];
422 }
423 // Delete the entry and move the other entries
424 unset($workArr[$ssArr[$i]]);
425 $workArrSize = sizeof($workArr);
426 for ($j = $ssArr[$i]; $j < $workArrSize; $j++) {
427 $workArr[$j] = $workArr[$j + 1];
428 unset($workArr[$j + 1]);
429 }
430 }
431 // If insert...
432 if ($POST['qG_ins']) {
433 // Initialize array to work on, save special parameters
434 $ssArr = $this->getSubscript($POST['qG_ins']);
435 $workArr = &$this->queryConfig;
436 $ssArrSize = sizeof($ssArr) - 1;
437 for ($i = 0; $i < $ssArrSize; $i++) {
438 $workArr = &$workArr[$ssArr[$i]];
439 }
440 // Move all entries above position where new entry is to be inserted
441 $workArrSize = sizeof($workArr);
442 for ($j = $workArrSize; $j > $ssArr[$i]; $j--) {
443 $workArr[$j] = $workArr[$j - 1];
444 }
445 // Clear new entry position
446 unset($workArr[$ssArr[$i] + 1]);
447 $workArr[$ssArr[$i] + 1]['type'] = 'FIELD_';
448 }
449 // If move up...
450 if ($POST['qG_up']) {
451 // Initialize array to work on
452 $ssArr = $this->getSubscript($POST['qG_up']);
453 $workArr = &$this->queryConfig;
454 $ssArrSize = sizeof($ssArr) - 1;
455 for ($i = 0; $i < $ssArrSize; $i++) {
456 $workArr = &$workArr[$ssArr[$i]];
457 }
458 // Swap entries
459 $qG_tmp = $workArr[$ssArr[$i]];
460 $workArr[$ssArr[$i]] = $workArr[$ssArr[$i] - 1];
461 $workArr[$ssArr[$i] - 1] = $qG_tmp;
462 }
463 // If new level...
464 if ($POST['qG_nl']) {
465 // Initialize array to work on
466 $ssArr = $this->getSubscript($POST['qG_nl']);
467 $workArr = &$this->queryConfig;
468 $ssArraySize = sizeof($ssArr) - 1;
469 for ($i = 0; $i < $ssArraySize; $i++) {
470 $workArr = &$workArr[$ssArr[$i]];
471 }
472 // Do stuff:
473 $tempEl = $workArr[$ssArr[$i]];
474 if (is_array($tempEl)) {
475 if ($tempEl['type'] != 'newlevel') {
476 $workArr[$ssArr[$i]] = array(
477 'type' => 'newlevel',
478 'operator' => $tempEl['operator'],
479 'nl' => array($tempEl)
480 );
481 }
482 }
483 }
484 // If collapse level...
485 if ($POST['qG_remnl']) {
486 // Initialize array to work on
487 $ssArr = $this->getSubscript($POST['qG_remnl']);
488 $workArr = &$this->queryConfig;
489 $ssArrSize = sizeof($ssArr) - 1;
490 for ($i = 0; $i < $ssArrSize; $i++) {
491 $workArr = &$workArr[$ssArr[$i]];
492 }
493 // Do stuff:
494 $tempEl = $workArr[$ssArr[$i]];
495 if (is_array($tempEl)) {
496 if ($tempEl['type'] == 'newlevel') {
497 $a1 = array_slice($workArr, 0, $ssArr[$i]);
498 $a2 = array_slice($workArr, $ssArr[$i]);
499 array_shift($a2);
500 $a3 = $tempEl['nl'];
501 $a3[0]['operator'] = $tempEl['operator'];
502 $workArr = array_merge($a1, $a3, $a2);
503 }
504 }
505 }
506 }
507
508 /**
509 * Clean up query config
510 *
511 * @param array $queryConfig Query config
512 * @return array
513 */
514 public function cleanUpQueryConfig($queryConfig) {
515 // Since we don't traverse the array using numeric keys in the upcoming while-loop make sure it's fresh and clean before displaying
516 if (is_array($queryConfig)) {
517 ksort($queryConfig);
518 } else {
519 // queryConfig should never be empty!
520 if (!$queryConfig[0] || !$queryConfig[0]['type']) {
521 $queryConfig[0] = array('type' => 'FIELD_');
522 }
523 }
524 // Traverse:
525 $c = 0;
526 $arrCount = 0;
527 foreach ($queryConfig as $key => $conf) {
528 if (substr($conf['type'], 0, 6) == 'FIELD_') {
529 $fieldName = substr($conf['type'], 6);
530 $fieldType = $this->fields[$fieldName]['type'];
531 } elseif ($conf['type'] == 'newlevel') {
532 $fieldType = $conf['type'];
533 } else {
534 $fieldType = 'ignore';
535 }
536 switch ($fieldType) {
537 case 'newlevel':
538 if (!$queryConfig[$key]['nl']) {
539 $queryConfig[$key]['nl'][0]['type'] = 'FIELD_';
540 }
541 $queryConfig[$key]['nl'] = $this->cleanUpQueryConfig($queryConfig[$key]['nl']);
542 break;
543 case 'userdef':
544 $queryConfig[$key] = $this->userDefCleanUp($queryConfig[$key]);
545 break;
546 case 'ignore':
547
548 default:
549 $verifiedName = $this->verifyType($fieldName);
550 $queryConfig[$key]['type'] = 'FIELD_' . $this->verifyType($verifiedName);
551 if ($conf['comparison'] >> 5 != $this->comp_offsets[$fieldType]) {
552 $conf['comparison'] = $this->comp_offsets[$fieldType] << 5;
553 }
554 $queryConfig[$key]['comparison'] = $this->verifyComparison($conf['comparison'], $conf['negate'] ? 1 : 0);
555 $queryConfig[$key]['inputValue'] = $this->cleanInputVal($queryConfig[$key]);
556 $queryConfig[$key]['inputValue1'] = $this->cleanInputVal($queryConfig[$key], 1);
557 }
558 }
559 return $queryConfig;
560 }
561
562 /**
563 * Get form elements
564 *
565 * @param int $subLevel
566 * @param string $queryConfig
567 * @param string $parent
568 * @return array
569 */
570 public function getFormElements($subLevel = 0, $queryConfig = '', $parent = '') {
571 $codeArr = array();
572 if (!is_array($queryConfig)) {
573 $queryConfig = $this->queryConfig;
574 }
575 $c = 0;
576 $arrCount = 0;
577 $loopcount = 0;
578 foreach ($queryConfig as $key => $conf) {
579 $subscript = $parent . '[' . $key . ']';
580 $lineHTML = '';
581 $lineHTML .= $this->mkOperatorSelect($this->name . $subscript, $conf['operator'], $c, $conf['type'] != 'FIELD_');
582 if (substr($conf['type'], 0, 6) == 'FIELD_') {
583 $fieldName = substr($conf['type'], 6);
584 $this->fieldName = $fieldName;
585 $fieldType = $this->fields[$fieldName]['type'];
586 if ($conf['comparison'] >> 5 != $this->comp_offsets[$fieldType]) {
587 $conf['comparison'] = $this->comp_offsets[$fieldType] << 5;
588 }
589 //nasty nasty...
590 //make sure queryConfig contains _actual_ comparevalue.
591 //mkCompSelect don't care, but getQuery does.
592 $queryConfig[$key]['comparison'] += isset($conf['negate']) - $conf['comparison'] % 2;
593 } elseif ($conf['type'] == 'newlevel') {
594 $fieldType = $conf['type'];
595 } else {
596 $fieldType = 'ignore';
597 }
598 switch ($fieldType) {
599 case 'ignore':
600 break;
601 case 'newlevel':
602 if (!$queryConfig[$key]['nl']) {
603 $queryConfig[$key]['nl'][0]['type'] = 'FIELD_';
604 }
605 $lineHTML .= '<input type="hidden" name="' . $this->name . $subscript . '[type]" value="newlevel">';
606 $codeArr[$arrCount]['sub'] = $this->getFormElements($subLevel + 1, $queryConfig[$key]['nl'], $subscript . '[nl]');
607 break;
608 case 'userdef':
609 $lineHTML .= $this->userDef($this->name . $subscript, $conf, $fieldName, $fieldType);
610 break;
611 case 'date':
612 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
613 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
614 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
615 if ($conf['comparison'] == 100 || $conf['comparison'] == 101) {
616 // between
617 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue]_hr' . '" value="' . strftime('%e-%m-%Y', $conf['inputValue']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue]\', \'date\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '">';
618 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue1]_hr' . '" value="' . strftime('%e-%m-%Y', $conf['inputValue1']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue1]\', \'date\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $this->name . $subscript . '[inputValue1]' . '">';
619 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue]", "date", "", 0,0);';
620 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue1]", "date", "", 0,0);';
621 } else {
622 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue]_hr' . '" value="' . strftime('%e-%m-%Y', $conf['inputValue']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue]\', \'date\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '">';
623 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue]", "date", "", 0,0);';
624 }
625 break;
626 case 'time':
627 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
628 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
629 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
630 if ($conf['comparison'] == 100 || $conf['comparison'] == 101) {
631 // between:
632 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue]_hr' . '" value="' . strftime('%H:%M %e-%m-%Y', $conf['inputValue']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue]\', \'datetime\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '">';
633 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue1]_hr' . '" value="' . strftime('%H:%M %e-%m-%Y', $conf['inputValue1']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue1]\', \'datetime\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $this->name . $subscript . '[inputValue1]' . '">';
634 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue]", "datetime", "", 0,0);';
635 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue1]", "datetime", "", 0,0);';
636 } else {
637 $lineHTML .= '<input type="text" name="' . $this->name . $subscript . '[inputValue]_hr' . '" value="' . strftime('%H:%M %e-%m-%Y', (int)$conf['inputValue']) . '" ' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' onChange="typo3form.fieldGet(\'' . $this->name . $subscript . '[inputValue]\', \'datetime\', \'\', 0,0);"><input type="hidden" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '">';
638 $this->extJSCODE .= 'typo3form.fieldSet("' . $this->name . $subscript . '[inputValue]", "datetime", "", 0,0);';
639 }
640 break;
641 case 'multiple':
642 case 'binary':
643 case 'relation':
644 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
645 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
646 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
647 if ($conf['comparison'] == 68 || $conf['comparison'] == 69 || $conf['comparison'] == 162 || $conf['comparison'] == 163) {
648 $lineHTML .= '<select name="' . $this->name . $subscript . '[inputValue]' . '[]" style="vertical-align:top;" size="5" multiple>';
649 } elseif ($conf['comparison'] == 66 || $conf['comparison'] == 67) {
650 if (is_array($conf['inputValue'])) {
651 $conf['inputValue'] = implode(',', $conf['inputValue']);
652 }
653 $lineHTML .= '<input type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . '>';
654 } else {
655 $lineHTML .= '<select name="' . $this->name . $subscript . '[inputValue]' . '" style="vertical-align:top;" onChange="submit();">';
656 }
657 if ($conf['comparison'] != 66 && $conf['comparison'] != 67) {
658 $lineHTML .= $this->makeOptionList($fieldName, $conf, $this->table);
659 $lineHTML .= '</select>';
660 }
661 break;
662 case 'files':
663 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
664 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
665 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
666 if ($conf['comparison'] == 68 || $conf['comparison'] == 69) {
667 $lineHTML .= '<select name="' . $this->name . $subscript . '[inputValue]' . '[]" style="vertical-align:top;" size="5" multiple>';
668 } else {
669 $lineHTML .= '<select name="' . $this->name . $subscript . '[inputValue]' . '" style="vertical-align:top;" onChange="submit();">';
670 }
671 $lineHTML .= '<option value=""></option>' . $this->makeOptionList($fieldName, $conf, $this->table);
672 $lineHTML .= '</select>';
673 if ($conf['comparison'] == 66 || $conf['comparison'] == 67) {
674 $lineHTML .= ' + <input type="text" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $this->name . $subscript . '[inputValue1]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . '>';
675 }
676 break;
677 case 'boolean':
678 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
679 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
680 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
681 $lineHTML .= '<input type="hidden" value="1" name="' . $this->name . $subscript . '[inputValue]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . '>';
682 break;
683 default:
684 $lineHTML .= $this->mkTypeSelect($this->name . $subscript . '[type]', $fieldName);
685 $lineHTML .= $this->mkCompSelect($this->name . $subscript . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
686 $lineHTML .= '<input type="checkbox" class="checkbox"' . ($conf['negate'] ? ' checked' : '') . ' name="' . $this->name . $subscript . '[negate]' . '" onClick="submit();">';
687 if ($conf['comparison'] == 37 || $conf['comparison'] == 36) {
688 // between:
689 $lineHTML .= '<input type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(5) . '>
690 <input type="text" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $this->name . $subscript . '[inputValue1]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(5) . '>';
691 } else {
692 $lineHTML .= '<input type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $this->name . $subscript . '[inputValue]' . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . '>';
693 }
694 }
695 if ($fieldType != 'ignore') {
696 $lineHTML .= $this->updateIcon();
697 if ($loopcount) {
698 $lineHTML .= '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/garbage.gif', 'width="11" height="12"') . 'title="Remove condition" name="qG_del' . $subscript . '">';
699 }
700 $lineHTML .= '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/add.gif', 'width="12" height="12"') . ' title="Add condition" name="qG_ins' . $subscript . '">';
701 if ($c != 0) {
702 $lineHTML .= '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/pil2up.gif', 'width="12" height="7"') . ' title="Move up" name="qG_up' . $subscript . '">';
703 }
704 if ($c != 0 && $fieldType != 'newlevel') {
705 $lineHTML .= '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/pil2right.gif', 'height="12" width="7"') . ' title="New level" name="qG_nl' . $subscript . '">';
706 }
707 if ($fieldType == 'newlevel') {
708 $lineHTML .= '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/pil2left.gif', 'height="12" width="7"') . ' title="Collapse new level" name="qG_remnl' . $subscript . '">';
709 }
710 $codeArr[$arrCount]['html'] = $lineHTML;
711 $codeArr[$arrCount]['query'] = $this->getQuerySingle($conf, $c > 0 ? 0 : 1);
712 $arrCount++;
713 $c++;
714 }
715 $loopcount = 1;
716 }
717 $this->queryConfig = $queryConfig;
718 return $codeArr;
719 }
720
721 /**
722 * Make option list
723 *
724 * @param string $fieldName
725 * @param array $conf
726 * @param string $table
727 * @return string
728 */
729 public function makeOptionList($fieldName, $conf, $table) {
730 $out = '';
731 $fieldSetup = $this->fields[$fieldName];
732 if ($fieldSetup['type'] == 'files') {
733 if ($conf['comparison'] == 66 || $conf['comparison'] == 67) {
734 $fileExtArray = explode(',', $fieldSetup['allowed']);
735 natcasesort($fileExtArray);
736 foreach ($fileExtArray as $fileExt) {
737 if (GeneralUtility::inList($conf['inputValue'], $fileExt)) {
738 $out .= '<option value="' . $fileExt . '" selected>.' . $fileExt . '</option>';
739 } else {
740 $out .= '<option value="' . $fileExt . '">.' . $fileExt . '</option>';
741 }
742 }
743 }
744 $d = dir(PATH_site . $fieldSetup['uploadfolder']);
745 while (FALSE !== ($entry = $d->read())) {
746 if ($entry == '.' || $entry == '..') {
747 continue;
748 }
749 $fileArray[] = $entry;
750 }
751 $d->close();
752 natcasesort($fileArray);
753 foreach ($fileArray as $fileName) {
754 if (GeneralUtility::inList($conf['inputValue'], $fileName)) {
755 $out .= '<option value="' . $fileName . '" selected>' . $fileName . '</option>';
756 } else {
757 $out .= '<option value="' . $fileName . '">' . $fileName . '</option>';
758 }
759 }
760 }
761 if ($fieldSetup['type'] == 'multiple') {
762 foreach ($fieldSetup['items'] as $key => $val) {
763 if (substr($val[0], 0, 4) == 'LLL:') {
764 $value = $GLOBALS['LANG']->sL($val[0]);
765 } else {
766 $value = $val[0];
767 }
768 if (GeneralUtility::inList($conf['inputValue'], $val[1])) {
769 $out .= '<option value="' . $val[1] . '" selected>' . $value . '</option>';
770 } else {
771 $out .= '<option value="' . $val[1] . '">' . $value . '</option>';
772 }
773 }
774 }
775 if ($fieldSetup['type'] == 'binary') {
776 foreach ($fieldSetup['items'] as $key => $val) {
777 if (substr($val[0], 0, 4) == 'LLL:') {
778 $value = $GLOBALS['LANG']->sL($val[0]);
779 } else {
780 $value = $val[0];
781 }
782 if (GeneralUtility::inList($conf['inputValue'], pow(2, $key))) {
783 $out .= '<option value="' . pow(2, $key) . '" selected>' . $value . '</option>';
784 } else {
785 $out .= '<option value="' . pow(2, $key) . '">' . $value . '</option>';
786 }
787 }
788 }
789 if ($fieldSetup['type'] == 'relation') {
790 if ($fieldSetup['items']) {
791 foreach ($fieldSetup['items'] as $key => $val) {
792 if (substr($val[0], 0, 4) == 'LLL:') {
793 $value = $GLOBALS['LANG']->sL($val[0]);
794 } else {
795 $value = $val[0];
796 }
797 if (GeneralUtility::inList($conf['inputValue'], $val[1])) {
798 $out .= '<option value="' . $val[1] . '" selected>' . $value . '</option>';
799 } else {
800 $out .= '<option value="' . $val[1] . '">' . $value . '</option>';
801 }
802 }
803 }
804 if (stristr($fieldSetup['allowed'], ',')) {
805 $from_table_Arr = explode(',', $fieldSetup['allowed']);
806 $useTablePrefix = 1;
807 if (!$fieldSetup['prepend_tname']) {
808 $checkres = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldName, $table, BackendUtility::deleteClause($table), ($groupBy = ''), ($orderBy = ''), ($limit = ''));
809 if ($checkres) {
810 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($checkres)) {
811 if (stristr($row[$fieldName], ',')) {
812 $checkContent = explode(',', $row[$fieldName]);
813 foreach ($checkContent as $singleValue) {
814 if (!stristr($singleValue, '_')) {
815 $dontPrefixFirstTable = 1;
816 }
817 }
818 } else {
819 $singleValue = $row[$fieldName];
820 if (strlen($singleValue) && !stristr($singleValue, '_')) {
821 $dontPrefixFirstTable = 1;
822 }
823 }
824 }
825 $GLOBALS['TYPO3_DB']->sql_free_result($checkres);
826 }
827 }
828 } else {
829 $from_table_Arr[0] = $fieldSetup['allowed'];
830 }
831 if ($fieldSetup['prepend_tname']) {
832 $useTablePrefix = 1;
833 }
834 if ($fieldSetup['foreign_table']) {
835 $from_table_Arr[0] = $fieldSetup['foreign_table'];
836 }
837 $counter = 0;
838 $webMountPageTree = '';
839 while (list(, $from_table) = each($from_table_Arr)) {
840 if ($useTablePrefix && !$dontPrefixFirstTable && $counter != 1 || $counter == 1) {
841 $tablePrefix = $from_table . '_';
842 }
843 $counter = 1;
844 if (is_array($GLOBALS['TCA'][$from_table])) {
845 $labelField = $GLOBALS['TCA'][$from_table]['ctrl']['label'];
846 $altLabelField = $GLOBALS['TCA'][$from_table]['ctrl']['label_alt'];
847 if ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items']) {
848 foreach ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items'] as $labelArray) {
849 if (substr($labelArray[0], 0, 4) == 'LLL:') {
850 $labelFieldSelect[$labelArray[1]] = $GLOBALS['LANG']->sL($labelArray[0]);
851 } else {
852 $labelFieldSelect[$labelArray[1]] = $labelArray[0];
853 }
854 }
855 $useSelectLabels = 1;
856 }
857 if ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items']) {
858 foreach ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items'] as $altLabelArray) {
859 if (substr($altLabelArray[0], 0, 4) == 'LLL:') {
860 $altLabelFieldSelect[$altLabelArray[1]] = $GLOBALS['LANG']->sL($altLabelArray[0]);
861 } else {
862 $altLabelFieldSelect[$altLabelArray[1]] = $altLabelArray[0];
863 }
864 }
865 $useAltSelectLabels = 1;
866 }
867 $altLabelFieldSelect = $altLabelField ? ',' . $altLabelField : '';
868 $select_fields = 'uid,' . $labelField . $altLabelFieldSelect;
869 if (!$GLOBALS['BE_USER']->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
870 $webMounts = $GLOBALS['BE_USER']->returnWebmounts();
871 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
872 foreach ($webMounts as $key => $val) {
873 if ($webMountPageTree) {
874 $webMountPageTreePrefix = ',';
875 }
876 $webMountPageTree .= $webMountPageTreePrefix . $this->getTreeList($val, 999, ($begin = 0), $perms_clause);
877 }
878 if ($from_table == 'pages') {
879 $where_clause = 'uid IN (' . $webMountPageTree . ') ';
880 if (!$GLOBALS['SOBE']->MOD_SETTINGS['show_deleted']) {
881 $where_clause .= BackendUtility::deleteClause($from_table) . ' AND' . $perms_clause;
882 }
883 } else {
884 $where_clause = 'pid IN (' . $webMountPageTree . ') ';
885 if (!$GLOBALS['SOBE']->MOD_SETTINGS['show_deleted']) {
886 $where_clause .= BackendUtility::deleteClause($from_table);
887 }
888 }
889 } else {
890 $where_clause = 'uid';
891 if (!$GLOBALS['SOBE']->MOD_SETTINGS['show_deleted']) {
892 $where_clause .= BackendUtility::deleteClause($from_table);
893 }
894 }
895 $orderBy = 'uid';
896 if (!$this->tableArray[$from_table]) {
897 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select_fields, $from_table, $where_clause, ($groupBy = ''), $orderBy, ($limit = ''));
898 }
899 if ($res) {
900 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
901 $this->tableArray[$from_table][] = $row;
902 }
903 $GLOBALS['TYPO3_DB']->sql_free_result($res);
904 }
905 foreach ($this->tableArray[$from_table] as $key => $val) {
906 if ($useSelectLabels) {
907 $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($labelFieldSelect[$val[$labelField]]);
908 } elseif ($val[$labelField]) {
909 $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($val[$labelField]);
910 } elseif ($useAltSelectLabels) {
911 $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($altLabelFieldSelect[$val[$altLabelField]]);
912 } else {
913 $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($val[$altLabelField]);
914 }
915 }
916 if ($GLOBALS['SOBE']->MOD_SETTINGS['options_sortlabel'] && is_array($outArray)) {
917 natcasesort($outArray);
918 }
919 }
920 }
921 foreach ($outArray as $key2 => $val2) {
922 if (GeneralUtility::inList($conf['inputValue'], $key2)) {
923 $out .= '<option value="' . $key2 . '" selected>[' . $key2 . '] ' . $val2 . '</option>';
924 } else {
925 $out .= '<option value="' . $key2 . '">[' . $key2 . '] ' . $val2 . '</option>';
926 }
927 }
928 }
929 return $out;
930 }
931
932 /**
933 * Print code array
934 *
935 * @param array $codeArr
936 * @param int $recursionLevel
937 * @return string
938 */
939 public function printCodeArray($codeArr, $recursionLevel = 0) {
940 $line = '';
941 $indent = '';
942 if ($recursionLevel) {
943 $indent = '<td style="vertical-align:top;"><img height="1" width="50"></td>';
944 }
945 foreach ($codeArr as $k => $v) {
946 $line .= '<tr>' . $indent . '<td class="bgColor2" ' . $this->noWrap . '>' . $v['html'] . '</td></tr>';
947 if ($this->enableQueryParts) {
948 $line .= '<tr>' . $indent . '<td>' . $this->formatQ($v['query']) . '</td></tr>';
949 }
950 if (is_array($v['sub'])) {
951 $line .= '<tr>' . $indent . '<td' . $this->noWrap . '>' . $this->printCodeArray($v['sub'], ($recursionLevel + 1)) . '</td></tr>';
952 }
953 }
954 $out = '<table border="0" cellpadding="0" cellspacing="1">' . $line . '</table>';
955 return $out;
956 }
957
958 /**
959 * Format query-string (output as HTML)
960 *
961 * @param string $str
962 * @return string
963 */
964 public function formatQ($str) {
965 return '<font size="1" face="verdana" color="maroon"><i>' . htmlspecialchars($str) . '</i></font>';
966 }
967
968 /**
969 * Make operator select
970 *
971 * @param string $name
972 * @param string $op
973 * @param bool $draw
974 * @param bool $submit
975 * @return string
976 */
977 public function mkOperatorSelect($name, $op, $draw, $submit) {
978 if ($draw) {
979 $out = '<select name="' . $name . '[operator]"' . ($submit ? ' onChange="submit();"' : '') . '>';
980 //
981 $out .= '<option value="AND"' . (!$op || $op == 'AND' ? ' selected' : '') . '>' . $this->lang['AND'] . '</option>';
982 $out .= '<option value="OR"' . ($op == 'OR' ? ' selected' : '') . '>' . $this->lang['OR'] . '</option>';
983 $out .= '</select>';
984 } else {
985 $out = '<input type="hidden" value="' . $op . '" name="' . $name . '[operator]">';
986 $out .= '<img src="clear.gif" height="1" width="47">';
987 }
988 return $out;
989 }
990
991 /**
992 * Make type select
993 *
994 * @param string $name
995 * @param string $fieldName
996 * @param string $prepend
997 * @return string
998 */
999 public function mkTypeSelect($name, $fieldName, $prepend = 'FIELD_') {
1000 $out = '<select name="' . $name . '" onChange="submit();">';
1001 $out .= '<option value=""></option>';
1002 foreach ($this->fields as $key => $value) {
1003 if (!$value['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $this->table . ':' . $key)) {
1004 $label = $this->fields[$key]['label'];
1005 $label_alt = $this->fields[$key]['label_alt'];
1006 $out .= '<option value="' . $prepend . $key . '"' . ($key == $fieldName ? ' selected' : '') . '>' . $label . '</option>';
1007 }
1008 }
1009 $out .= '</select>';
1010 return $out;
1011 }
1012
1013 /**
1014 * Verify type
1015 *
1016 * @param string $fieldName
1017 * @return string
1018 */
1019 public function verifyType($fieldName) {
1020 $first = '';
1021 foreach ($this->fields as $key => $value) {
1022 if (!$first) {
1023 $first = $key;
1024 }
1025 if ($key == $fieldName) {
1026 return $key;
1027 }
1028 }
1029 return $first;
1030 }
1031
1032 /**
1033 * Verify comparison
1034 *
1035 * @param string $comparison
1036 * @param int $neg
1037 * @return int
1038 */
1039 public function verifyComparison($comparison, $neg) {
1040 $compOffSet = $comparison >> 5;
1041 $first = -1;
1042 for ($i = 32 * $compOffSet + $neg; $i < 32 * ($compOffSet + 1); $i += 2) {
1043 if ($first == -1) {
1044 $first = $i;
1045 }
1046 if ($i >> 1 == $comparison >> 1) {
1047 return $i;
1048 }
1049 }
1050 return $first;
1051 }
1052
1053 /**
1054 * Make field to input select
1055 *
1056 * @param string $name
1057 * @param string $fieldName
1058 * @return string
1059 */
1060 public function mkFieldToInputSelect($name, $fieldName) {
1061 $out = '<input type="Text" value="' . htmlspecialchars($fieldName) . '" name="' . $name . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth() . '>' . $this->updateIcon();
1062 $out .= '<a href="#" onClick="document.forms[0][\'' . $name . '\'].value=\'\';return false;">' . IconUtility::getSpriteIcon('actions-edit-delete', array('title' => 'Clear list')) . '</a>';
1063 $out .= '<BR><select name="_fieldListDummy" size="5" onChange="document.forms[0][\'' . $name . '\'].value+=\',\'+this.value">';
1064 foreach ($this->fields as $key => $value) {
1065 if (!$value['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $this->table . ':' . $key)) {
1066 $label = $this->fields[$key]['label'];
1067 $label_alt = $this->fields[$key]['label_alt'];
1068 $out .= '<option value="' . $key . '"' . ($key == $fieldName ? ' selected' : '') . '>' . $label . '</option>';
1069 }
1070 }
1071 $out .= '</select>';
1072 return $out;
1073 }
1074
1075 /**
1076 * Make table select
1077 *
1078 * @param string $name
1079 * @param string $cur
1080 * @return string
1081 */
1082 public function mkTableSelect($name, $cur) {
1083 $out = '<select name="' . $name . '" onChange="submit();">';
1084 $out .= '<option value=""></option>';
1085 foreach ($GLOBALS['TCA'] as $tN => $value) {
1086 if ($GLOBALS['BE_USER']->check('tables_select', $tN)) {
1087 $out .= '<option value="' . $tN . '"' . ($tN == $cur ? ' selected' : '') . '>' . $GLOBALS['LANG']->sl($GLOBALS['TCA'][$tN]['ctrl']['title']) . '</option>';
1088 }
1089 }
1090 $out .= '</select>';
1091 return $out;
1092 }
1093
1094 /**
1095 * Make comparison select
1096 *
1097 * @param string $name
1098 * @param string $comparison
1099 * @param int $neg
1100 * @return string
1101 */
1102 public function mkCompSelect($name, $comparison, $neg) {
1103 $compOffSet = $comparison >> 5;
1104 $out = '<select name="' . $name . '" onChange="submit();">';
1105 for ($i = 32 * $compOffSet + $neg; $i < 32 * ($compOffSet + 1); $i += 2) {
1106 if ($this->lang['comparison'][$i . '_']) {
1107 $out .= '<option value="' . $i . '"' . ($i >> 1 == $comparison >> 1 ? ' selected' : '') . '>' . $this->lang['comparison'][($i . '_')] . '</option>';
1108 }
1109 }
1110 $out .= '</select>';
1111 return $out;
1112 }
1113
1114 /**
1115 * Get subscript
1116 *
1117 * @param array $arr
1118 * @return array
1119 */
1120 public function getSubscript($arr) {
1121 $retArr = array();
1122 while (is_array($arr)) {
1123 reset($arr);
1124 list($key, ) = each($arr);
1125 $retArr[] = $key;
1126 $arr = $arr[$key];
1127 }
1128 return $retArr;
1129 }
1130
1131 /**
1132 * Init user definition
1133 *
1134 * @return void
1135 */
1136 public function initUserDef() {
1137
1138 }
1139
1140 /**
1141 * User definition
1142 *
1143 * @return void
1144 */
1145 public function userDef() {
1146
1147 }
1148
1149 /**
1150 * User definition clean up
1151 *
1152 * @param array $queryConfig
1153 * @return array
1154 */
1155 public function userDefCleanUp($queryConfig) {
1156 return $queryConfig;
1157 }
1158
1159 /**
1160 * Get query
1161 *
1162 * @param array $queryConfig
1163 * @param string $pad
1164 * @return string
1165 */
1166 public function getQuery($queryConfig, $pad = '') {
1167 $qs = '';
1168 // Since we don't traverse the array using numeric keys in the upcoming whileloop make sure it's fresh and clean
1169 ksort($queryConfig);
1170 $first = 1;
1171 foreach ($queryConfig as $key => $conf) {
1172 switch ($conf['type']) {
1173 case 'newlevel':
1174 $qs .= LF . $pad . trim($conf['operator']) . ' (' . $this->getQuery($queryConfig[$key]['nl'], ($pad . ' ')) . LF . $pad . ')';
1175 break;
1176 case 'userdef':
1177 $qs .= LF . $pad . $this->getUserDefQuery($conf, $first);
1178 break;
1179 default:
1180 $qs .= LF . $pad . $this->getQuerySingle($conf, $first);
1181 }
1182 $first = 0;
1183 }
1184 return $qs;
1185 }
1186
1187 /**
1188 * Get single query
1189 *
1190 * @param array $conf
1191 * @param bool $first
1192 * @return string
1193 */
1194 public function getQuerySingle($conf, $first) {
1195 $qs = '';
1196 $prefix = $this->enablePrefix ? $this->table . '.' : '';
1197 if (!$first) {
1198 // Is it OK to insert the AND operator if none is set?
1199 $qs .= trim(($conf['operator'] ?: 'AND')) . ' ';
1200 }
1201 $qsTmp = str_replace('#FIELD#', $prefix . trim(substr($conf['type'], 6)), $this->compSQL[$conf['comparison']]);
1202 $inputVal = $this->cleanInputVal($conf);
1203 if ($conf['comparison'] == 68 || $conf['comparison'] == 69) {
1204 $inputVal = explode(',', $inputVal);
1205 foreach ($inputVal as $key => $fileName) {
1206 $inputVal[$key] = '\'' . $fileName . '\'';
1207 }
1208 $inputVal = implode(',', $inputVal);
1209 $qsTmp = str_replace('#VALUE#', $inputVal, $qsTmp);
1210 } elseif ($conf['comparison'] == 162 || $conf['comparison'] == 163) {
1211 $inputValArray = explode(',', $inputVal);
1212 $inputVal = 0;
1213 foreach ($inputValArray as $fileName) {
1214 $inputVal += (int)$fileName;
1215 }
1216 $qsTmp = str_replace('#VALUE#', $inputVal, $qsTmp);
1217 } else {
1218 $qsTmp = str_replace('#VALUE#', $GLOBALS['TYPO3_DB']->quoteStr($inputVal, $this->table), $qsTmp);
1219 }
1220 if ($conf['comparison'] == 37 || $conf['comparison'] == 36 || $conf['comparison'] == 66 || $conf['comparison'] == 67 || $conf['comparison'] == 100 || $conf['comparison'] == 101) {
1221 // between:
1222 $inputVal = $this->cleanInputVal($conf, '1');
1223 $qsTmp = str_replace('#VALUE1#', $GLOBALS['TYPO3_DB']->quoteStr($inputVal, $this->table), $qsTmp);
1224 }
1225 $qs .= trim($qsTmp);
1226 return $qs;
1227 }
1228
1229 /**
1230 * Clear input value
1231 *
1232 * @param array $conf
1233 * @param string $suffix
1234 * @return string
1235 */
1236 public function cleanInputVal($conf, $suffix = '') {
1237 if ($conf['comparison'] >> 5 == 0 || ($conf['comparison'] == 32 || $conf['comparison'] == 33 || $conf['comparison'] == 64 || $conf['comparison'] == 65 || $conf['comparison'] == 66 || $conf['comparison'] == 67 || $conf['comparison'] == 96 || $conf['comparison'] == 97)) {
1238 $inputVal = $conf['inputValue' . $suffix];
1239 } elseif ($conf['comparison'] == 39 || $conf['comparison'] == 38) {
1240 // in list:
1241 $inputVal = implode(',', GeneralUtility::intExplode(',', $conf['inputValue' . $suffix]));
1242 } elseif ($conf['comparison'] == 68 || $conf['comparison'] == 69 || $conf['comparison'] == 162 || $conf['comparison'] == 163) {
1243 // in list:
1244 if (is_array($conf['inputValue' . $suffix])) {
1245 $inputVal = implode(',', $conf['inputValue' . $suffix]);
1246 } elseif ($conf['inputValue' . $suffix]) {
1247 $inputVal = $conf['inputValue' . $suffix];
1248 } else {
1249 $inputVal = 0;
1250 }
1251 } else {
1252 $inputVal = doubleval($conf['inputValue' . $suffix]);
1253 }
1254 return $inputVal;
1255 }
1256
1257 /**
1258 * Get user definition query
1259 *
1260 * @param array $qcArr
1261 * @param bool $first
1262 * @return void
1263 */
1264 public function getUserDefQuery($qcArr, $first) {
1265
1266 }
1267
1268 /**
1269 * Update icon
1270 *
1271 * @return string
1272 */
1273 public function updateIcon() {
1274 return '<input type="image" border="0" ' . IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/refresh_n.gif', 'width="14" height="14"') . ' title="Update" name="just_update">';
1275 }
1276
1277 /**
1278 * Get label column
1279 *
1280 * @return string
1281 */
1282 public function getLabelCol() {
1283 return $GLOBALS['TCA'][$this->table]['ctrl']['label'];
1284 }
1285
1286 /**
1287 * Make selector table
1288 *
1289 * @param array $modSettings
1290 * @param string $enableList
1291 * @return string
1292 */
1293 public function makeSelectorTable($modSettings, $enableList = 'table,fields,query,group,order,limit') {
1294 $enableArr = explode(',', $enableList);
1295 // Make output
1296 $TDparams = ' class="bgColor5" nowrap';
1297 if (in_array('table', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableSelectATable']) {
1298 $out = '
1299 <tr>
1300 <td' . $TDparams . '><strong>Select a table:</strong></td>
1301 <td' . $TDparams . '>' . $this->mkTableSelect('SET[queryTable]', $this->table) . '</td>
1302 </tr>';
1303 }
1304 if ($this->table) {
1305 // Init fields:
1306 $this->setAndCleanUpExternalLists('queryFields', $modSettings['queryFields'], 'uid,' . $this->getLabelCol());
1307 $this->setAndCleanUpExternalLists('queryGroup', $modSettings['queryGroup']);
1308 $this->setAndCleanUpExternalLists('queryOrder', $modSettings['queryOrder'] . ',' . $modSettings['queryOrder2']);
1309 // Limit:
1310 $this->extFieldLists['queryLimit'] = $modSettings['queryLimit'];
1311 if (!$this->extFieldLists['queryLimit']) {
1312 $this->extFieldLists['queryLimit'] = 100;
1313 }
1314 $parts = GeneralUtility::intExplode(',', $this->extFieldLists['queryLimit']);
1315 if ($parts[1]) {
1316 $this->limitBegin = $parts[0];
1317 $this->limitLength = $parts[1];
1318 } else {
1319 $this->limitLength = $this->extFieldLists['queryLimit'];
1320 }
1321 $this->extFieldLists['queryLimit'] = implode(',', array_slice($parts, 0, 2));
1322 // Insert Descending parts
1323 if ($this->extFieldLists['queryOrder']) {
1324 $descParts = explode(',', $modSettings['queryOrderDesc'] . ',' . $modSettings['queryOrder2Desc']);
1325 $orderParts = explode(',', $this->extFieldLists['queryOrder']);
1326 $reList = array();
1327 foreach ($orderParts as $kk => $vv) {
1328 $reList[] = $vv . ($descParts[$kk] ? ' DESC' : '');
1329 }
1330 $this->extFieldLists['queryOrder_SQL'] = implode(',', $reList);
1331 }
1332 // Query Generator:
1333 $this->procesData($modSettings['queryConfig'] ? unserialize($modSettings['queryConfig']) : '');
1334 $this->queryConfig = $this->cleanUpQueryConfig($this->queryConfig);
1335 $this->enableQueryParts = (bool)$modSettings['search_query_smallparts'];
1336 $codeArr = $this->getFormElements();
1337 $queryCode = $this->printCodeArray($codeArr);
1338 if (in_array('fields', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableSelectFields']) {
1339 $out .= '
1340 <tr>
1341 <td' . $TDparams . '><strong>Select fields:</strong></td>
1342 <td' . $TDparams . '>' . $this->mkFieldToInputSelect('SET[queryFields]', $this->extFieldLists['queryFields']) . '</td>
1343 </tr>';
1344 }
1345 if (in_array('query', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableMakeQuery']) {
1346 $out .= '<tr>
1347 <td colspan="2"' . $TDparams . '><strong>Make Query:</strong></td>
1348 </tr>
1349 <tr>
1350 <td colspan="2">' . $queryCode . '</td>
1351 </tr>
1352 ';
1353 }
1354 if (in_array('group', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableGroupBy']) {
1355 $out .= '<tr>
1356 <td' . $TDparams . '><strong>Group By:</strong></td>
1357 <td' . $TDparams . '>' . $this->mkTypeSelect('SET[queryGroup]', $this->extFieldLists['queryGroup'], '') . '</td>
1358 </tr>';
1359 }
1360 if (in_array('order', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableOrderBy']) {
1361 $orderByArr = explode(',', $this->extFieldLists['queryOrder']);
1362 $orderBy = '';
1363 $orderBy .= $this->mkTypeSelect('SET[queryOrder]', $orderByArr[0], '') . '&nbsp;'
1364 . '<div class="checkbox"><label for="checkQueryOrderDesc">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[queryOrderDesc]', $modSettings['queryOrderDesc'], '', '', 'id="checkQueryOrderDesc"') . 'Descending</label></div>';
1365 if ($orderByArr[0]) {
1366 $orderBy .= '<BR>' . $this->mkTypeSelect('SET[queryOrder2]', $orderByArr[1], '') . '&nbsp;'
1367 . '<div class="checkbox"><label for="checkQueryOrder2Desc">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[queryOrder2Desc]', $modSettings['queryOrder2Desc'], '', '', 'id="checkQueryOrder2Desc"') . 'Descending</label></div>';
1368 }
1369 $out .= '<tr>
1370 <td' . $TDparams . '><strong>Order By:</strong></td>
1371 <td' . $TDparams . '>' . $orderBy . '</td>
1372 </tr>';
1373 }
1374 if (in_array('limit', $enableArr) && !$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableLimit']) {
1375 $limit = '<input type="Text" value="' . htmlspecialchars($this->extFieldLists['queryLimit']) . '" name="SET[queryLimit]" id="queryLimit"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . '>' . $this->updateIcon();
1376 $prevLimit = $this->limitBegin - $this->limitLength < 0 ? 0 : $this->limitBegin - $this->limitLength;
1377 if ($this->limitBegin) {
1378 $prevButton = '<input type="button" value="previous ' . $this->limitLength . '" onclick=\'document.getElementById("queryLimit").value="' . $prevLimit . ',' . $this->limitLength . '";document.forms[0].submit();\'>';
1379 }
1380 if (!$this->limitLength) {
1381 $this->limitLength = 100;
1382 }
1383 $nextLimit = $this->limitBegin + $this->limitLength;
1384 if ($nextLimit < 0) {
1385 $nextLimit = 0;
1386 }
1387 if ($nextLimit) {
1388 $nextButton = '<input type="button" value="next ' . $this->limitLength . '" onclick=\'document.getElementById("queryLimit").value="' . $nextLimit . ',' . $this->limitLength . '";document.forms[0].submit();\'>';
1389 }
1390 $numberButtons = '<input type="button" value="10" onclick=\'document.getElementById("queryLimit").value="10";document.forms[0].submit();\'>';
1391 $numberButtons .= '<input type="button" value="20" onclick=\'document.getElementById("queryLimit").value="20";document.forms[0].submit();\'>';
1392 $numberButtons .= '<input type="button" value="50" onclick=\'document.getElementById("queryLimit").value="50";document.forms[0].submit();\'>';
1393 $numberButtons .= '<input type="button" value="100" onclick=\'document.getElementById("queryLimit").value="100";document.forms[0].submit();\'>';
1394 $out .= '<tr>
1395 <td' . $TDparams . '><strong>Limit:</strong></td>
1396 <td' . $TDparams . '>' . $limit . $prevButton . $nextButton . '&nbsp;' . $numberButtons . '</td>
1397 </tr>
1398 ';
1399 }
1400 }
1401 $out = '<table border="0" cellpadding="3" cellspacing="1" class="qg-make-query">' . $out . '</table>';
1402 $out .= $this->JSbottom($this->formName);
1403 return $out;
1404 }
1405
1406 /**
1407 * Get tree list
1408 *
1409 * @param int $id
1410 * @param int $depth
1411 * @param int $begin
1412 * @param string $perms_clause
1413 * @return string
1414 */
1415 public function getTreeList($id, $depth, $begin = 0, $perms_clause) {
1416 $depth = (int)$depth;
1417 $begin = (int)$begin;
1418 $id = (int)$id;
1419 if ($id < 0) {
1420 $id = abs($id);
1421 }
1422 if ($begin == 0) {
1423 $theList = $id;
1424 } else {
1425 $theList = '';
1426 }
1427 if ($id && $depth > 0) {
1428 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid=' . $id . ' ' . BackendUtility::deleteClause('pages') . ' AND ' . $perms_clause);
1429 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1430 if ($begin <= 0) {
1431 $theList .= ',' . $row['uid'];
1432 }
1433 if ($depth > 1) {
1434 $theList .= $this->getTreeList($row['uid'], $depth - 1, $begin - 1, $perms_clause);
1435 }
1436 }
1437 $GLOBALS['TYPO3_DB']->sql_free_result($res);
1438 }
1439 return $theList;
1440 }
1441
1442 /**
1443 * Get select query
1444 *
1445 * @param string $qString
1446 * @param string $fieldName
1447 * @return bool|\mysqli_result|object
1448 */
1449 public function getSelectQuery($qString = '', $fieldName = '') {
1450 if (!$qString) {
1451 $qString = $this->getQuery($this->queryConfig);
1452 }
1453 $qString = '(' . $qString . ')';
1454 if (!$GLOBALS['BE_USER']->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
1455 $webMounts = $GLOBALS['BE_USER']->returnWebmounts();
1456 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
1457 $webMountPageTree = '';
1458 foreach ($webMounts as $key => $val) {
1459 if ($webMountPageTree) {
1460 $webMountPageTreePrefix = ',';
1461 }
1462 $webMountPageTree .= $webMountPageTreePrefix . $this->getTreeList($val, 999, ($begin = 0), $perms_clause);
1463 }
1464 if ($this->table == 'pages') {
1465 $qString .= ' AND uid IN (' . $webMountPageTree . ')';
1466 } else {
1467 $qString .= ' AND pid IN (' . $webMountPageTree . ')';
1468 }
1469 }
1470 $fieldlist = $this->extFieldLists['queryFields'] . ',pid' . ($GLOBALS['TCA'][$this->table]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$this->table]['ctrl']['delete'] : '');
1471 if (!$GLOBALS['SOBE']->MOD_SETTINGS['show_deleted']) {
1472 $qString .= BackendUtility::deleteClause($this->table);
1473 }
1474 $query = $GLOBALS['TYPO3_DB']->SELECTquery($fieldlist, $this->table, $qString, trim($this->extFieldLists['queryGroup']), $this->extFieldLists['queryOrder'] ? trim($this->extFieldLists['queryOrder_SQL']) : '', $this->extFieldLists['queryLimit']);
1475 return $query;
1476 }
1477
1478 /**
1479 * JavaScript bottom
1480 *
1481 * @param string $formname
1482 * @return string
1483 */
1484 public function JSbottom($formname) {
1485 $out = '';
1486 if ($this->extJSCODE) {
1487 $out .= '
1488 <script language="javascript" type="text/javascript" src="' . $GLOBALS['BACK_PATH'] . 'sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js"></script>
1489 <script language="javascript" type="text/javascript" src="' . $GLOBALS['BACK_PATH'] . 'sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js"></script>
1490 <script language="javascript" type="text/javascript">
1491 TBE_EDITOR.formname = "' . $formname . '";
1492 TBE_EDITOR.formnameUENC = "' . rawurlencode($formname) . '";
1493 TBE_EDITOR.backend_interface = "' . $GLOBALS['BE_USER']->uc['interfaceSetup'] . '";
1494 ' . $this->extJSCODE . '
1495 </script>';
1496 }
1497 return $out;
1498 }
1499
1500 /**
1501 * Sets the current name of the input form.
1502 *
1503 * @param string $formName The name of the form.
1504 * @return void
1505 */
1506 public function setFormName($formName) {
1507 $this->formName = trim($formName);
1508 }
1509
1510 }