TYPO3 CMS  TYPO3_7-6
QueryGenerator.php
Go to the documentation of this file.
1 <?php
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 
23 
28 {
32  public $lang = [
33  'OR' => 'or',
34  'AND' => 'and',
35  'comparison' => [
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 
94  public $compSQL = [
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 
152  public $comp_offsets = [
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 
167  public $noWrap = ' nowrap';
168 
174  public $name;
175 
181  public $table;
182 
186  public $tableArray;
187 
193  public $fieldList;
194 
200  public $fields = [];
201 
205  public $extFieldLists = [];
206 
212  public $queryConfig = [];
213 
217  public $enablePrefix = false;
218 
222  public $enableQueryParts = false;
223 
228  public $extJSCODE = '';
229 
233  protected $formName = '';
234 
238  protected $limitBegin;
239 
243  protected $limitLength;
244 
248  protected $fieldName;
249 
255  public function makeFieldList()
256  {
257  $fieldListArr = [];
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 
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 
416  public function setAndCleanUpExternalLists($name, $list, $force = '')
417  {
418  $fields = array_unique(GeneralUtility::trimExplode(',', $list . ',' . $force, true));
419  $reList = [];
420  foreach ($fields as $fieldName) {
421  if ($this->fields[$fieldName]) {
422  $reList[] = $fieldName;
423  }
424  }
425  $this->extFieldLists[$name] = implode(',', $reList);
426  }
427 
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 = count($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 = count($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 = count($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 = count($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 = count($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 = count($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]] = [
501  'type' => 'newlevel',
502  'operator' => $tempEl['operator'],
503  'nl' => [$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 = count($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 
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 (!isset($queryConfig[0]) || empty($queryConfig[0]['type'])) {
546  // Make sure queryConfig is an array
547  $queryConfig = [];
548  $queryConfig[0] = ['type' => 'FIELD_'];
549  }
550  }
551  // Traverse:
552  foreach ($queryConfig as $key => $conf) {
553  $fieldName = '';
554  if (substr($conf['type'], 0, 6) === 'FIELD_') {
555  $fieldName = substr($conf['type'], 6);
556  $fieldType = $this->fields[$fieldName]['type'];
557  } elseif ($conf['type'] === 'newlevel') {
558  $fieldType = $conf['type'];
559  } else {
560  $fieldType = 'ignore';
561  }
562  switch ($fieldType) {
563  case 'newlevel':
564  if (!$queryConfig[$key]['nl']) {
565  $queryConfig[$key]['nl'][0]['type'] = 'FIELD_';
566  }
567  $queryConfig[$key]['nl'] = $this->cleanUpQueryConfig($queryConfig[$key]['nl']);
568  break;
569  case 'userdef':
570  $queryConfig[$key] = $this->userDefCleanUp($queryConfig[$key]);
571  break;
572  case 'ignore':
573  default:
574  $verifiedName = $this->verifyType($fieldName);
575  $queryConfig[$key]['type'] = 'FIELD_' . $this->verifyType($verifiedName);
576  if ($conf['comparison'] >> 5 != $this->comp_offsets[$fieldType]) {
577  $conf['comparison'] = $this->comp_offsets[$fieldType] << 5;
578  }
579  $queryConfig[$key]['comparison'] = $this->verifyComparison($conf['comparison'], $conf['negate'] ? 1 : 0);
580  $queryConfig[$key]['inputValue'] = $this->cleanInputVal($queryConfig[$key]);
581  $queryConfig[$key]['inputValue1'] = $this->cleanInputVal($queryConfig[$key], 1);
582  }
583  }
584  return $queryConfig;
585  }
586 
595  public function getFormElements($subLevel = 0, $queryConfig = '', $parent = '')
596  {
597  $codeArr = [];
598  if (!is_array($queryConfig)) {
600  }
601  $c = 0;
602  $arrCount = 0;
603  $loopCount = 0;
604  foreach ($queryConfig as $key => $conf) {
605  $fieldName = '';
606  $subscript = $parent . '[' . $key . ']';
607  $lineHTML = [];
608  $lineHTML[] = $this->mkOperatorSelect($this->name . $subscript, $conf['operator'], $c, $conf['type'] != 'FIELD_');
609  if (substr($conf['type'], 0, 6) === 'FIELD_') {
610  $fieldName = substr($conf['type'], 6);
611  $this->fieldName = $fieldName;
612  $fieldType = $this->fields[$fieldName]['type'];
613  if ($conf['comparison'] >> 5 != $this->comp_offsets[$fieldType]) {
614  $conf['comparison'] = $this->comp_offsets[$fieldType] << 5;
615  }
616  //nasty nasty...
617  //make sure queryConfig contains _actual_ comparevalue.
618  //mkCompSelect don't care, but getQuery does.
619  $queryConfig[$key]['comparison'] += isset($conf['negate']) - $conf['comparison'] % 2;
620  } elseif ($conf['type'] === 'newlevel') {
621  $fieldType = $conf['type'];
622  } else {
623  $fieldType = 'ignore';
624  }
625  $fieldPrefix = htmlspecialchars($this->name . $subscript);
626  switch ($fieldType) {
627  case 'ignore':
628  break;
629  case 'newlevel':
630  if (!$queryConfig[$key]['nl']) {
631  $queryConfig[$key]['nl'][0]['type'] = 'FIELD_';
632  }
633  $lineHTML[] = '<input type="hidden" name="' . $fieldPrefix . '[type]" value="newlevel">';
634  $codeArr[$arrCount]['sub'] = $this->getFormElements($subLevel + 1, $queryConfig[$key]['nl'], $subscript . '[nl]');
635  break;
636  case 'userdef':
637  $lineHTML[] = $this->userDef($fieldPrefix, $conf, $fieldName, $fieldType);
638  break;
639  case 'date':
640  $lineHTML[] = '<div class="form-inline">';
641  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
642  if ($conf['comparison'] === 100 || $conf['comparison'] === 101) {
643  // between
644  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue]', $conf['inputValue'], 'date');
645  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue1]', $conf['inputValue1'], 'date');
646  } else {
647  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue]', $conf['inputValue'], 'date');
648  }
649  $lineHTML[] = '</div>';
650  break;
651  case 'time':
652  $lineHTML[] = '<div class="form-inline">';
653  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
654  if ($conf['comparison'] === 100 || $conf['comparison'] === 101) {
655  // between:
656  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue]', $conf['inputValue'], 'datetime');
657  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue1]', $conf['inputValue1'], 'datetime');
658  } else {
659  $lineHTML[] = $this->getDateTimePickerField($fieldPrefix . '[inputValue]', $conf['inputValue'], 'datetime');
660  }
661  $lineHTML[] = '</div>';
662  break;
663  case 'multiple':
664  case 'binary':
665  case 'relation':
666  $lineHTML[] = '<div class="form-inline">';
667  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
668  if ($conf['comparison'] === 68 || $conf['comparison'] === 69 || $conf['comparison'] === 162 || $conf['comparison'] === 163) {
669  $lineHTML[] = '<select class="form-control" name="' . $fieldPrefix . '[inputValue]' . '[]" multiple="multiple">';
670  } elseif ($conf['comparison'] === 66 || $conf['comparison'] === 67) {
671  if (is_array($conf['inputValue'])) {
672  $conf['inputValue'] = implode(',', $conf['inputValue']);
673  }
674  $lineHTML[] = '<input class="form-control t3js-clearable" type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $fieldPrefix . '[inputValue]' . '">';
675  } else {
676  $lineHTML[] = '<select class="form-control t3js-submit-change" name="' . $fieldPrefix . '[inputValue]' . '">';
677  }
678  if ($conf['comparison'] != 66 && $conf['comparison'] != 67) {
679  $lineHTML[] = $this->makeOptionList($fieldName, $conf, $this->table);
680  $lineHTML[] = '</select>';
681  }
682  $lineHTML[] = '</div>';
683  break;
684  case 'files':
685  $lineHTML[] = '<div class="form-inline">';
686  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
687  if ($conf['comparison'] === 68 || $conf['comparison'] === 69) {
688  $lineHTML[] = '<select class="form-control" name="' . $fieldPrefix . '[inputValue]' . '[]" multiple="multiple">';
689  } else {
690  $lineHTML[] = '<select class="form-control t3js-submit-change" name="' . $fieldPrefix . '[inputValue]' . '">';
691  }
692  $lineHTML[] = '<option value=""></option>' . $this->makeOptionList($fieldName, $conf, $this->table);
693  $lineHTML[] = '</select>';
694  if ($conf['comparison'] === 66 || $conf['comparison'] === 67) {
695  $lineHTML[] = ' + <input class="form-control t3js-clearable" type="text" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $fieldPrefix . '[inputValue1]' . '">';
696  }
697  $lineHTML[] = '</div>';
698  break;
699  case 'boolean':
700  $lineHTML[] = '<div class="form-inline">';
701  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
702  $lineHTML[] = '<input type="hidden" value="1" name="' . $fieldPrefix . '[inputValue]' . '">';
703  $lineHTML[] = '</div>';
704  break;
705  default:
706  $lineHTML[] = '<div class="form-inline">';
707  $lineHTML[] = $this->makeComparisonSelector($subscript, $fieldName, $conf);
708  if ($conf['comparison'] === 37 || $conf['comparison'] === 36) {
709  // between:
710  $lineHTML[] = '<input class="form-control t3js-clearable" type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $fieldPrefix . '[inputValue]' . '">';
711  $lineHTML[] = '<input class="form-control t3js-clearable" type="text" value="' . htmlspecialchars($conf['inputValue1']) . '" name="' . $fieldPrefix . '[inputValue1]' . '">';
712  } else {
713  $lineHTML[] = '<input class="form-control t3js-clearable" type="text" value="' . htmlspecialchars($conf['inputValue']) . '" name="' . $fieldPrefix . '[inputValue]' . '">';
714  }
715  $lineHTML[] = '</div>';
716  }
717  if ($fieldType !== 'ignore') {
718  $lineHTML[] = '<div class="btn-group action-button-group">';
719  $lineHTML[] = $this->updateIcon();
720  if ($loopCount) {
721  $lineHTML[] = '<button class="btn btn-default" title="Remove condition" name="qG_del' . htmlspecialchars($subscript) . '"><i class="fa fa-trash fa-fw"></i></button>';
722  }
723  $lineHTML[] = '<button class="btn btn-default" title="Add condition" name="qG_ins' . htmlspecialchars($subscript) . '"><i class="fa fa-plus fa-fw"></i></button>';
724  if ($c != 0) {
725  $lineHTML[] = '<button class="btn btn-default" title="Move up" name="qG_up' . htmlspecialchars($subscript) . '"><i class="fa fa-chevron-up fa-fw"></i></button>';
726  }
727  if ($c != 0 && $fieldType != 'newlevel') {
728  $lineHTML[] = '<button class="btn btn-default" title="New level" name="qG_nl' . htmlspecialchars($subscript) . '"><i class="fa fa-chevron-right fa-fw"></i></button>';
729  }
730  if ($fieldType === 'newlevel') {
731  $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>';
732  }
733  $lineHTML[] = '</div>';
734  $codeArr[$arrCount]['html'] = implode(LF, $lineHTML);
735  $codeArr[$arrCount]['query'] = $this->getQuerySingle($conf, $c > 0 ? 0 : 1);
736  $arrCount++;
737  $c++;
738  }
739  $loopCount = 1;
740  }
741  $this->queryConfig = $queryConfig;
742  return $codeArr;
743  }
744 
752  protected function makeComparisonSelector($subscript, $fieldName, $conf)
753  {
754  $fieldPrefix = $this->name . $subscript;
755  $lineHTML = [];
756  $lineHTML[] = $this->mkTypeSelect($fieldPrefix . '[type]', $fieldName);
757  $lineHTML[] = ' <div class="input-group">';
758  $lineHTML[] = $this->mkCompSelect($fieldPrefix . '[comparison]', $conf['comparison'], $conf['negate'] ? 1 : 0);
759  $lineHTML[] = ' <div class="input-group-addon">';
760  $lineHTML[] = ' <input type="checkbox" class="checkbox t3js-submit-click"' . ($conf['negate'] ? ' checked' : '') . ' name="' . htmlspecialchars($fieldPrefix) . '[negate]' . '">';
761  $lineHTML[] = ' </div>';
762  $lineHTML[] = ' </div>';
763  return implode(LF, $lineHTML);
764  }
765 
774  public function makeOptionList($fieldName, $conf, $table)
775  {
776  $out = [];
777  $fieldSetup = $this->fields[$fieldName];
778  $languageService = $this->getLanguageService();
779  if ($fieldSetup['type'] === 'files') {
780  if ($conf['comparison'] === 66 || $conf['comparison'] === 67) {
781  $fileExtArray = explode(',', $fieldSetup['allowed']);
782  natcasesort($fileExtArray);
783  foreach ($fileExtArray as $fileExt) {
784  if (GeneralUtility::inList($conf['inputValue'], $fileExt)) {
785  $out[] = '<option value="' . htmlspecialchars($fileExt) . '" selected>.' . htmlspecialchars($fileExt) . '</option>';
786  } else {
787  $out[] = '<option value="' . htmlspecialchars($fileExt) . '">.' . htmlspecialchars($fileExt) . '</option>';
788  }
789  }
790  }
791  $d = dir(PATH_site . $fieldSetup['uploadfolder']);
792  while (false !== ($entry = $d->read())) {
793  if ($entry === '.' || $entry === '..') {
794  continue;
795  }
796  $fileArray[] = $entry;
797  }
798  $d->close();
799  natcasesort($fileArray);
800  foreach ($fileArray as $fileName) {
801  if (GeneralUtility::inList($conf['inputValue'], $fileName)) {
802  $out[] = '<option value="' . htmlspecialchars($fileName) . '" selected>' . htmlspecialchars($fileName) . '</option>';
803  } else {
804  $out[] = '<option value="' . htmlspecialchars($fileName) . '">' . htmlspecialchars($fileName) . '</option>';
805  }
806  }
807  }
808  if ($fieldSetup['type'] === 'multiple') {
809  foreach ($fieldSetup['items'] as $key => $val) {
810  if (substr($val[0], 0, 4) === 'LLL:') {
811  $value = $languageService->sL($val[0]);
812  } else {
813  $value = $val[0];
814  }
815  if (GeneralUtility::inList($conf['inputValue'], $val[1])) {
816  $out[] = '<option value="' . htmlspecialchars($val[1]) . '" selected>' . htmlspecialchars($value) . '</option>';
817  } else {
818  $out[] = '<option value="' . htmlspecialchars($val[1]) . '">' . htmlspecialchars($value) . '</option>';
819  }
820  }
821  }
822  if ($fieldSetup['type'] === 'binary') {
823  foreach ($fieldSetup['items'] as $key => $val) {
824  if (substr($val[0], 0, 4) === 'LLL:') {
825  $value = $languageService->sL($val[0]);
826  } else {
827  $value = $val[0];
828  }
829  if (GeneralUtility::inList($conf['inputValue'], pow(2, $key))) {
830  $out[] = '<option value="' . pow(2, $key) . '" selected>' . htmlspecialchars($value) . '</option>';
831  } else {
832  $out[] = '<option value="' . pow(2, $key) . '">' . htmlspecialchars($value) . '</option>';
833  }
834  }
835  }
836  if ($fieldSetup['type'] === 'relation') {
837  $databaseConnection = $this->getDatabaseConnection();
838  $useTablePrefix = 0;
839  $dontPrefixFirstTable = 0;
840  if ($fieldSetup['items']) {
841  foreach ($fieldSetup['items'] as $key => $val) {
842  if (substr($val[0], 0, 4) === 'LLL:') {
843  $value = $languageService->sL($val[0]);
844  } else {
845  $value = $val[0];
846  }
847  if (GeneralUtility::inList($conf['inputValue'], $val[1])) {
848  $out[] = '<option value="' . htmlspecialchars($val[1]) . '" selected>' . htmlspecialchars($value) . '</option>';
849  } else {
850  $out[] = '<option value="' . htmlspecialchars($val[1]) . '">' . htmlspecialchars($value) . '</option>';
851  }
852  }
853  }
854  if (stristr($fieldSetup['allowed'], ',')) {
855  $from_table_Arr = explode(',', $fieldSetup['allowed']);
856  $useTablePrefix = 1;
857  if (!$fieldSetup['prepend_tname']) {
858  $checkres = $databaseConnection->exec_SELECTquery($fieldName, $table, BackendUtility::deleteClause($table), ($groupBy = ''), ($orderBy = ''), ($limit = ''));
859  if ($checkres) {
860  while ($row = $databaseConnection->sql_fetch_assoc($checkres)) {
861  if (stristr($row[$fieldName], ',')) {
862  $checkContent = explode(',', $row[$fieldName]);
863  foreach ($checkContent as $singleValue) {
864  if (!stristr($singleValue, '_')) {
865  $dontPrefixFirstTable = 1;
866  }
867  }
868  } else {
869  $singleValue = $row[$fieldName];
870  if ($singleValue !== '' && !stristr($singleValue, '_')) {
871  $dontPrefixFirstTable = 1;
872  }
873  }
874  }
875  $databaseConnection->sql_free_result($checkres);
876  }
877  }
878  } else {
879  $from_table_Arr[0] = $fieldSetup['allowed'];
880  }
881  if ($fieldSetup['prepend_tname']) {
882  $useTablePrefix = 1;
883  }
884  if ($fieldSetup['foreign_table']) {
885  $from_table_Arr[0] = $fieldSetup['foreign_table'];
886  }
887  $counter = 0;
888  $webMountPageTree = '';
889  $tablePrefix = '';
890  $backendUserAuthentication = $this->getBackendUserAuthentication();
891  $module = $this->getModule();
892  $outArray = [];
893  $labelFieldSelect = [];
894  foreach ($from_table_Arr as $from_table) {
895  $useSelectLabels = false;
896  $useAltSelectLabels = false;
897  if ($useTablePrefix && !$dontPrefixFirstTable && $counter != 1 || $counter === 1) {
898  $tablePrefix = $from_table . '_';
899  }
900  $counter = 1;
901  if (is_array($GLOBALS['TCA'][$from_table])) {
902  $labelField = $GLOBALS['TCA'][$from_table]['ctrl']['label'];
903  $altLabelField = $GLOBALS['TCA'][$from_table]['ctrl']['label_alt'];
904  if ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items']) {
905  foreach ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items'] as $labelArray) {
906  if (substr($labelArray[0], 0, 4) === 'LLL:') {
907  $labelFieldSelect[$labelArray[1]] = $languageService->sL($labelArray[0]);
908  } else {
909  $labelFieldSelect[$labelArray[1]] = $labelArray[0];
910  }
911  }
912  $useSelectLabels = true;
913  }
914  if ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items']) {
915  foreach ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items'] as $altLabelArray) {
916  if (substr($altLabelArray[0], 0, 4) === 'LLL:') {
917  $altLabelFieldSelect[$altLabelArray[1]] = $languageService->sL($altLabelArray[0]);
918  } else {
919  $altLabelFieldSelect[$altLabelArray[1]] = $altLabelArray[0];
920  }
921  }
922  $useAltSelectLabels = true;
923  }
924  $altLabelFieldSelect = $altLabelField ? ',' . $altLabelField : '';
925  $select_fields = 'uid,' . $labelField . $altLabelFieldSelect;
926  if (!$backendUserAuthentication->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
927  $webMounts = $backendUserAuthentication->returnWebmounts();
928  $perms_clause = $backendUserAuthentication->getPagePermsClause(1);
929  $webMountPageTreePrefix = '';
930  foreach ($webMounts as $key => $val) {
931  if ($webMountPageTree) {
932  $webMountPageTreePrefix = ',';
933  }
934  $webMountPageTree .= $webMountPageTreePrefix . $this->getTreeList($val, 999, ($begin = 0), $perms_clause);
935  }
936  if ($from_table === 'pages') {
937  $where_clause = 'uid IN (' . $webMountPageTree . ') ';
938  if (!$module->MOD_SETTINGS['show_deleted']) {
939  $where_clause .= BackendUtility::deleteClause($from_table) . ' AND' . $perms_clause;
940  }
941  } else {
942  $where_clause = 'pid IN (' . $webMountPageTree . ') ';
943  if (!$module->MOD_SETTINGS['show_deleted']) {
944  $where_clause .= BackendUtility::deleteClause($from_table);
945  }
946  }
947  } else {
948  $where_clause = 'uid';
949  if (!$module->MOD_SETTINGS['show_deleted']) {
950  $where_clause .= BackendUtility::deleteClause($from_table);
951  }
952  }
953  $orderBy = 'uid';
954  if (!$this->tableArray[$from_table]) {
955  $res = $databaseConnection->exec_SELECTquery($select_fields, $from_table, $where_clause, ($groupBy = ''), $orderBy, ($limit = ''));
956  if ($res) {
957  while ($row = $databaseConnection->sql_fetch_assoc($res)) {
958  $this->tableArray[$from_table][] = $row;
959  }
960  $databaseConnection->sql_free_result($res);
961  }
962  }
963  foreach ($this->tableArray[$from_table] as $key => $val) {
964  if ($useSelectLabels) {
965  $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($labelFieldSelect[$val[$labelField]]);
966  } elseif ($val[$labelField]) {
967  $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($val[$labelField]);
968  } elseif ($useAltSelectLabels) {
969  $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($altLabelFieldSelect[$val[$altLabelField]]);
970  } else {
971  $outArray[$tablePrefix . $val['uid']] = htmlspecialchars($val[$altLabelField]);
972  }
973  }
974  if ($module->MOD_SETTINGS['options_sortlabel'] && is_array($outArray)) {
975  natcasesort($outArray);
976  }
977  }
978  }
979  foreach ($outArray as $key2 => $val2) {
980  if (GeneralUtility::inList($conf['inputValue'], $key2)) {
981  $out[] = '<option value="' . htmlspecialchars($key2) . '" selected>[' . htmlspecialchars($key2) . '] ' . htmlspecialchars($val2) . '</option>';
982  } else {
983  $out[] = '<option value="' . htmlspecialchars($key2) . '">[' . htmlspecialchars($key2) . '] ' . htmlspecialchars($val2) . '</option>';
984  }
985  }
986  }
987  return implode(LF, $out);
988  }
989 
997  public function printCodeArray($codeArr, $recursionLevel = 0)
998  {
999  $indent = 'row-group';
1000  if ($recursionLevel) {
1001  $indent = 'row-group indent indent-' . (int)$recursionLevel;
1002  }
1003  $out = [];
1004  foreach ($codeArr as $k => $v) {
1005  $out[] = '<div class="' . $indent . '">';
1006  $out[] = $v['html'];
1007 
1008  if ($this->enableQueryParts) {
1009  $out[] = '<pre>';
1010  $out[] = htmlspecialchars($v['query']);
1011  $out[] = '</pre>';
1012  }
1013  if (is_array($v['sub'])) {
1014  $out[] = '<div class="' . $indent . '">';
1015  $out[] = $this->printCodeArray($v['sub'], ($recursionLevel + 1));
1016  $out[] = '</div>';
1017  }
1018 
1019  $out[] = '</div>';
1020  }
1021  return implode(LF, $out);
1022  }
1023 
1031  public function formatQ($str)
1032  {
1034  return htmlspecialchars($str);
1035  }
1036 
1046  public function mkOperatorSelect($name, $op, $draw, $submit)
1047  {
1048  $out = [];
1049  if ($draw) {
1050  $out[] = '<select class="form-control from-control-operator' . ($submit ? ' t3js-submit-change' : '') . '" name="' . htmlspecialchars($name) . '[operator]">';
1051  $out[] = ' <option value="AND"' . (!$op || $op === 'AND' ? ' selected' : '') . '>' . htmlspecialchars($this->lang['AND']) . '</option>';
1052  $out[] = ' <option value="OR"' . ($op === 'OR' ? ' selected' : '') . '>' . htmlspecialchars($this->lang['OR']) . '</option>';
1053  $out[] = '</select>';
1054  } else {
1055  $out[] = '<input type="hidden" value="' . htmlspecialchars($op) . '" name="' . htmlspecialchars($name) . '[operator]">';
1056  }
1057  return implode(LF, $out);
1058  }
1059 
1068  public function mkTypeSelect($name, $fieldName, $prepend = 'FIELD_')
1069  {
1070  $out = [];
1071  $out[] = '<select class="form-control t3js-submit-change" name="' . htmlspecialchars($name) . '">';
1072  $out[] = '<option value=""></option>';
1073  foreach ($this->fields as $key => $value) {
1074  if (!$value['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $this->table . ':' . $key)) {
1075  $label = $this->fields[$key]['label'];
1076  $out[] = '<option value="' . htmlspecialchars($prepend . $key) . '"' . ($key === $fieldName ? ' selected' : '') . '>' . htmlspecialchars($label) . '</option>';
1077  }
1078  }
1079  $out[] = '</select>';
1080  return implode(LF, $out);
1081  }
1082 
1089  public function verifyType($fieldName)
1090  {
1091  $first = '';
1092  foreach ($this->fields as $key => $value) {
1093  if (!$first) {
1094  $first = $key;
1095  }
1096  if ($key === $fieldName) {
1097  return $key;
1098  }
1099  }
1100  return $first;
1101  }
1102 
1110  public function verifyComparison($comparison, $neg)
1111  {
1112  $compOffSet = $comparison >> 5;
1113  $first = -1;
1114  for ($i = 32 * $compOffSet + $neg; $i < 32 * ($compOffSet + 1); $i += 2) {
1115  if ($first === -1) {
1116  $first = $i;
1117  }
1118  if ($i >> 1 === $comparison >> 1) {
1119  return $i;
1120  }
1121  }
1122  return $first;
1123  }
1124 
1133  {
1134  $out = [];
1135  $out[] = '<div class="input-group">';
1136  $out[] = ' <div class="input-group-addon">';
1137  $out[] = ' <span class="input-group-btn">';
1138  $out[] = $this->updateIcon();
1139  $out[] = ' </span>';
1140  $out[] = ' </div>';
1141  $out[] = ' <input type="text" class="form-control t3js-clearable" value="' . htmlspecialchars($fieldName) . '" name="' . htmlspecialchars($name) . '">';
1142  $out[] = '</div>';
1143 
1144  $out[] = '<select class="form-control t3js-addfield" name="_fieldListDummy" size="5" data-field="' . htmlspecialchars($name) . '">';
1145  foreach ($this->fields as $key => $value) {
1146  if (!$value['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $this->table . ':' . $key)) {
1147  $label = $this->fields[$key]['label'];
1148  $out[] = '<option value="' . htmlspecialchars($key) . '"' . ($key === $fieldName ? ' selected' : '') . '>' . htmlspecialchars($label) . '</option>';
1149  }
1150  }
1151  $out[] = '</select>';
1152  return implode(LF, $out);
1153  }
1154 
1162  public function mkTableSelect($name, $cur)
1163  {
1164  $out = [];
1165  $out[] = '<select class="form-control t3js-submit-change" name="' . $name . '">';
1166  $out[] = '<option value=""></option>';
1167  foreach ($GLOBALS['TCA'] as $tN => $value) {
1168  if ($this->getBackendUserAuthentication()->check('tables_select', $tN)) {
1169  $out[] = '<option value="' . htmlspecialchars($tN) . '"' . ($tN === $cur ? ' selected' : '') . '>' . htmlspecialchars($this->getLanguageService()->sl($GLOBALS['TCA'][$tN]['ctrl']['title'])) . '</option>';
1170  }
1171  }
1172  $out[] = '</select>';
1173  return implode(LF, $out);
1174  }
1175 
1184  public function mkCompSelect($name, $comparison, $neg)
1185  {
1186  $compOffSet = $comparison >> 5;
1187  $out = [];
1188  $out[] = '<select class="form-control t3js-submit-change" name="' . $name . '">';
1189  for ($i = 32 * $compOffSet + $neg; $i < 32 * ($compOffSet + 1); $i += 2) {
1190  if ($this->lang['comparison'][$i . '_']) {
1191  $out[] = '<option value="' . $i . '"' . ($i >> 1 === $comparison >> 1 ? ' selected' : '') . '>' . htmlspecialchars($this->lang['comparison'][$i . '_']) . '</option>';
1192  }
1193  }
1194  $out[] = '</select>';
1195  return implode(LF, $out);
1196  }
1197 
1204  public function getSubscript($arr)
1205  {
1206  $retArr = [];
1207  while (is_array($arr)) {
1208  reset($arr);
1209  $key = key($arr);
1210  $retArr[] = $key;
1211  $arr = $arr[$key];
1212  }
1213  return $retArr;
1214  }
1215 
1221  public function initUserDef()
1222  {
1223  }
1224 
1235  public function userDef($fieldPrefix, $conf, $fieldName, $fieldType)
1236  {
1237  return '';
1238  }
1239 
1246  public function userDefCleanUp($queryConfig)
1247  {
1248  return $queryConfig;
1249  }
1250 
1258  public function getQuery($queryConfig, $pad = '')
1259  {
1260  $qs = '';
1261  // Since we don't traverse the array using numeric keys in the upcoming whileloop make sure it's fresh and clean
1262  ksort($queryConfig);
1263  $first = 1;
1264  foreach ($queryConfig as $key => $conf) {
1265  switch ($conf['type']) {
1266  case 'newlevel':
1267  $qs .= LF . $pad . trim($conf['operator']) . ' (' . $this->getQuery($queryConfig[$key]['nl'], ($pad . ' ')) . LF . $pad . ')';
1268  break;
1269  case 'userdef':
1270  $qs .= LF . $pad . $this->getUserDefQuery($conf, $first);
1271  break;
1272  default:
1273  $qs .= LF . $pad . $this->getQuerySingle($conf, $first);
1274  }
1275  $first = 0;
1276  }
1277  return $qs;
1278  }
1279 
1287  public function getQuerySingle($conf, $first)
1288  {
1289  $qs = '';
1290  $databaseConnection = $this->getDatabaseConnection();
1291  $prefix = $this->enablePrefix ? $this->table . '.' : '';
1292  if (!$first) {
1293  // Is it OK to insert the AND operator if none is set?
1294  $qs .= trim($conf['operator'] ?: 'AND') . ' ';
1295  }
1296  $qsTmp = str_replace('#FIELD#', $prefix . trim(substr($conf['type'], 6)), $this->compSQL[$conf['comparison']]);
1297  $inputVal = $this->cleanInputVal($conf);
1298  if ($conf['comparison'] === 68 || $conf['comparison'] === 69) {
1299  $inputVal = explode(',', $inputVal);
1300  foreach ($inputVal as $key => $fileName) {
1301  $inputVal[$key] = '\'' . $fileName . '\'';
1302  }
1303  $inputVal = implode(',', $inputVal);
1304  $qsTmp = str_replace('#VALUE#', $inputVal, $qsTmp);
1305  } elseif ($conf['comparison'] === 162 || $conf['comparison'] === 163) {
1306  $inputValArray = explode(',', $inputVal);
1307  $inputVal = 0;
1308  foreach ($inputValArray as $fileName) {
1309  $inputVal += (int)$fileName;
1310  }
1311  $qsTmp = str_replace('#VALUE#', $inputVal, $qsTmp);
1312  } else {
1313  $qsTmp = str_replace('#VALUE#', $databaseConnection->quoteStr($inputVal, $this->table), $qsTmp);
1314  }
1315  if ($conf['comparison'] === 37 || $conf['comparison'] === 36 || $conf['comparison'] === 66 || $conf['comparison'] === 67 || $conf['comparison'] === 100 || $conf['comparison'] === 101) {
1316  // between:
1317  $inputVal = $this->cleanInputVal($conf, '1');
1318  $qsTmp = str_replace('#VALUE1#', $databaseConnection->quoteStr($inputVal, $this->table), $qsTmp);
1319  }
1320  $qs .= trim($qsTmp);
1321  return $qs;
1322  }
1323 
1331  public function cleanInputVal($conf, $suffix = '')
1332  {
1333  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)) {
1334  $inputVal = $conf['inputValue' . $suffix];
1335  } elseif ($conf['comparison'] === 39 || $conf['comparison'] === 38) {
1336  // in list:
1337  $inputVal = implode(',', GeneralUtility::intExplode(',', $conf['inputValue' . $suffix]));
1338  } elseif ($conf['comparison'] === 68 || $conf['comparison'] === 69 || $conf['comparison'] === 162 || $conf['comparison'] === 163) {
1339  // in list:
1340  if (is_array($conf['inputValue' . $suffix])) {
1341  $inputVal = implode(',', $conf['inputValue' . $suffix]);
1342  } elseif ($conf['inputValue' . $suffix]) {
1343  $inputVal = $conf['inputValue' . $suffix];
1344  } else {
1345  $inputVal = 0;
1346  }
1347  } else {
1348  $inputVal = floatval($conf['inputValue' . $suffix]);
1349  }
1350  return $inputVal;
1351  }
1352 
1360  public function getUserDefQuery($qcArr, $first)
1361  {
1362  }
1363 
1369  public function updateIcon()
1370  {
1371  return '<button class="btn btn-default" title="Update" name="just_update"><i class="fa fa-refresh fa-fw"></i></button>';
1372  }
1373 
1379  public function getLabelCol()
1380  {
1381  return $GLOBALS['TCA'][$this->table]['ctrl']['label'];
1382  }
1383 
1391  public function makeSelectorTable($modSettings, $enableList = 'table,fields,query,group,order,limit')
1392  {
1393  $out = [];
1394  $enableArr = explode(',', $enableList);
1395  $backendUserAuthentication = $this->getBackendUserAuthentication();
1396  // Make output
1397  if (in_array('table', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableSelectATable']) {
1398  $out[] = '<div class="form-group">';
1399  $out[] = ' <label for="SET[queryTable]">Select a table:</label>';
1400  $out[] = $this->mkTableSelect('SET[queryTable]', $this->table);
1401  $out[] = '</div>';
1402  }
1403  if ($this->table) {
1404  // Init fields:
1405  $this->setAndCleanUpExternalLists('queryFields', $modSettings['queryFields'], 'uid,' . $this->getLabelCol());
1406  $this->setAndCleanUpExternalLists('queryGroup', $modSettings['queryGroup']);
1407  $this->setAndCleanUpExternalLists('queryOrder', $modSettings['queryOrder'] . ',' . $modSettings['queryOrder2']);
1408  // Limit:
1409  $this->extFieldLists['queryLimit'] = $modSettings['queryLimit'];
1410  if (!$this->extFieldLists['queryLimit']) {
1411  $this->extFieldLists['queryLimit'] = 100;
1412  }
1413  $parts = GeneralUtility::intExplode(',', $this->extFieldLists['queryLimit']);
1414  if ($parts[1]) {
1415  $this->limitBegin = $parts[0];
1416  $this->limitLength = $parts[1];
1417  } else {
1418  $this->limitLength = $this->extFieldLists['queryLimit'];
1419  }
1420  $this->extFieldLists['queryLimit'] = implode(',', array_slice($parts, 0, 2));
1421  // Insert Descending parts
1422  if ($this->extFieldLists['queryOrder']) {
1423  $descParts = explode(',', $modSettings['queryOrderDesc'] . ',' . $modSettings['queryOrder2Desc']);
1424  $orderParts = explode(',', $this->extFieldLists['queryOrder']);
1425  $reList = [];
1426  foreach ($orderParts as $kk => $vv) {
1427  $reList[] = $vv . ($descParts[$kk] ? ' DESC' : '');
1428  }
1429  $this->extFieldLists['queryOrder_SQL'] = implode(',', $reList);
1430  }
1431  // Query Generator:
1432  $this->procesData($modSettings['queryConfig'] ? unserialize($modSettings['queryConfig']) : '');
1433  $this->queryConfig = $this->cleanUpQueryConfig($this->queryConfig);
1434  $this->enableQueryParts = (bool)$modSettings['search_query_smallparts'];
1435  $codeArr = $this->getFormElements();
1436  $queryCode = $this->printCodeArray($codeArr);
1437  if (in_array('fields', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableSelectFields']) {
1438  $out[] = '<div class="form-group form-group-with-button-addon">';
1439  $out[] = ' <label for="SET[queryFields]">Select fields:</label>';
1440  $out[] = $this->mkFieldToInputSelect('SET[queryFields]', $this->extFieldLists['queryFields']);
1441  $out[] = '</div>';
1442  }
1443  if (in_array('query', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableMakeQuery']) {
1444  $out[] = '<div class="form-group">';
1445  $out[] = ' <label>Make Query:</label>';
1446  $out[] = $queryCode;
1447  $out[] = '</div>';
1448  }
1449  if (in_array('group', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableGroupBy']) {
1450  $out[] = '<div class="form-group form-inline">';
1451  $out[] = ' <label for="SET[queryGroup]">Group By:</label>';
1452  $out[] = $this->mkTypeSelect('SET[queryGroup]', $this->extFieldLists['queryGroup'], '');
1453  $out[] = '</div>';
1454  }
1455  if (in_array('order', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableOrderBy']) {
1456  $module = $this->getModule();
1457  $orderByArr = explode(',', $this->extFieldLists['queryOrder']);
1458  $orderBy = [];
1459  $orderBy[] = $this->mkTypeSelect('SET[queryOrder]', $orderByArr[0], '');
1460  $orderBy[] = '<div class="checkbox">';
1461  $orderBy[] = ' <label for="checkQueryOrderDesc">';
1462  $orderBy[] = BackendUtility::getFuncCheck($module->id, 'SET[queryOrderDesc]', $modSettings['queryOrderDesc'], '', '', 'id="checkQueryOrderDesc"') . ' Descending';
1463  $orderBy[] = ' </label>';
1464  $orderBy[] = '</div>';
1465 
1466  if ($orderByArr[0]) {
1467  $orderBy[] = $this->mkTypeSelect('SET[queryOrder2]', $orderByArr[1], '');
1468  $orderBy[] = '<div class="checkbox">';
1469  $orderBy[] = ' <label for="checkQueryOrder2Desc">';
1470  $orderBy[] = BackendUtility::getFuncCheck($module->id, 'SET[queryOrder2Desc]', $modSettings['queryOrder2Desc'], '', '', 'id="checkQueryOrder2Desc"') . ' Descending';
1471  $orderBy[] = ' </label>';
1472  $orderBy[] = '</div>';
1473  }
1474  $out[] = '<div class="form-group form-inline">';
1475  $out[] = ' <label>Order By:</label>';
1476  $out[] = implode(LF, $orderBy);
1477  $out[] = '</div>';
1478  }
1479  if (in_array('limit', $enableArr) && !$backendUserAuthentication->userTS['mod.']['dbint.']['disableLimit']) {
1480  $limit = [];
1481  $limit[] = '<div class="input-group">';
1482  $limit[] = ' <div class="input-group-addon">';
1483  $limit[] = ' <span class="input-group-btn">';
1484  $limit[] = $this->updateIcon();
1485  $limit[] = ' </span>';
1486  $limit[] = ' </div>';
1487  $limit[] = ' <input type="text" class="form-control" value="' . htmlspecialchars($this->extFieldLists['queryLimit']) . '" name="SET[queryLimit]" id="queryLimit">';
1488  $limit[] = '</div>';
1489 
1490  $prevLimit = $this->limitBegin - $this->limitLength < 0 ? 0 : $this->limitBegin - $this->limitLength;
1491  $prevButton = '';
1492  $nextButton = '';
1493 
1494  if ($this->limitBegin) {
1495  $prevButton = '<input type="button" class="btn btn-default" value="previous ' . htmlspecialchars($this->limitLength) . '" data-value="' . htmlspecialchars($prevLimit . ',' . $this->limitLength) . '">';
1496  }
1497  if (!$this->limitLength) {
1498  $this->limitLength = 100;
1499  }
1500 
1501  $nextLimit = $this->limitBegin + $this->limitLength;
1502  if ($nextLimit < 0) {
1503  $nextLimit = 0;
1504  }
1505  if ($nextLimit) {
1506  $nextButton = '<input type="button" class="btn btn-default" value="next ' . htmlspecialchars($this->limitLength) . '" data-value="' . htmlspecialchars($nextLimit . ',' . $this->limitLength) . '">';
1507  }
1508 
1509  $out[] = '<div class="form-group form-group-with-button-addon">';
1510  $out[] = ' <label>Limit:</label>';
1511  $out[] = ' <div class="form-inline">';
1512  $out[] = implode(LF, $limit);
1513  $out[] = ' <div class="input-group">';
1514  $out[] = ' <div class="btn-group t3js-limit-submit">';
1515  $out[] = $prevButton;
1516  $out[] = $nextButton;
1517  $out[] = ' </div>';
1518  $out[] = ' <div class="btn-group t3js-limit-submit">';
1519  $out[] = ' <input type="button" class="btn btn-default" data-value="10" value="10">';
1520  $out[] = ' <input type="button" class="btn btn-default" data-value="20" value="20">';
1521  $out[] = ' <input type="button" class="btn btn-default" data-value="50" value="50">';
1522  $out[] = ' <input type="button" class="btn btn-default" data-value="100" value="100">';
1523  $out[] = ' </div>';
1524  $out[] = ' </div>';
1525  $out[] = ' </div>';
1526  $out[] = '</div>';
1527  }
1528  }
1529  $out[] = $this->JSbottom($this->formName);
1530  return implode(LF, $out);
1531  }
1532 
1542  public function getTreeList($id, $depth, $begin = 0, $perms_clause)
1543  {
1544  $depth = (int)$depth;
1545  $begin = (int)$begin;
1546  $id = (int)$id;
1547  if ($id < 0) {
1548  $id = abs($id);
1549  }
1550  if ($begin === 0) {
1551  $theList = $id;
1552  } else {
1553  $theList = '';
1554  }
1555  if ($id && $depth > 0) {
1556  $databaseConnection = $this->getDatabaseConnection();
1557  $res = $databaseConnection->exec_SELECTquery('uid', 'pages', 'pid=' . $id . ' ' . BackendUtility::deleteClause('pages') . ' AND ' . $perms_clause);
1558  while ($row = $databaseConnection->sql_fetch_assoc($res)) {
1559  if ($begin <= 0) {
1560  $theList .= ',' . $row['uid'];
1561  }
1562  if ($depth > 1) {
1563  $theSubList = $this->getTreeList($row['uid'], $depth - 1, $begin - 1, $perms_clause);
1564  if (!empty($theList) && !empty($theSubList) && ($theSubList[0] !== ',')) {
1565  $theList .= ',';
1566  }
1567  $theList .= $theSubList;
1568  }
1569  }
1570  $databaseConnection->sql_free_result($res);
1571  }
1572  return $theList;
1573  }
1574 
1582  public function getSelectQuery($qString = '', $fieldName = '')
1583  {
1584  $backendUserAuthentication = $this->getBackendUserAuthentication();
1585  if (!$qString) {
1586  $qString = $this->getQuery($this->queryConfig);
1587  }
1588  $qString = '(' . $qString . ')';
1589  if (!$backendUserAuthentication->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
1590  $webMounts = $backendUserAuthentication->returnWebmounts();
1591  $perms_clause = $backendUserAuthentication->getPagePermsClause(1);
1592  $webMountPageTree = '';
1593  $webMountPageTreePrefix = '';
1594  foreach ($webMounts as $key => $val) {
1595  if ($webMountPageTree) {
1596  $webMountPageTreePrefix = ',';
1597  }
1598  $webMountPageTree .= $webMountPageTreePrefix . $this->getTreeList($val, 999, ($begin = 0), $perms_clause);
1599  }
1600  if ($this->table === 'pages') {
1601  $qString .= ' AND uid IN (' . $webMountPageTree . ')';
1602  } else {
1603  $qString .= ' AND pid IN (' . $webMountPageTree . ')';
1604  }
1605  }
1606  $fieldList = $this->extFieldLists['queryFields'] . ',pid' . ($GLOBALS['TCA'][$this->table]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$this->table]['ctrl']['delete'] : '');
1607  if (!$this->getModule()->MOD_SETTINGS['show_deleted']) {
1608  $qString .= BackendUtility::deleteClause($this->table);
1609  }
1610  $query = $this->getDatabaseConnection()->SELECTquery($fieldList, $this->table, $qString, trim($this->extFieldLists['queryGroup']), $this->extFieldLists['queryOrder'] ? trim($this->extFieldLists['queryOrder_SQL']) : '', $this->extFieldLists['queryLimit']);
1611  return $query;
1612  }
1613 
1621  public function JSbottom($formname)
1622  {
1624  $out = [];
1625  if ($this->extJSCODE) {
1626  $out[] = '<script language="javascript" type="text/javascript">';
1627  $out[] = ' ' . $this->extJSCODE;
1628  $out[] = '</script>';
1629  }
1630  return implode(LF, $out);
1631  }
1632 
1640  protected function getDateTimePickerField($name, $timestamp, $type)
1641  {
1642  $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '%H:%M %m-%d-%Y' : '%H:%M %d-%m-%Y';
1643  $value = ($timestamp > 0 ? strftime($dateFormat, $timestamp) : '');
1644  $id = StringUtility::getUniqueId('dt_');
1645  $html = [];
1646  $html[] = '<div class="input-group" id="' . $id . '-wrapper">';
1647  $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 . '">';
1648  $html[] = ' <input name="' . htmlspecialchars($name) . '" value="' . (int)$timestamp . '" type="hidden">';
1649  $html[] = ' <span class="input-group-btn">';
1650  $html[] = ' <label class="btn btn-default" for="' . $id . '">';
1651  $html[] = ' <span class="fa fa-calendar"></span>';
1652  $html[] = ' </label>';
1653  $html[] = ' </span>';
1654  $html[] = '</div>';
1655  return implode(LF, $html);
1656  }
1657 
1664  public function setFormName($formName)
1665  {
1666  $this->formName = trim($formName);
1667  }
1668 
1672  protected function getDatabaseConnection()
1673  {
1674  return $GLOBALS['TYPO3_DB'];
1675  }
1676 
1680  protected function getBackendUserAuthentication()
1681  {
1682  return $GLOBALS['BE_USER'];
1683  }
1684 
1688  protected function getModule()
1689  {
1690  return $GLOBALS['SOBE'];
1691  }
1692 
1696  protected function getLanguageService()
1697  {
1698  return $GLOBALS['LANG'];
1699  }
1700 }
makeSelectorTable($modSettings, $enableList='table, fields, query, group, order, limit')
getSelectQuery($qString='', $fieldName='')
static getFuncCheck($mainParams, $elementName, $currentValue, $script='', $addParams='', $tagParams='')
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
getDateTimePickerField($name, $timestamp, $type)
init($name, $table, $fieldList='')
mkCompSelect($name, $comparison, $neg)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
makeOptionList($fieldName, $conf, $table)
mkOperatorSelect($name, $op, $draw, $submit)
printCodeArray($codeArr, $recursionLevel=0)
getTreeList($id, $depth, $begin=0, $perms_clause)
userDef($fieldPrefix, $conf, $fieldName, $fieldType)
setAndCleanUpExternalLists($name, $list, $force='')
mkTypeSelect($name, $fieldName, $prepend='FIELD_')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
getFormElements($subLevel=0, $queryConfig='', $parent='')
makeComparisonSelector($subscript, $fieldName, $conf)
static deleteClause($table, $tableAlias='')