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