0eca75d3064c8579c281839eecbadea1595bb881
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / SuggestElement.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Element;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2007-2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * TCEforms wizard for rendering an AJAX selector for records
31 *
32 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
33 * @author Benjamin Mack <benni@typo3.org>
34 */
35 class SuggestElement {
36
37 // Count the number of ajax selectors used
38 public $suggestCount = 0;
39
40 public $cssClass = 'typo3-TCEforms-suggest';
41
42 // Reference to t3lib_tceforms
43 public $TCEformsObj;
44
45 /**
46 * Initialize an instance of t3lib_TCEforms_suggest
47 *
48 * @param \TYPO3\CMS\Backend\Form\FormEngine $tceForms Reference to an TCEforms instance
49 * @return void
50 */
51 public function init(&$tceForms) {
52 $this->TCEformsObj =& $tceForms;
53 }
54
55 /**
56 * Renders an ajax-enabled text field. Also adds required JS
57 *
58 * @param string $fieldname The fieldname in the form
59 * @param string $table The table we render this selector for
60 * @param string $field The field we render this selector for
61 * @param array $row The row which is currently edited
62 * @param array $config The TSconfig of the field
63 * @return string The HTML code for the selector
64 */
65 public function renderSuggestSelector($fieldname, $table, $field, array $row, array $config) {
66 $this->suggestCount++;
67 $containerCssClass = $this->cssClass . ' ' . $this->cssClass . '-position-right';
68 $suggestId = 'suggest-' . $table . '-' . $field . '-' . $row['uid'];
69 if ($GLOBALS['TCA'][$table]['columns'][$field]['config']['type'] === 'flex') {
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.xml: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.xml: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 if (isset($config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters'])) {
86 $minChars = intval($config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters']);
87 }
88 // Overwrite it with minimumCharacters from TSConfig (TCEFORM) if given
89 if (isset($config['fieldTSConfig']['suggest.']['default.']['minimumCharacters'])) {
90 $minChars = intval($config['fieldTSConfig']['suggest.']['default.']['minimumCharacters']);
91 }
92 $minChars = $minChars > 0 ? $minChars : 2;
93 // Replace "-" with ucwords for the JS object name
94 $jsObj = str_replace(' ', '', ucwords(str_replace('-', ' ', \TYPO3\CMS\Core\Utility\GeneralUtility::strtolower($suggestId))));
95 $this->TCEformsObj->additionalJS_post[] = '
96 var ' . $jsObj . ' = new TCEForms.Suggest("' . $fieldname . '", "' . $table . '", "' . $field . '", "' . $row['uid'] . '", ' . $row['pid'] . ', ' . $minChars . ');
97 ' . $jsObj . '.defaultValue = "' . \TYPO3\CMS\Core\Utility\GeneralUtility::slashJS($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.findRecord')) . '";
98 ';
99 return $selector;
100 }
101
102 /**
103 * Ajax handler for the "suggest" feature in TCEforms.
104 *
105 * @param array $params The parameters from the AJAX call
106 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AJAX object representing the AJAX call
107 * @return void
108 */
109 public function processAjaxRequest($params, &$ajaxObj) {
110 // Get parameters from $_GET/$_POST
111 $search = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('value');
112 $table = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('table');
113 $field = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('field');
114 $uid = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('uid');
115 $pageId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('pid');
116 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($table);
117 // If the $uid is numeric, we have an already existing element, so get the
118 // TSconfig of the page itself or the element container (for non-page elements)
119 // otherwise it's a new element, so use given id of parent page (i.e., don't modify it here)
120 if (is_numeric($uid)) {
121 if ($table == 'pages') {
122 $pageId = $uid;
123 } else {
124 $row = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $uid);
125 $pageId = $row['pid'];
126 }
127 }
128 $TSconfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig($pageId);
129 $queryTables = array();
130 $foreign_table_where = '';
131 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
132 $parts = explode('|', $field);
133 if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] === 'flex') {
134 if (is_array($row) && count($row) > 0) {
135 $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config'];
136 $flexformDSArray = \TYPO3\CMS\Backend\Utility\BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table);
137 $flexformDSArray = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveAllSheetsInDS($flexformDSArray);
138 $flexformElement = $parts[count($parts) - 2];
139 $continue = TRUE;
140 foreach ($flexformDSArray as $sheet) {
141 foreach ($sheet as $_ => $dataStructure) {
142 if (isset($dataStructure['ROOT']['el'][$flexformElement]['TCEforms']['config'])) {
143 $fieldConfig = $dataStructure['ROOT']['el'][$flexformElement]['TCEforms']['config'];
144 $continue = FALSE;
145 break;
146 }
147 }
148 if (!$continue) {
149 break;
150 }
151 }
152 $field = str_replace('|', '][', $field);
153 }
154 }
155 $wizardConfig = $fieldConfig['wizards']['suggest'];
156 if (isset($fieldConfig['allowed'])) {
157 $queryTables = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
158 } elseif (isset($fieldConfig['foreign_table'])) {
159 $queryTables = array($fieldConfig['foreign_table']);
160 $foreign_table_where = $fieldConfig['foreign_table_where'];
161 // strip ORDER BY clause
162 $foreign_table_where = trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $foreign_table_where));
163 }
164 $resultRows = array();
165 // fetch the records for each query table. A query table is a table from which records are allowed to
166 // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
167 foreach ($queryTables as $queryTable) {
168 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($queryTable);
169 // if the table does not exist, skip it
170 if (!is_array($GLOBALS['TCA'][$queryTable]) || !count($GLOBALS['TCA'][$queryTable])) {
171 continue;
172 }
173 $config = (array) $wizardConfig['default'];
174 if (is_array($wizardConfig[$queryTable])) {
175 $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $wizardConfig[$queryTable]);
176 }
177 // merge the configurations of different "levels" to get the working configuration for this table and
178 // field (i.e., go from the most general to the most special configuration)
179 if (is_array($TSconfig['TCEFORM.']['suggest.']['default.'])) {
180 $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.']['suggest.']['default.']);
181 }
182 if (is_array($TSconfig['TCEFORM.']['suggest.'][$queryTable . '.'])) {
183 $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.']['suggest.'][$queryTable . '.']);
184 }
185 // use $table instead of $queryTable here because we overlay a config
186 // for the input-field here, not for the queried table
187 if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.'])) {
188 $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.']);
189 }
190 if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.'])) {
191 $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.']);
192 }
193 //process addWhere
194 if (!isset($config['addWhere']) && $foreign_table_where) {
195 $config['addWhere'] = $foreign_table_where;
196 }
197 if (isset($config['addWhere'])) {
198 $config['addWhere'] = strtr(' ' . $config['addWhere'], array(
199 '###THIS_UID###' => intval($uid),
200 '###CURRENT_PID###' => intval($pageId)
201 ));
202 }
203 // instantiate the class that should fetch the records for this $queryTable
204 $receiverClassName = $config['receiverClass'];
205 if (!class_exists($receiverClassName)) {
206 $receiverClassName = 'TYPO3\\CMS\\Backend\\Form\\Element\\SuggestDefaultReceiver';
207 }
208 $receiverObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
209 $params = array('value' => $search);
210 $rows = $receiverObj->queryTable($params);
211 if (empty($rows)) {
212 continue;
213 }
214 $resultRows = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge($resultRows, $rows);
215 unset($rows);
216 }
217 $listItems = array();
218 if (count($resultRows) > 0) {
219 // traverse all found records and sort them
220 $rowsSort = array();
221 foreach ($resultRows as $key => $row) {
222 $rowsSort[$key] = $row['text'];
223 }
224 asort($rowsSort);
225 $rowsSort = array_keys($rowsSort);
226 // Limit the number of items in the result list
227 $maxItems = $config['maxItemsInResultList'] ? $config['maxItemsInResultList'] : 10;
228 $maxItems = min(count($resultRows), $maxItems);
229 // put together the selector entry
230 for ($i = 0; $i < $maxItems; $i++) {
231 $row = $resultRows[$rowsSort[$i]];
232 $rowId = $row['table'] . '-' . $row['uid'] . '-' . $table . '-' . $uid . '-' . $field;
233 $listItems[] = '<li' . ($row['class'] != '' ? ' class="' . $row['class'] . '"' : '') . ' id="' . $rowId . '" style="' . $row['style'] . '">' . $row['text'] . '</li>';
234 }
235 }
236 if (count($listItems) > 0) {
237 $list = implode('', $listItems);
238 } else {
239 $list = '<li class="suggest-noresults"><i>' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.noRecordFound') . '</i></li>';
240 }
241 $list = '<ul class="' . $this->cssClass . '-resultlist">' . $list . '</ul>';
242 $ajaxObj->addContent(0, $list);
243 }
244
245 }
246
247
248 ?>