TYPO3  7.6
QueryGenerator.php
Go to the documentation of this file.
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 
23 
28 {
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 
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 
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 
167  public $noWrap = ' nowrap';
168 
174  public $name;
175 
181  public $table;
182 
186  public $tableArray;
187 
193  public $fieldList;
194 
200  public $fields = array();
201 
205  public $extFieldLists = array();
206 
212  public $queryConfig = array();
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 = 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 
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 = array();
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 = 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 
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 
593  public function getFormElements($subLevel = 0, $queryConfig = '', $parent = '')
594  {
595  $codeArr = array();
596  if (!is_array($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 
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 
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 
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 
1029  public function formatQ($str)
1030  {
1032  return htmlspecialchars($str);
1033  }
1034 
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 
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 
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 
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 
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 
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 
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 
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 
1219  public function initUserDef()
1220  {
1221  }
1222 
1233  public function userDef($fieldPrefix, $conf, $fieldName, $fieldType)
1234  {
1235  return '';
1236  }
1237 
1244  public function userDefCleanUp($queryConfig)
1245  {
1246  return $queryConfig;
1247  }
1248 
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 
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 
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 
1358  public function getUserDefQuery($qcArr, $first)
1359  {
1360  }
1361 
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 
1377  public function getLabelCol()
1378  {
1379  return $GLOBALS['TCA'][$this->table]['ctrl']['label'];
1380  }
1381 
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 
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 
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 
1615  public function JSbottom($formname)
1616  {
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 
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 
1658  public function setFormName($formName)
1659  {
1660  $this->formName = trim($formName);
1661  }
1662 
1666  protected function getDatabaseConnection()
1667  {
1668  return $GLOBALS['TYPO3_DB'];
1669  }
1670 
1674  protected function getBackendUserAuthentication()
1675  {
1676  return $GLOBALS['BE_USER'];
1677  }
1678 
1682  protected function getModule()
1683  {
1684  return $GLOBALS['SOBE'];
1685  }
1686 
1690  protected function getLanguageService()
1691  {
1692  return $GLOBALS['LANG'];
1693  }
1694 }