TYPO3 CMS  TYPO3_7-6
SingleFieldContainer.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 
28 
39 {
45  public function render()
46  {
47  $backendUser = $this->getBackendUserAuthentication();
48  $languageService = $this->getLanguageService();
49  $resultArray = $this->initializeResultArray();
50 
51  $table = $this->data['tableName'];
52  $row = $this->data['databaseRow'];
53  $fieldName = $this->data['fieldName'];
54 
55  // @todo: it should be safe at this point, this array exists ...
56  if (!is_array($this->data['processedTca']['columns'][$fieldName])) {
57  return $resultArray;
58  }
59 
60  $parameterArray = [];
61  $parameterArray['fieldConf'] = $this->data['processedTca']['columns'][$fieldName];
62 
63  $isOverlay = false;
64 
65  // This field decides whether the current record is an overlay (as opposed to being a standalone record)
66  // Based on this decision we need to trigger field exclusion or special rendering (like readOnly)
67  if (isset($this->data['processedTca']['ctrl']['transOrigPointerField'])
68  && is_array($this->data['processedTca']['columns'][$this->data['processedTca']['ctrl']['transOrigPointerField']])
69  ) {
70  $parentValue = $row[$this->data['processedTca']['ctrl']['transOrigPointerField']];
71  if (MathUtility::canBeInterpretedAsInteger($parentValue)) {
72  $isOverlay = (bool)$parentValue;
73  } elseif (is_array($parentValue)) {
74  // This case may apply if the value has been converted to an array by the select data provider
75  $isOverlay = !empty($parentValue) ? (bool)$parentValue[0] : false;
76  } elseif (is_string($parentValue) && $parentValue !== '') {
77  // This case may apply if a group definition is used in TCA and the group provider builds a weird string
78  $recordsReferencedInField = GeneralUtility::trimExplode(',', $parentValue);
79  // Pick the first record because if you set multiple records you're in trouble anyways
80  $recordIdentifierParts = GeneralUtility::trimExplode('|', $recordsReferencedInField[0]);
81  list(, $refUid) = BackendUtility::splitTable_Uid($recordIdentifierParts[0]);
82  $isOverlay = MathUtility::canBeInterpretedAsInteger($refUid) ? (bool)$refUid : false;
83  } else {
84  throw new \InvalidArgumentException('The given value for the original language field '
85  . $this->data['processedTca']['ctrl']['transOrigPointerField']
86  . ' of table ' . $table . ' contains an invalid value.', 1470742770);
87  }
88  }
89 
90  // A couple of early returns in case the field should not be rendered
91  // Check if this field is configured and editable according to exclude fields and other configuration
92  if (// Return if BE-user has no access rights to this field, @todo: another user access rights check!
93  $parameterArray['fieldConf']['exclude'] && !$backendUser->check('non_exclude_fields', $table . ':' . $fieldName)
94  || $parameterArray['fieldConf']['config']['type'] === 'passthrough'
95  // @todo: Drop option "showIfRTE" ?
96  || !$backendUser->isRTE() && $parameterArray['fieldConf']['config']['showIfRTE']
97  // Return if field should not be rendered in translated records
98  || $isOverlay && empty($parameterArray['fieldConf']['l10n_display']) && $parameterArray['fieldConf']['l10n_mode'] === 'exclude'
99  // @todo: localizationMode still needs handling!
100  || $isOverlay && $this->data['localizationMode'] && $this->data['localizationMode'] !== $parameterArray['fieldConf']['l10n_cat']
101  || $this->inlineFieldShouldBeSkipped()
102  ) {
103  return $resultArray;
104  }
105 
106  $parameterArray['fieldTSConfig'] = [];
107  if (isset($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
108  && is_array($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
109  ) {
110  $parameterArray['fieldTSConfig'] = $this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'];
111  }
112  if ($parameterArray['fieldTSConfig']['disabled']) {
113  return $resultArray;
114  }
115 
116  // Override fieldConf by fieldTSconfig:
117  $parameterArray['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($parameterArray['fieldConf']['config'], $parameterArray['fieldTSConfig']);
118  $parameterArray['itemFormElName'] = 'data[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']';
119  $parameterArray['itemFormElID'] = 'data_' . $table . '_' . $row['uid'] . '_' . $fieldName;
120  $newElementBaseName = $this->data['elementBaseName'] . '[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']';
121 
122  // The value to show in the form field.
123  $parameterArray['itemFormElValue'] = $row[$fieldName];
124  // Set field to read-only if configured for translated records to show default language content as readonly
125  if ($parameterArray['fieldConf']['l10n_display']
126  && GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'defaultAsReadonly')
127  && $isOverlay
128  ) {
129  $parameterArray['fieldConf']['config']['readOnly'] = true;
130  $parameterArray['itemFormElValue'] = $this->data['defaultLanguageRow'][$fieldName];
131  }
132 
133  if (strpos($this->data['processedTca']['ctrl']['type'], ':') === false) {
134  $typeField = $this->data['processedTca']['ctrl']['type'];
135  } else {
136  $typeField = substr($this->data['processedTca']['ctrl']['type'], 0, strpos($this->data['processedTca']['ctrl']['type'], ':'));
137  }
138  // Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
139  // This is used for eg. "type" fields and others configured with "requestUpdate"
140  if (!empty($this->data['processedTca']['ctrl']['type'])
141  && $fieldName === $typeField
142  || !empty($this->data['processedTca']['ctrl']['requestUpdate'])
143  && GeneralUtility::inList(str_replace(' ', '', $this->data['processedTca']['ctrl']['requestUpdate']), $fieldName)
144  ) {
145  if ($backendUser->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
146  $alertMsgOnChange = 'top.TYPO3.Modal.confirm(TBE_EDITOR.labels.refreshRequired.title, TBE_EDITOR.labels.refreshRequired.content).on("button.clicked", function(e) { if (e.target.name == "ok" && TBE_EDITOR.checkSubmit(-1)) { TBE_EDITOR.submitForm() } top.TYPO3.Modal.dismiss(); });';
147  } else {
148  $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
149  }
150  } else {
151  $alertMsgOnChange = '';
152  }
153 
154  // JavaScript code for event handlers:
155  $parameterArray['fieldChangeFunc'] = [];
156  $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(' . GeneralUtility::quoteJSvalue($table) . ',' . GeneralUtility::quoteJSvalue($row['uid']) . ',' . GeneralUtility::quoteJSvalue($fieldName) . ',' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ');';
157  if ($alertMsgOnChange) {
158  $parameterArray['fieldChangeFunc']['alert'] = $alertMsgOnChange;
159  }
160 
161  // If this is the child of an inline type and it is the field creating the label
162  if ($this->isInlineChildAndLabelField($table, $fieldName)) {
164  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
165  $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
166  $inlineDomObjectId = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
167  $inlineObjectId = implode(
168  '-',
169  [
170  $inlineDomObjectId,
171  $table,
172  $row['uid']
173  ]
174  );
175  $parameterArray['fieldChangeFunc']['inline'] = 'inline.handleChangedField(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ',' . GeneralUtility::quoteJSvalue($inlineObjectId) . ');';
176  }
177 
178  // Based on the type of the item, call a render function on a child element
179  $options = $this->data;
180  $options['parameterArray'] = $parameterArray;
181  $options['elementBaseName'] = $newElementBaseName;
182  if (!empty($parameterArray['fieldConf']['config']['renderType'])) {
183  $options['renderType'] = $parameterArray['fieldConf']['config']['renderType'];
184  } else {
185  // Fallback to type if no renderType is given
186  $options['renderType'] = $parameterArray['fieldConf']['config']['type'];
187  }
188  $resultArray = $this->nodeFactory->create($options)->render();
189 
190  // If output is empty stop further processing.
191  // This means there was internal processing only and we don't need to add additional information
192  if (empty($resultArray['html'])) {
193  return $resultArray;
194  }
195 
196  $html = $resultArray['html'];
197 
198  // @todo: the language handling, the null and the placeholder stuff should be embedded in the single
199  // @todo: element classes. Basically, this method should return here and have the element classes
200  // @todo: decide on language stuff and other wraps already.
201 
202  // Add language + diff
203  $renderLanguageDiff = true;
204  if ($parameterArray['fieldConf']['l10n_display'] && (GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'hideDiff')
205  || GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'defaultAsReadonly'))
206  ) {
207  $renderLanguageDiff = false;
208  }
209  if ($renderLanguageDiff) {
210  $html = $this->renderDefaultLanguageContent($table, $fieldName, $row, $html);
211  $html = $this->renderDefaultLanguageDiff($table, $fieldName, $row, $html);
212  }
213 
214  $fieldItemClasses = [
215  't3js-formengine-field-item'
216  ];
217 
218  // NULL value and placeholder handling
219  $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']');
220  if (!empty($parameterArray['fieldConf']['config']['eval']) && GeneralUtility::inList($parameterArray['fieldConf']['config']['eval'], 'null')
221  && (empty($parameterArray['fieldConf']['config']['mode']) || $parameterArray['fieldConf']['config']['mode'] !== 'useOrOverridePlaceholder')
222  ) {
223  // This field has eval=null set, but has no useOverridePlaceholder defined.
224  // Goal is to have a field that can distinct between NULL and empty string in the database.
225  // A checkbox and an additional hidden field will be created, both with the same name
226  // and prefixed with "control[active]". If the checkbox is set (value 1), the value from the casual
227  // input field will be written to the database. If the checkbox is not set, the hidden field
228  // transfers value=0 to DataHandler, the value of the input field will then be reset to NULL by the
229  // DataHandler at an early point in processing, so NULL will be written to DB as field value.
230 
231  // If the value of the field *is* NULL at the moment, an additional class is set
232  // @todo: This does not work well at the moment, but is kept for now. see input_14 of ext:styleguide as example
233  $checked = ' checked="checked"';
234  if ($this->data['databaseRow'][$fieldName] === null) {
235  $fieldItemClasses[] = 'disabled';
236  $checked = '';
237  }
238 
239  $formElementName = 'data[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']';
240  $onChange = htmlspecialchars(
241  'typo3form.fieldSetNull(' . GeneralUtility::quoteJSvalue($formElementName) . ', !this.checked)'
242  );
243 
244  $nullValueWrap = [];
245  $nullValueWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">';
246  $nullValueWrap[] = '<div class="t3-form-field-disable"></div>';
247  $nullValueWrap[] = '<div class="checkbox t3-form-field-eval-null-checkbox">';
248  $nullValueWrap[] = '<label for="' . $nullControlNameEscaped . '">';
249  $nullValueWrap[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="0" />';
250  $nullValueWrap[] = '<input type="checkbox" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1" onchange="' . $onChange . '"' . $checked . ' /> &nbsp;';
251  $nullValueWrap[] = '</label>';
252  $nullValueWrap[] = '</div>';
253  $nullValueWrap[] = $html;
254  $nullValueWrap[] = '</div>';
255 
256  $html = implode(LF, $nullValueWrap);
257  } elseif (isset($parameterArray['fieldConf']['config']['mode']) && $parameterArray['fieldConf']['config']['mode'] === 'useOrOverridePlaceholder') {
258  // This field has useOverridePlaceholder set.
259  // Here, a value from a deeper DB structure can be "fetched up" as value, and can also be overridden by a
260  // local value. This is used in FAL, where eg. the "title" field can have the default value from sys_file_metadata,
261  // the title field of sys_file_reference is then set to NULL. Or the "override" checkbox is set, and a string
262  // or an empty string is then written to the field of sys_file_reference.
263  // The situation is similar to the NULL handling above, but additionally a "default" value should be shown.
264  // To achieve this, again a hidden control[hidden] field is added together with a checkbox with the same name
265  // to transfer the information whether the default value should be used or not: Checkbox checked transfers 1 as
266  // value in control[active], meaning the overridden value should be used.
267  // Additionally to the casual input field, a second field is added containing the "placeholder" value. This
268  // field has no name attribute and is not transferred at all. Those two are then hidden / shown depending
269  // on the state of the above checkbox in via JS.
270 
271  $placeholder = empty($parameterArray['fieldConf']['config']['placeholder']) ? '' : $parameterArray['fieldConf']['config']['placeholder'];
272  $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', !this.checked)';
273  $checked = $parameterArray['itemFormElValue'] === null ? '' : ' checked="checked"';
274 
275  $resultArray['additionalJavaScriptPost'][] = 'typo3form.fieldTogglePlaceholder('
276  . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
277 
278  // Renders an input or textarea field depending on type of "parent"
279  $options = [];
280  $options['databaseRow'] = [];
281  $options['table'] = '';
282  $options['parameterArray'] = $parameterArray;
283  $options['parameterArray']['itemFormElValue'] = GeneralUtility::fixed_lgd_cs($placeholder, 30);
284  $options['renderType'] = 'none';
285  $noneElementResult = $this->nodeFactory->create($options)->render();
286  $noneElementHtml = $noneElementResult['html'];
287 
288  $placeholderWrap = [];
289  $placeholderWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">';
290  $placeholderWrap[] = '<div class="t3-form-field-disable"></div>';
291  $placeholderWrap[] = '<div class="checkbox">';
292  $placeholderWrap[] = '<label for="' . $nullControlNameEscaped . '">';
293  $placeholderWrap[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="0" />';
294  $placeholderWrap[] = '<input type="checkbox" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1" id="tce-forms-textfield-use-override-' . $fieldName . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />';
295  $placeholderWrap[] = sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'), BackendUtility::getRecordTitlePrep($placeholder, 20));
296  $placeholderWrap[] = '</label>';
297  $placeholderWrap[] = '</div>';
298  $placeholderWrap[] = '<div class="t3js-formengine-placeholder-placeholder">';
299  $placeholderWrap[] = $noneElementHtml;
300  $placeholderWrap[] = '</div>';
301  $placeholderWrap[] = '<div class="t3js-formengine-placeholder-formfield">';
302  $placeholderWrap[] = $html;
303  $placeholderWrap[] = '</div>';
304  $placeholderWrap[] = '</div>';
305 
306  $html = implode(LF, $placeholderWrap);
307  } elseif ($parameterArray['fieldConf']['config']['type'] !== 'user' || empty($parameterArray['fieldConf']['config']['noTableWrapping'])) {
308  // Add a casual wrap if the field is not of type user with no wrap requested.
309  $standardWrap = [];
310  $standardWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">';
311  $standardWrap[] = '<div class="t3-form-field-disable"></div>';
312  $standardWrap[] = $html;
313  $standardWrap[] = '</div>';
314 
315  $html = implode(LF, $standardWrap);
316  }
317 
318  $resultArray['html'] = $html;
319  return $resultArray;
320  }
321 
332  protected function renderDefaultLanguageContent($table, $field, $row, $item)
333  {
334  if (is_array($this->data['defaultLanguageRow'])) {
335  $defaultLanguageValue = BackendUtility::getProcessedValue(
336  $table,
337  $field,
338  $this->data['defaultLanguageRow'][$field],
339  0,
340  true,
341  false,
342  $this->data['defaultLanguageRow']['uid'],
343  true,
344  $this->data['defaultLanguageRow']['pid']
345  );
346  $fieldConfig = $this->data['processedTca']['columns'][$field];
347  // Don't show content if it's for IRRE child records:
348  if ($fieldConfig['config']['type'] !== 'inline') {
350  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
351  if ($defaultLanguageValue !== '') {
352  $item .= '<div class="t3-form-original-language" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank', true) . '">'
353  . $iconFactory->getIcon($this->data['systemLanguageRows'][0]['flagIconIdentifier'], Icon::SIZE_SMALL)->render()
354  . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
355  . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
356  }
357  $additionalPreviewLanguages = $this->data['additionalLanguageRows'];
358  foreach ($additionalPreviewLanguages as $previewLanguage) {
359  $defaultLanguageValue = BackendUtility::getProcessedValue(
360  $table,
361  $field,
362  $previewLanguage[$field],
363  0,
364  true
365  );
366  if ($defaultLanguageValue !== '') {
367  $item .= '<div class="t3-form-original-language" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank', true) . '">'
368  . $iconFactory->getIcon($this->data['systemLanguageRows'][$previewLanguage['sys_language_uid']]['flagIconIdentifier'], Icon::SIZE_SMALL)->render()
369  . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
370  . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
371  }
372  }
373  }
374  }
375  return $item;
376  }
377 
387  protected function getMergeBehaviourIcon($l10nMode)
388  {
389  $icon = '';
390  if ($l10nMode === 'mergeIfNotBlank') {
392  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
393  $icon = $iconFactory->getIcon('actions-edit-merge-localization', Icon::SIZE_SMALL)->render();
394  }
395  return $icon;
396  }
397 
408  protected function renderDefaultLanguageDiff($table, $field, $row, $item)
409  {
410  if (is_array($this->data['defaultLanguageDiffRow'][$table . ':' . $row['uid']])) {
411  // Initialize:
412  $dLVal = [
413  'old' => $this->data['defaultLanguageDiffRow'][$table . ':' . $row['uid']],
414  'new' => $this->data['defaultLanguageRow']
415  ];
416  // There must be diff-data:
417  if (isset($dLVal['old'][$field])) {
418  if ((string)$dLVal['old'][$field] !== (string)$dLVal['new'][$field]) {
419  // Create diff-result:
421  $diffUtility = GeneralUtility::makeInstance(DiffUtility::class);
422  $diffUtility->stripTags = false;
423  $diffres = $diffUtility->makeDiffDisplay(
424  BackendUtility::getProcessedValue($table, $field, $dLVal['old'][$field], 0, 1),
425  BackendUtility::getProcessedValue($table, $field, $dLVal['new'][$field], 0, 1)
426  );
427  $item .= '
428  <div class="t3-form-original-language-diff">
429  <div class="t3-form-original-language-diffheader">'
430  . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.changeInOrig'))
431  . '</div>
432  <div class="t3-form-original-language-diffcontent">
433  <div class="diff">
434  <div class="diff-item">
435  <div class="diff-item-result diff-item-result-inline">' . $diffres . '</div>
436  </div>
437  </div>
438  </div>
439  </div>
440  ';
441  }
442  }
443  }
444  return $item;
445  }
446 
456  protected function isInlineChildAndLabelField($table, $field)
457  {
459  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
460  $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
461  $level = $inlineStackProcessor->getStructureLevel(-1);
462  if ($level['config']['foreign_label']) {
463  $label = $level['config']['foreign_label'];
464  } else {
465  $label = $this->data['processedTca']['ctrl']['label'];
466  }
467  return $level['config']['foreign_table'] === $table && $label === $field;
468  }
469 
475  protected function inlineFieldShouldBeSkipped()
476  {
477  $table = $this->data['tableName'];
478  $row = $this->data['databaseRow'];
479  $fieldName = $this->data['fieldName'];
480  $fieldConfig = $this->data['processedTca']['columns'][$fieldName]['config'];
481 
483  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
484  $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
485  $structureDepth = $inlineStackProcessor->getStructureDepth();
486 
487  $skipThisField = false;
488  if ($structureDepth > 0) {
489  $searchArray = [
490  '%OR' => [
491  'config' => [
492  0 => [
493  '%AND' => [
494  'foreign_table' => $table,
495  '%OR' => [
496  '%AND' => [
497  'appearance' => ['useCombination' => true],
498  'foreign_selector' => $fieldName
499  ],
500  'MM' => $fieldConfig['MM']
501  ]
502  ]
503  ],
504  1 => [
505  '%AND' => [
506  'foreign_table' => $fieldConfig['foreign_table'],
507  'foreign_selector' => $fieldConfig['foreign_field']
508  ]
509  ]
510  ]
511  ]
512  ];
513  // Get the parent record from structure stack
514  $level = $inlineStackProcessor->getStructureLevel(-1);
515  // If we have symmetric fields, check on which side we are and hide fields, that are set automatically:
516  if ($this->data['isOnSymmetricSide']) {
517  $searchArray['%OR']['config'][0]['%AND']['%OR']['symmetric_field'] = $fieldName;
518  $searchArray['%OR']['config'][0]['%AND']['%OR']['symmetric_sortby'] = $fieldName;
519  } else {
520  $searchArray['%OR']['config'][0]['%AND']['%OR']['foreign_field'] = $fieldName;
521  $searchArray['%OR']['config'][0]['%AND']['%OR']['foreign_sortby'] = $fieldName;
522  }
523  $skipThisField = $this->arrayCompareComplex($level, $searchArray);
524  }
525  return $skipThisField;
526  }
527 
560  protected function arrayCompareComplex($subjectArray, $searchArray, $type = '')
561  {
562  $localMatches = 0;
563  $localEntries = 0;
564  if (is_array($searchArray) && !empty($searchArray)) {
565  // If no type was passed, try to determine
566  if (!$type) {
567  reset($searchArray);
568  $type = key($searchArray);
569  $searchArray = current($searchArray);
570  }
571  // We use '%AND' and '%OR' in uppercase
572  $type = strtoupper($type);
573  // Split regular elements from sub elements
574  foreach ($searchArray as $key => $value) {
575  $localEntries++;
576  // Process a sub-group of OR-conditions
577  if ($key === '%OR') {
578  $localMatches += $this->arrayCompareComplex($subjectArray, $value, '%OR') ? 1 : 0;
579  } elseif ($key === '%AND') {
580  $localMatches += $this->arrayCompareComplex($subjectArray, $value, '%AND') ? 1 : 0;
581  } elseif (is_array($value) && $this->isAssociativeArray($searchArray)) {
582  $localMatches += $this->arrayCompareComplex($subjectArray[$key], $value, $type) ? 1 : 0;
583  } elseif (is_array($value)) {
584  $localMatches += $this->arrayCompareComplex($subjectArray, $value, $type) ? 1 : 0;
585  } else {
586  if (isset($subjectArray[$key]) && isset($value)) {
587  // Boolean match:
588  if (is_bool($value)) {
589  $localMatches += !($subjectArray[$key] xor $value) ? 1 : 0;
590  } elseif (is_numeric($subjectArray[$key]) && is_numeric($value)) {
591  $localMatches += $subjectArray[$key] == $value ? 1 : 0;
592  } else {
593  $localMatches += $subjectArray[$key] === $value ? 1 : 0;
594  }
595  }
596  }
597  // If one or more matches are required ('OR'), return TRUE after the first successful match
598  if ($type === '%OR' && $localMatches > 0) {
599  return true;
600  }
601  // If all matches are required ('AND') and we have no result after the first run, return FALSE
602  if ($type === '%AND' && $localMatches == 0) {
603  return false;
604  }
605  }
606  }
607  // Return the result for '%AND' (if nothing was checked, TRUE is returned)
608  return $localEntries === $localMatches;
609  }
610 
617  protected function isAssociativeArray($object)
618  {
619  return is_array($object) && !empty($object) && array_keys($object) !== range(0, count($object) - 1);
620  }
621 
625  protected function getBackendUserAuthentication()
626  {
627  return $GLOBALS['BE_USER'];
628  }
629 
633  protected function getLanguageService()
634  {
635  return $GLOBALS['LANG'];
636  }
637 }
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static static overrideFieldConf($fieldConfig, $TSconfig)
arrayCompareComplex($subjectArray, $searchArray, $type='')
static fixed_lgd_cs($string, $chars, $appendString='...')
static getRecordTitlePrep($title, $titleLength=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']