TYPO3 CMS  TYPO3_6-2
SuggestElement.php
Go to the documentation of this file.
1 <?php
3 
20 
28 
32  public $suggestCount = 0;
33 
37  public $cssClass = 'typo3-TCEforms-suggest';
38 
42  public $TCEformsObj;
43 
50  public function init($tceForms) {
51  $this->TCEformsObj = $tceForms;
52  }
53 
64  public function renderSuggestSelector($fieldname, $table, $field, array $row, array $config) {
65  $this->suggestCount++;
66  $containerCssClass = $this->cssClass . ' ' . $this->cssClass . '-position-right';
67  $suggestId = 'suggest-' . $table . '-' . $field . '-' . $row['uid'];
68  $isFlexFormField = $GLOBALS['TCA'][$table]['columns'][$field]['config']['type'] === 'flex';
69  if ($isFlexFormField) {
70  $fieldPattern = 'data[' . $table . '][' . $row['uid'] . '][';
71  $flexformField = str_replace($fieldPattern, '', $fieldname);
72  $flexformField = substr($flexformField, 0, -1);
73  $field = str_replace(array(']['), '|', $flexformField);
74  }
75  $selector = '
76  <div class="' . $containerCssClass . '" id="' . $suggestId . '">
77  <input type="text" id="' . $fieldname . 'Suggest" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.findRecord') . '" class="' . $this->cssClass . '-search" />
78  <div class="' . $this->cssClass . '-indicator" style="display: none;" id="' . $fieldname . 'SuggestIndicator">
79  <img src="' . $GLOBALS['BACK_PATH'] . 'gfx/spinner.gif" alt="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:alttext.suggestSearching') . '" />
80  </div>
81  <div class="' . $this->cssClass . '-choices" style="display: none;" id="' . $fieldname . 'SuggestChoices"></div>
82 
83  </div>';
84  // Get minimumCharacters from TCA
85  $minChars = 0;
86  if (isset($config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters'])) {
87  $minChars = (int)$config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters'];
88  }
89  // Overwrite it with minimumCharacters from TSConfig (TCEFORM) if given
90  if (isset($config['fieldTSConfig']['suggest.']['default.']['minimumCharacters'])) {
91  $minChars = (int)$config['fieldTSConfig']['suggest.']['default.']['minimumCharacters'];
92  }
93  $minChars = $minChars > 0 ? $minChars : 2;
94 
95  // fetch the TCA field type to hand it over to the JS class
96  $type = '';
97  if (isset($config['fieldConf']['config']['type'])) {
98  $type = $config['fieldConf']['config']['type'];
99  }
100 
101  $jsRow = '';
102  if ($isFlexFormField && !MathUtility::canBeInterpretedAsInteger($row['uid'])) {
103  // Ff we have a new record, we hand that row over to JS.
104  // This way we can properly retrieve the configuration of our wizard
105  // if it is shown in a flexform
106  $jsRow = json_encode($row);
107  }
108 
109  // Replace "-" with ucwords for the JS object name
110  $jsObj = str_replace(' ', '', ucwords(str_replace(array('-', '.'), ' ', GeneralUtility::strtolower($suggestId))));
111  $this->TCEformsObj->additionalJS_post[] = '
112  var ' . $jsObj . ' = new TCEForms.Suggest('
113  . GeneralUtility::quoteJSvalue($fieldname) . ', '
114  . GeneralUtility::quoteJSvalue($table) . ', '
115  . GeneralUtility::quoteJSvalue($field) . ', '
116  . GeneralUtility::quoteJSvalue($row['uid']) . ', '
117  . (int)$row['pid'] . ', '
118  . (int)$minChars . ', '
119  . GeneralUtility::quoteJSvalue($type) . ', '
120  . GeneralUtility::quoteJSvalue($jsRow) . ');' . LF
121  . $jsObj . '.defaultValue = ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.findRecord')) . ';' . LF;
122  return $selector;
123  }
124 
133  protected function getNestedDsFieldConfig(array $dataStructure, $fieldName) {
134  $fieldConfig = array();
135  $elements = $dataStructure['ROOT']['el'] ? $dataStructure['ROOT']['el'] : $dataStructure['el'];
136  if (is_array($elements)) {
137  foreach ($elements as $k => $ds) {
138  if ($k === $fieldName) {
139  $fieldConfig = $ds['TCEforms']['config'];
140  break;
141  } elseif (isset($ds['el'][$fieldName]['TCEforms']['config'])) {
142  $fieldConfig = $ds['el'][$fieldName]['TCEforms']['config'];
143  break;
144  } else {
145  $fieldConfig = $this->getNestedDsFieldConfig($ds, $fieldName);
146  }
147  }
148  }
149  return $fieldConfig;
150  }
151 
159  public function processAjaxRequest($params, &$ajaxObj) {
160  // Get parameters from $_GET/$_POST
161  $search = GeneralUtility::_GP('value');
162  $table = GeneralUtility::_GP('table');
163  $field = GeneralUtility::_GP('field');
164  $uid = GeneralUtility::_GP('uid');
165  $pageId = GeneralUtility::_GP('pid');
166  $newRecordRow = GeneralUtility::_GP('newRecordRow');
167  // If the $uid is numeric, we have an already existing element, so get the
168  // TSconfig of the page itself or the element container (for non-page elements)
169  // otherwise it's a new element, so use given id of parent page (i.e., don't modify it here)
170  $row = NULL;
171  if (is_numeric($uid)) {
172  $row = BackendUtility::getRecord($table, $uid);
173  if ($table == 'pages') {
174  $pageId = $uid;
175  } else {
176  $pageId = $row['pid'];
177  }
178  } else {
179  $row = json_decode($newRecordRow, TRUE);
180  }
181  $TSconfig = BackendUtility::getPagesTSconfig($pageId);
182  $queryTables = array();
183  $foreign_table_where = '';
184  $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
185  $parts = explode('|', $field);
186  if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] === 'flex') {
187  $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config'];
188  $flexformDSArray = BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table, $parts[0]);
189  $flexformDSArray = GeneralUtility::resolveAllSheetsInDS($flexformDSArray);
190  $flexformElement = $parts[count($parts) - 2];
191  $continue = TRUE;
192  foreach ($flexformDSArray as $sheet) {
193  foreach ($sheet as $dataStructure) {
194  $fieldConfig = $this->getNestedDsFieldConfig($dataStructure, $flexformElement);
195  if (count($fieldConfig) > 0) {
196  $continue = FALSE;
197  break;
198  }
199  }
200  if (!$continue) {
201  break;
202  }
203  }
204  $field = str_replace('|', '][', $field);
205  }
206  $wizardConfig = $fieldConfig['wizards']['suggest'];
207  if (isset($fieldConfig['allowed'])) {
208  if ($fieldConfig['allowed'] === '*') {
209  foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) {
210  // TODO: Refactor function to BackendUtility
211  if (empty($tableConfig['ctrl']['hideTable'])
212  && ($GLOBALS['BE_USER']->isAdmin()
213  || (empty($tableConfig['ctrl']['adminOnly'])
214  && (empty($tableConfig['ctrl']['rootLevel'])
215  || !empty($tableConfig['ctrl']['security']['ignoreRootLevelRestriction']))))
216  ) {
217  $queryTables[] = $tableName;
218  }
219  }
220  unset($tableName, $tableConfig);
221  } else {
222  $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
223  }
224  } elseif (isset($fieldConfig['foreign_table'])) {
225  $queryTables = array($fieldConfig['foreign_table']);
226  $foreign_table_where = $fieldConfig['foreign_table_where'];
227  // strip ORDER BY clause
228  $foreign_table_where = trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $foreign_table_where));
229  }
230  $resultRows = array();
231  // fetch the records for each query table. A query table is a table from which records are allowed to
232  // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
233  foreach ($queryTables as $queryTable) {
234  // if the table does not exist, skip it
235  if (!is_array($GLOBALS['TCA'][$queryTable]) || !count($GLOBALS['TCA'][$queryTable])) {
236  continue;
237  }
238  $config = (array)$wizardConfig['default'];
239  if (is_array($wizardConfig[$queryTable])) {
240  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]);
241  }
242  // merge the configurations of different "levels" to get the working configuration for this table and
243  // field (i.e., go from the most general to the most special configuration)
244  if (is_array($TSconfig['TCEFORM.']['suggest.']['default.'])) {
245  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.']['default.']);
246  }
247  if (is_array($TSconfig['TCEFORM.']['suggest.'][$queryTable . '.'])) {
248  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.'][$queryTable . '.']);
249  }
250  // use $table instead of $queryTable here because we overlay a config
251  // for the input-field here, not for the queried table
252  if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.'])) {
253  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.']);
254  }
255  if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.'])) {
256  \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.']);
257  }
258  //process addWhere
259  if (!isset($config['addWhere']) && $foreign_table_where) {
260  $config['addWhere'] = $foreign_table_where;
261  }
262  if (isset($config['addWhere'])) {
263  $replacement = array(
264  '###THIS_UID###' => (int)$uid,
265  '###CURRENT_PID###' => (int)$pageId
266  );
267  if (isset($TSconfig['TCEFORM.'][$table . '.'][$field . '.'])) {
268  $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.'];
269  if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) {
270  $replacement['###PAGE_TSCONFIG_ID###'] = (int)$fieldTSconfig['PAGE_TSCONFIG_ID'];
271  }
272  if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) {
273  $replacement['###PAGE_TSCONFIG_IDLIST###'] = $GLOBALS['TYPO3_DB']->cleanIntList($fieldTSconfig['PAGE_TSCONFIG_IDLIST']);
274  }
275  if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) {
276  $replacement['###PAGE_TSCONFIG_STR###'] = $GLOBALS['TYPO3_DB']->quoteStr($fieldTSconfig['PAGE_TSCONFIG_STR'], $fieldConfig['foreign_table']);
277  }
278  }
279  $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement);
280  }
281  // instantiate the class that should fetch the records for this $queryTable
282  $receiverClassName = $config['receiverClass'];
283  if (!class_exists($receiverClassName)) {
284  $receiverClassName = 'TYPO3\\CMS\\Backend\\Form\\Element\\SuggestDefaultReceiver';
285  }
286  $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
287  $params = array('value' => $search);
288  $rows = $receiverObj->queryTable($params);
289  if (empty($rows)) {
290  continue;
291  }
292  $resultRows = GeneralUtility::array_merge($resultRows, $rows);
293  unset($rows);
294  }
295  $listItems = array();
296  if (count($resultRows) > 0) {
297  // traverse all found records and sort them
298  $rowsSort = array();
299  foreach ($resultRows as $key => $row) {
300  $rowsSort[$key] = $row['text'];
301  }
302  asort($rowsSort);
303  $rowsSort = array_keys($rowsSort);
304  // Limit the number of items in the result list
305  $maxItems = $config['maxItemsInResultList'] ?: 10;
306  $maxItems = min(count($resultRows), $maxItems);
307  // put together the selector entry
308  for ($i = 0; $i < $maxItems; $i++) {
309  $row = $resultRows[$rowsSort[$i]];
310  $rowId = $row['table'] . '-' . $row['uid'] . '-' . $table . '-' . $uid . '-' . $field;
311  $listItems[] = '<li' . ($row['class'] != '' ? ' class="' . $row['class'] . '"' : '') . ' id="' . $rowId . '"' . ($row['style'] != '' ? ' style="' . $row['style'] . '"' : '') . '>' . $row['sprite'] . $row['text'] . '</li>';
312  }
313  }
314  if (count($listItems) > 0) {
315  $list = implode('', $listItems);
316  } else {
317  $list = '<li class="suggest-noresults"><i>' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRecordFound') . '</i></li>';
318  }
319  $list = '<ul class="' . $this->cssClass . '-resultlist">' . $list . '</ul>';
320  $ajaxObj->addContent(0, $list);
321  }
322 
323 }
renderSuggestSelector($fieldname, $table, $field, array $row, array $config)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=TRUE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
static resolveAllSheetsInDS(array $dataStructArray)
$uid
Definition: server.php:36
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
static getFlexFormDS($conf, $row, $table, $fieldName='', $WSOL=TRUE, $newRecordPidValue=0)
static array_merge(array $arr1, array $arr2)
getNestedDsFieldConfig(array $dataStructure, $fieldName)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static getPagesTSconfig($id, $rootLine=NULL, $returnPartArray=FALSE)
if($ajaxRegistryEntry !==NULL) $ajaxObj
Definition: ajax.php:63