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