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