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