[TASK] Reintegrate TYPO3 7 LTS upgrade wizards
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / BackendLayoutWizardController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller;
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
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\AbstractModule;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Imaging\Icon;
23 use TYPO3\CMS\Core\Page\PageRenderer;
24 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 /**
28 * Script Class for grid wizard
29 */
30 class BackendLayoutWizardController extends AbstractModule
31 {
32 /**
33 * GET vars:
34 * Wizard parameters, coming from TCEforms linking to the wizard.
35 * @var array
36 */
37 public $P;
38
39 /**
40 * Accumulated content.
41 * @var string
42 */
43 public $content;
44
45 /**
46 * @var string
47 */
48 public $formName;
49
50 /**
51 * @var string
52 */
53 public $fieldName;
54
55 /**
56 * @var array
57 */
58 protected $rows;
59
60 /**
61 * @var int
62 */
63 protected $colCount;
64
65 /**
66 * @var int
67 */
68 protected $rowCount;
69
70 /**
71 * Constructor
72 */
73 public function __construct()
74 {
75 parent::__construct();
76 $this->init();
77 }
78
79 /**
80 * Initialises the Class
81 *
82 * @return void
83 * @throws \InvalidArgumentException
84 */
85 public function init()
86 {
87 $lang = $this->getLanguageService();
88 $lang->includeLLFile('EXT:lang/locallang_wizards.xlf');
89
90 // Setting GET vars (used in frameset script):
91 $this->P = GeneralUtility::_GP('P');
92 $this->formName = $this->P['formName'];
93 $this->fieldName = $this->P['itemName'];
94 $hmac_validate = GeneralUtility::hmac($this->formName . $this->fieldName, 'wizard_js');
95 if (!$this->P['hmac'] || ($this->P['hmac'] !== $hmac_validate)) {
96 throw new \InvalidArgumentException('Hmac Validation failed for backend_layout wizard', 1385811397);
97 }
98 $uid = (int)$this->P['uid'];
99
100 /** @var \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer */
101 $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
102 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/GridEditor');
103 $pageRenderer->addInlineSetting(
104 'ContextHelp',
105 'moduleUrl',
106 BackendUtility::getModuleUrl(
107 'help_CshmanualCshmanual',
108 array(
109 'tx_cshmanual_help_cshmanualcshmanual' => array(
110 'controller' => 'Help',
111 'action' => 'detail'
112 )
113 )
114 )
115 );
116 $pageRenderer->addJsInlineCode('storeData', '
117 function storeData(data) {
118 if (parent.opener && parent.opener.document && parent.opener.document.' . $this->formName
119 . ' && parent.opener.document.' . $this->formName . '['
120 . GeneralUtility::quoteJSvalue($this->fieldName) . ']) {
121 parent.opener.document.' . $this->formName . '['
122 . GeneralUtility::quoteJSvalue($this->fieldName) . '].value = data;
123 parent.opener.TBE_EDITOR.fieldChanged("backend_layout","' . $uid . '","config",'
124 . '"data[backend_layout][' . $uid . '][config]");
125 }
126 }
127 ', false);
128 $languageLabels = array(
129 'save' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_labelSave')),
130 'title' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_windowTitle')),
131 'editCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_editCell')),
132 'mergeCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_mergeCell')),
133 'splitCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_splitCell')),
134 'name' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_name')),
135 'column' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_column')),
136 'notSet' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_notSet')),
137 'nameHelp' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_nameHelp')),
138 'columnHelp' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_columnHelp'))
139 );
140 $pageRenderer->addInlineLanguageLabelArray($languageLabels);
141 // Select record
142 $record = $this->getDatabaseConnection()->exec_SELECTgetRows(
143 $this->P['field'],
144 $this->P['table'],
145 'uid=' . (int)$this->P['uid']
146 );
147 if (trim($record[0][$this->P['field']]) == '') {
148 $rows = array(array(array('colspan' => 1, 'rowspan' => 1, 'spanned' => false, 'name' => '')));
149 $colCount = 1;
150 $rowCount = 1;
151 } else {
152 // load TS parser
153 $parser = GeneralUtility::makeInstance(TypoScriptParser::class);
154 $parser->parse($record[0][$this->P['field']]);
155 $data = $parser->setup['backend_layout.'];
156 $rows = array();
157 $colCount = $data['colCount'];
158 $rowCount = $data['rowCount'];
159 $dataRows = $data['rows.'];
160 $spannedMatrix = array();
161 for ($i = 1; $i <= $rowCount; $i++) {
162 $cells = array();
163 $row = array_shift($dataRows);
164 $columns = $row['columns.'];
165 for ($j = 1; $j <= $colCount; $j++) {
166 $cellData = array();
167 if (!$spannedMatrix[$i][$j]) {
168 if (is_array($columns) && !empty($columns)) {
169 $column = array_shift($columns);
170 if (isset($column['colspan'])) {
171 $cellData['colspan'] = (int)$column['colspan'];
172 $columnColSpan = (int)$column['colspan'];
173 if (isset($column['rowspan'])) {
174 $columnRowSpan = (int)$column['rowspan'];
175 for ($spanRow = 0; $spanRow < $columnRowSpan; $spanRow++) {
176 for ($spanColumn = 0; $spanColumn < $columnColSpan; $spanColumn++) {
177 $spannedMatrix[$i + $spanRow][$j + $spanColumn] = 1;
178 }
179 }
180 } else {
181 for ($spanColumn = 0; $spanColumn < $columnColSpan; $spanColumn++) {
182 $spannedMatrix[$i][$j + $spanColumn] = 1;
183 }
184 }
185 } else {
186 $cellData['colspan'] = 1;
187 if (isset($column['rowspan'])) {
188 $columnRowSpan = (int)$column['rowspan'];
189 for ($spanRow = 0; $spanRow < $columnRowSpan; $spanRow++) {
190 $spannedMatrix[$i + $spanRow][$j] = 1;
191 }
192 }
193 }
194 if (isset($column['rowspan'])) {
195 $cellData['rowspan'] = (int)$column['rowspan'];
196 } else {
197 $cellData['rowspan'] = 1;
198 }
199 if (isset($column['name'])) {
200 $cellData['name'] = $column['name'];
201 }
202 if (isset($column['colPos'])) {
203 $cellData['column'] = (int)$column['colPos'];
204 }
205 }
206 } else {
207 $cellData = array('colspan' => 1, 'rowspan' => 1, 'spanned' => 1);
208 }
209 $cells[] = $cellData;
210 }
211 $rows[] = $cells;
212 if (!empty($spannedMatrix[$i]) && is_array($spannedMatrix[$i])) {
213 ksort($spannedMatrix[$i]);
214 }
215 }
216 }
217 $this->rows = $rows;
218 $this->colCount = (int)$colCount;
219 $this->rowCount = (int)$rowCount;
220 }
221
222 /**
223 * Injects the request object for the current request or subrequest
224 * As this controller goes only through the main() method, it is rather simple for now
225 *
226 * @param ServerRequestInterface $request
227 * @param ResponseInterface $response
228 * @return ResponseInterface
229 */
230 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
231 {
232 $this->main();
233
234 $this->setPagePath($this->P['table'], $this->P['uid']);
235
236 $this->moduleTemplate->setContent($this->content);
237 $response->getBody()->write($this->moduleTemplate->renderContent());
238 return $response;
239 }
240
241 /**
242 * Creates the correct path to the current record
243 *
244 * @param string $table
245 * @param int $uid
246 */
247 protected function setPagePath($table, $uid)
248 {
249 $uid = (int)$uid;
250
251 if ($table === 'pages') {
252 $pageId = $uid;
253 } else {
254 $record = BackendUtility::getRecord($table, $uid, '*', '', false);
255 $pageId = $record['pid'];
256 }
257
258 $pageAccess = BackendUtility::readPageAccess($pageId, $this->getBackendUser()->getPagePermsClause(1));
259 if (is_array($pageAccess)) {
260 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageAccess);
261 }
262 }
263
264 /**
265 * Main Method, rendering either colorpicker or frameset depending on ->showPicker
266 *
267 * @return void
268 */
269 public function main()
270 {
271 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
272 $lang = $this->getLanguageService();
273
274 $saveButton = $buttonBar->makeInputButton()
275 ->setName('_savedok')
276 ->setValue('1')
277 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc'))
278 ->setClasses('t3js-grideditor-savedok')
279 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
280
281 $saveAndCloseButton = $buttonBar->makeInputButton()
282 ->setName('_savedokandclose')
283 ->setValue('1')
284 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc'))
285 ->setClasses('t3js-grideditor-savedokclose')
286 ->setIcon(
287 $this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', Icon::SIZE_SMALL)
288 );
289
290 $splitButton = $buttonBar->makeSplitButton()
291 ->addItem($saveButton)
292 ->addItem($saveAndCloseButton);
293 $buttonBar->addButton($splitButton);
294
295 $closeButton = $buttonBar->makeLinkButton()
296 ->setHref('#')
297 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc'))
298 ->setOnClick('window.close();return true;')
299 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
300 $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 30);
301
302 $markup = array();
303 $markup[] = '';
304 $markup[] = '<table class="grideditor table table-bordered"">';
305 $markup[] = ' <tr>';
306 $markup[] = ' <td class="editor_cell">';
307 $markup[] = ' <div id="editor" class="t3js-grideditor" data-data="' . htmlspecialchars(
308 json_encode(
309 $this->rows,
310 JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS
311 )
312 ) . '" '
313 . 'data-rowcount="' . (int)$this->rowCount . '" '
314 . 'data-colcount="' . (int)$this->colCount . '">';
315 $markup[] = ' </div>';
316 $markup[] = ' </td>';
317 $markup[] = ' <td>';
318 $markup[] = ' <div class="btn-group-vertical">';
319 $markup[] = ' <a class="btn btn-default btn-sm t3js-grideditor-addcolumn" href="#" title="'
320 . htmlspecialchars($lang->getLL('grid_addColumn')) . '">';
321 $markup[] = ' <i class="fa fa-fw fa-arrow-right"></i>';
322 $markup[] = ' </a>';
323 $markup[] = ' <a class="btn btn-default btn-sm t3js-grideditor-removecolumn" href="#" title="'
324 . htmlspecialchars($lang->getLL('grid_removeColumn')) . '">';
325 $markup[] = ' <i class="fa fa-fw fa-arrow-left"></i>';
326 $markup[] = ' </a>';
327 $markup[] = ' </div>';
328 $markup[] = ' </td>';
329 $markup[] = ' </tr>';
330 $markup[] = ' <tr>';
331 $markup[] = ' <td colspan="2" align="center">';
332 $markup[] = ' <div class="btn-group">';
333 $markup[] = ' <a class="btn btn-default btn-sm t3js-grideditor-addrow" href="#" title="'
334 . htmlspecialchars($lang->getLL('grid_addRow')) . '">';
335 $markup[] = ' <i class="fa fa-fw fa-arrow-down"></i>';
336 $markup[] = ' </a>';
337 $markup[] = ' <a class="btn btn-default btn-sm t3js-grideditor-removerow" href="#" title="'
338 . htmlspecialchars($lang->getLL('grid_removeRow')) . '">';
339 $markup[] = ' <i class="fa fa-fw fa-arrow-up"></i>';
340 $markup[] = ' </a>';
341 $markup[] = ' </div>';
342 $markup[] = ' </td>';
343 $markup[] = ' </tr>';
344 $markup[] = '</table>';
345
346 $this->content .= implode(LF, $markup);
347 }
348
349 /**
350 * Returns LanguageService
351 *
352 * @return \TYPO3\CMS\Lang\LanguageService
353 */
354 protected function getLanguageService()
355 {
356 return $GLOBALS['LANG'];
357 }
358
359 /**
360 * Returns the database connection
361 *
362 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
363 */
364 protected function getDatabaseConnection()
365 {
366 return $GLOBALS['TYPO3_DB'];
367 }
368
369 /**
370 * Gets the current backend user.
371 *
372 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
373 */
374 protected function getBackendUser()
375 {
376 return $GLOBALS['BE_USER'];
377 }
378 }