[TASK] Fix CGL errors
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / Wizard / TableController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller\Wizard;
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\ServerRequestInterface;
18 use Psr\Http\Message\ResponseInterface;
19 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
22 use TYPO3\CMS\Core\DataHandling\DataHandler;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Core\Utility\HttpUtility;
27 use TYPO3\CMS\Core\Utility\MathUtility;
28 use TYPO3\CMS\Core\Utility\StringUtility;
29
30 /**
31 * Script Class for rendering the Table Wizard
32 */
33 class TableController extends AbstractWizardController
34 {
35 /**
36 * Content accumulation for the module.
37 *
38 * @var string
39 */
40 public $content;
41
42 /**
43 * If TRUE, <input> fields are shown instead of textareas.
44 *
45 * @var bool
46 */
47 public $inputStyle = false;
48
49 /**
50 * If set, the string version of the content is interpreted/written as XML
51 * instead of the original line-based kind. This variable still needs binding
52 * to the wizard parameters - but support is ready!
53 *
54 * @var int
55 */
56 public $xmlStorage = 0;
57
58 /**
59 * Number of new rows to add in bottom of wizard
60 *
61 * @var int
62 */
63 public $numNewRows = 1;
64
65 /**
66 * Name of field in parent record which MAY contain the number of columns for the table
67 * here hardcoded to the value of tt_content. Should be set by FormEngine parameters (from P)
68 *
69 * @var string
70 */
71 public $colsFieldName = 'cols';
72
73 /**
74 * Wizard parameters, coming from FormEngine linking to the wizard.
75 *
76 * @var array
77 */
78 public $P;
79
80 /**
81 * The array which is constantly submitted by the multidimensional form of this wizard.
82 *
83 * @var array
84 */
85 public $TABLECFG;
86
87 /**
88 * Table parsing
89 * quoting of table cells
90 *
91 * @var string
92 */
93 public $tableParsing_quote;
94
95 /**
96 * delimiter between table cells
97 *
98 * @var string
99 */
100 public $tableParsing_delimiter;
101
102 /**
103 * @var IconFactory
104 */
105 protected $iconFactory;
106
107 /**
108 * Constructor
109 */
110 public function __construct()
111 {
112 parent::__construct();
113 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_wizards.xlf');
114 $GLOBALS['SOBE'] = $this;
115
116 $this->init();
117 }
118
119 /**
120 * Initialization of the class
121 *
122 * @return void
123 */
124 protected function init()
125 {
126 // GPvars:
127 $this->P = GeneralUtility::_GP('P');
128 $this->TABLECFG = GeneralUtility::_GP('TABLE');
129 // Setting options:
130 $this->xmlStorage = $this->P['params']['xmlOutput'];
131 $this->numNewRows = MathUtility::forceIntegerInRange($this->P['params']['numNewRows'], 1, 50, 5);
132 // Textareas or input fields:
133 $this->inputStyle = isset($this->TABLECFG['textFields']) ? (bool)$this->TABLECFG['textFields'] : true;
134 // Setting form tag:
135 list($rUri) = explode('#', GeneralUtility::getIndpEnv('REQUEST_URI'));
136 $this->tableParsing_delimiter = '|';
137 $this->tableParsing_quote = '';
138 }
139
140 /**
141 * Injects the request object for the current request or subrequest
142 * As this controller goes only through the main() method, it is rather simple for now
143 *
144 * @param ServerRequestInterface $request
145 * @param ResponseInterface $response
146 * @return ResponseInterface
147 */
148 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
149 {
150 $this->main();
151 $response->getBody()->write($this->moduleTemplate->renderContent());
152 return $response;
153 }
154
155 /**
156 * Main function, rendering the table wizard
157 *
158 * @return void
159 */
160 public function main()
161 {
162 $this->content .= '<form action="' . htmlspecialchars($rUri) . '" method="post" id="TableController" name="wizardForm">';
163 if ($this->P['table'] && $this->P['field'] && $this->P['uid']) {
164 $this->content .= '<h2>' . $this->getLanguageService()->getLL('table_title', true) . '</h2>'
165 . '<div>' . $this->tableWizard() . '</div>';
166 } else {
167 $this->content .= '<h2>' . $this->getLanguageService()->getLL('table_title', true) . '</h2>'
168 . '<div><span class="text-danger">' . $this->getLanguageService()->getLL('table_noData', true) . '</span></div>';
169 ;
170 }
171 $this->content .= '</form>';
172 // Setting up the buttons and markers for docHeader
173 $this->getButtons();
174 // Build the <body> for the module
175 $this->moduleTemplate->setContent($this->content);
176 }
177
178 /**
179 * Outputting the accumulated content to screen
180 *
181 * @return void
182 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
183 */
184 public function printContent()
185 {
186 GeneralUtility::logDeprecatedFunction();
187 echo $this->content;
188 }
189
190 /**
191 * Create the panel of buttons for submitting the form or otherwise perform operations.
192 */
193 protected function getButtons()
194 {
195 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
196 if ($this->P['table'] && $this->P['field'] && $this->P['uid']) {
197 // CSH
198 $cshButton = $buttonBar->makeHelpButton()
199 ->setModuleName('xMOD_csh_corebe')
200 ->setFieldName('wizard_table_wiz');
201 $buttonBar->addButton($cshButton);
202 // Close
203 $closeButton = $buttonBar->makeLinkButton()
204 ->setHref($this->P['returnUrl'])
205 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', true))
206 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
207 $buttonBar->addButton($closeButton);
208 // Save
209 $saveButton = $buttonBar->makeInputButton()
210 ->setName('_savedok')
211 ->setValue('1')
212 ->setForm('TableController')
213 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL))
214 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true));
215 // Save & Close
216 $saveAndCloseButton = $buttonBar->makeInputButton()
217 ->setName('_saveandclosedok')
218 ->setValue('1')
219 ->setForm('TableController')
220 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', true))
221 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
222 'actions-document-save-close',
223 Icon::SIZE_SMALL
224 ));
225 $splitButtonElement = $buttonBar->makeSplitButton()
226 ->addItem($saveButton)
227 ->addItem($saveAndCloseButton);
228
229 $buttonBar->addButton($splitButtonElement, ButtonBar::BUTTON_POSITION_LEFT, 3);
230 // Reload
231 $reloadButton = $buttonBar->makeInputButton()
232 ->setName('_refresh')
233 ->setValue('1')
234 ->setForm('TableController')
235 ->setTitle($this->getLanguageService()->getLL('forms_refresh', true))
236 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-refresh', Icon::SIZE_SMALL));
237 $buttonBar->addButton($reloadButton);
238 }
239 }
240
241 /**
242 * Draws the table wizard content
243 *
244 * @return string HTML content for the form.
245 * @throws \RuntimeException
246 */
247 public function tableWizard()
248 {
249 if (!$this->checkEditAccess($this->P['table'], $this->P['uid'])) {
250 throw new \RuntimeException('Wizard Error: No access', 1349692692);
251 }
252 // First, check the references by selecting the record:
253 $row = BackendUtility::getRecord($this->P['table'], $this->P['uid']);
254 if (!is_array($row)) {
255 throw new \RuntimeException('Wizard Error: No reference to record', 1294587125);
256 }
257 // This will get the content of the form configuration code field to us - possibly cleaned up,
258 // saved to database etc. if the form has been submitted in the meantime.
259 $tableCfgArray = $this->getConfigCode($row);
260 // Generation of the Table Wizards HTML code:
261 $content = $this->getTableHTML($tableCfgArray);
262 // Return content:
263 return $content;
264 }
265
266 /*
267 *
268 * Helper functions
269 *
270 */
271
272 /**
273 * Will get and return the configuration code string
274 * Will also save (and possibly redirect/exit) the content if a save button has been pressed
275 *
276 * @param array $row Current parent record row
277 * @return array Table config code in an array
278 * @internal
279 */
280 public function getConfigCode($row)
281 {
282 // Get delimiter settings
283 $flexForm = GeneralUtility::xml2array($row['pi_flexform']);
284 if (is_array($flexForm)) {
285 $this->tableParsing_quote = $flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF']) : '';
286 $this->tableParsing_delimiter = $flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF']) : '|';
287 }
288 // If some data has been submitted, then construct
289 if (isset($this->TABLECFG['c'])) {
290 // Process incoming:
291 $this->changeFunc();
292 // Convert to string (either line based or XML):
293 if ($this->xmlStorage) {
294 // Convert the input array to XML:
295 $bodyText = GeneralUtility::array2xml_cs($this->TABLECFG['c'], 'T3TableWizard');
296 // Setting cfgArr directly from the input:
297 $configuration = $this->TABLECFG['c'];
298 } else {
299 // Convert the input array to a string of configuration code:
300 $bodyText = $this->cfgArray2CfgString($this->TABLECFG['c']);
301 // Create cfgArr from the string based configuration - that way it is cleaned up
302 // and any incompatibilities will be removed!
303 $configuration = $this->cfgString2CfgArray($bodyText, $row[$this->colsFieldName]);
304 }
305 // If a save button has been pressed, then save the new field content:
306 if ($_POST['_savedok'] || $_POST['_saveandclosedok']) {
307 // Get DataHandler object:
308 /** @var DataHandler $dataHandler */
309 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
310 $dataHandler->stripslashes_values = false;
311 // Put content into the data array:
312 $data = array();
313 if ($this->P['flexFormPath']) {
314 // Current value of flexForm path:
315 $currentFlexFormData = GeneralUtility::xml2array($row[$this->P['field']]);
316 /** @var FlexFormTools $flexFormTools */
317 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
318 $flexFormTools->setArrayValueByPath($this->P['flexFormPath'], $currentFlexFormData, $bodyText);
319 $data[$this->P['table']][$this->P['uid']][$this->P['field']] = $currentFlexFormData;
320 } else {
321 $data[$this->P['table']][$this->P['uid']][$this->P['field']] = $bodyText;
322 }
323 // Perform the update:
324 $dataHandler->start($data, array());
325 $dataHandler->process_datamap();
326 // If the save/close button was pressed, then redirect the screen:
327 if ($_POST['_saveandclosedok']) {
328 HttpUtility::redirect(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl']));
329 }
330 }
331 } else {
332 // If nothing has been submitted, load the $bodyText variable from the selected database row:
333 if ($this->xmlStorage) {
334 $configuration = GeneralUtility::xml2array($row[$this->P['field']]);
335 } else {
336 if ($this->P['flexFormPath']) {
337 // Current value of flexForm path:
338 $currentFlexFormData = GeneralUtility::xml2array($row[$this->P['field']]);
339 /** @var FlexFormTools $flexFormTools */
340 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
341 $configuration = $flexFormTools->getArrayValueByPath(
342 $this->P['flexFormPath'],
343 $currentFlexFormData
344 );
345 $configuration = $this->cfgString2CfgArray($configuration, 0);
346 } else {
347 // Regular line based table configuration:
348 $configuration = $this->cfgString2CfgArray($row[$this->P['field']], $row[$this->colsFieldName]);
349 }
350 }
351 $configuration = is_array($configuration) ? $configuration : array();
352 }
353 return $configuration;
354 }
355
356 /**
357 * Creates the HTML for the Table Wizard:
358 *
359 * @param array $configuration Table config array
360 * @return string HTML for the table wizard
361 * @internal
362 */
363 public function getTableHTML($configuration)
364 {
365 // Traverse the rows:
366 $tRows = array();
367 $k = 0;
368 $countLines = count($configuration);
369 foreach ($configuration as $cellArr) {
370 if (is_array($cellArr)) {
371 // Initialize:
372 $cells = array();
373 $a = 0;
374 // Traverse the columns:
375 foreach ($cellArr as $cellContent) {
376 if ($this->inputStyle) {
377 $cells[] = '<input class="form-control" type="text" name="TABLE[c][' . ($k + 1) * 2 . '][' . ($a + 1) * 2 . ']" value="' . htmlspecialchars($cellContent) . '" />';
378 } else {
379 $cellContent = preg_replace('/<br[ ]?[\\/]?>/i', LF, $cellContent);
380 $cells[] = '<textarea class="form-control" rows="6" name="TABLE[c][' . ($k + 1) * 2 . '][' . ($a + 1) * 2 . ']">' . htmlspecialchars($cellContent) . '</textarea>';
381 }
382 // Increment counter:
383 $a++;
384 }
385 // CTRL panel for a table row (move up/down/around):
386 $onClick = 'document.wizardForm.action+=' . GeneralUtility::quoteJSvalue('#ANC_' . (($k + 1) * 2 - 2)) . ';';
387 $onClick = ' onclick="' . htmlspecialchars($onClick) . '"';
388 $ctrl = '';
389 if ($k !== 0) {
390 $ctrl .= '<button class="btn btn-default" name="TABLE[row_up][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_up', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-angle-up"></span></button>';
391 } else {
392 $ctrl .= '<button class="btn btn-default" name="TABLE[row_bottom][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_bottom', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-angle-double-down"></span></button>';
393 }
394 if ($k + 1 !== $countLines) {
395 $ctrl .= '<button class="btn btn-default" name="TABLE[row_down][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_down', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-angle-down"></span></button>';
396 } else {
397 $ctrl .= '<button class="btn btn-default" name="TABLE[row_top][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_top', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-angle-double-up"></span></button>';
398 }
399 $ctrl .= '<button class="btn btn-default" name="TABLE[row_remove][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_removeRow', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-trash"></span></button>';
400 $ctrl .= '<button class="btn btn-default" name="TABLE[row_add][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_addRow', true) . '"' . $onClick . '><span class="t3-icon fa fa-fw fa-plus"></span></button>';
401 $tRows[] = '
402 <tr>
403 <td>
404 <a name="ANC_' . ($k + 1) * 2 . '"></a>
405 <span class="btn-group' . ($this->inputStyle ? '' : '-vertical') . '">' . $ctrl . '</span>
406 </td>
407 <td>' . implode('</td>
408 <td>', $cells) . '</td>
409 </tr>';
410 // Increment counter:
411 $k++;
412 }
413 }
414 // CTRL panel for a table column (move left/right/around/delete)
415 $cells = array();
416 $cells[] = '';
417 // Finding first row:
418 $firstRow = reset($configuration);
419 if (is_array($firstRow)) {
420 $cols = count($firstRow);
421 for ($a = 1; $a <= $cols; $a++) {
422 $b = $a * 2;
423 $ctrl = '';
424 if ($a !== 1) {
425 $ctrl .= '<button class="btn btn-default" name="TABLE[col_left][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_left', true) . '"><span class="t3-icon fa fa-fw fa-angle-left"></span></button>';
426 } else {
427 $ctrl .= '<button class="btn btn-default" name="TABLE[col_end][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_end', true) . '"><span class="t3-icon fa fa-fw fa-angle-double-right"></span></button>';
428 }
429 if ($a != $cols) {
430 $ctrl .= '<button class="btn btn-default" name="TABLE[col_right][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_right', true) . '"><span class="t3-icon fa fa-fw fa-angle-right"></span></button>';
431 } else {
432 $ctrl .= '<button class="btn btn-default" name="TABLE[col_start][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_start', true) . '"><span class="t3-icon fa fa-fw fa-angle-double-left"></span></button>';
433 }
434 $ctrl .= '<button class="btn btn-default" name="TABLE[col_remove][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_removeColumn', true) . '"><span class="t3-icon fa fa-fw fa-trash"></span></button>';
435 $ctrl .= '<button class="btn btn-default" name="TABLE[col_add][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_addColumn', true) . '"><span class="t3-icon fa fa-fw fa-plus"></span></button>';
436 $cells[] = '<span class="btn-group">' . $ctrl . '</span>';
437 }
438 $tRows[] = '
439 <tfoot>
440 <tr>
441 <td>' . implode('</td>
442 <td>', $cells) . '</td>
443 </tr>
444 </tfoot>';
445 }
446 $content = '';
447 $addSubmitOnClick = 'onclick="document.getElementById(\'TableController\').submit();"';
448 // Implode all table rows into a string, wrapped in table tags.
449 $content .= '
450
451 <!-- Table wizard -->
452 <div class="table-fit table-fit-inline-block">
453 <table id="typo3-tablewizard" class="table table-center">
454 ' . implode('', $tRows) . '
455 </table>
456 </div>';
457 // Input type checkbox:
458 $content .= '
459
460 <!-- Input mode check box: -->
461 <div class="checkbox">
462 <input type="hidden" name="TABLE[textFields]" value="0" />
463 <label for="textFields">
464 <input type="checkbox" ' . $addSubmitOnClick . ' name="TABLE[textFields]" id="textFields" value="1"' . ($this->inputStyle ? ' checked="checked"' : '') . ' />
465 ' . $this->getLanguageService()->getLL('table_smallFields') . '
466 </label>
467 </div>';
468 return $content;
469 }
470
471 /**
472 * Detects if a control button (up/down/around/delete) has been pressed for an item and accordingly it will
473 * manipulate the internal TABLECFG array
474 *
475 * @return void
476 * @internal
477 */
478 public function changeFunc()
479 {
480 if ($this->TABLECFG['col_remove']) {
481 $kk = key($this->TABLECFG['col_remove']);
482 $cmd = 'col_remove';
483 } elseif ($this->TABLECFG['col_add']) {
484 $kk = key($this->TABLECFG['col_add']);
485 $cmd = 'col_add';
486 } elseif ($this->TABLECFG['col_start']) {
487 $kk = key($this->TABLECFG['col_start']);
488 $cmd = 'col_start';
489 } elseif ($this->TABLECFG['col_end']) {
490 $kk = key($this->TABLECFG['col_end']);
491 $cmd = 'col_end';
492 } elseif ($this->TABLECFG['col_left']) {
493 $kk = key($this->TABLECFG['col_left']);
494 $cmd = 'col_left';
495 } elseif ($this->TABLECFG['col_right']) {
496 $kk = key($this->TABLECFG['col_right']);
497 $cmd = 'col_right';
498 } elseif ($this->TABLECFG['row_remove']) {
499 $kk = key($this->TABLECFG['row_remove']);
500 $cmd = 'row_remove';
501 } elseif ($this->TABLECFG['row_add']) {
502 $kk = key($this->TABLECFG['row_add']);
503 $cmd = 'row_add';
504 } elseif ($this->TABLECFG['row_top']) {
505 $kk = key($this->TABLECFG['row_top']);
506 $cmd = 'row_top';
507 } elseif ($this->TABLECFG['row_bottom']) {
508 $kk = key($this->TABLECFG['row_bottom']);
509 $cmd = 'row_bottom';
510 } elseif ($this->TABLECFG['row_up']) {
511 $kk = key($this->TABLECFG['row_up']);
512 $cmd = 'row_up';
513 } elseif ($this->TABLECFG['row_down']) {
514 $kk = key($this->TABLECFG['row_down']);
515 $cmd = 'row_down';
516 } else {
517 $kk = '';
518 $cmd = '';
519 }
520 if ($cmd && MathUtility::canBeInterpretedAsInteger($kk)) {
521 if (StringUtility::beginsWith($cmd, 'row_')) {
522 switch ($cmd) {
523 case 'row_remove':
524 unset($this->TABLECFG['c'][$kk]);
525 break;
526 case 'row_add':
527 for ($a = 1; $a <= $this->numNewRows; $a++) {
528 // Checking if set: The point is that any new row between existing rows
529 // will be TRUE after one row is added while if rows are added in the bottom
530 // of the table there will be no existing rows to stop the addition of new rows
531 // which means it will add up to $this->numNewRows rows then.
532 if (!isset($this->TABLECFG['c'][($kk + $a)])) {
533 $this->TABLECFG['c'][$kk + $a] = array();
534 } else {
535 break;
536 }
537 }
538 break;
539 case 'row_top':
540 $this->TABLECFG['c'][1] = $this->TABLECFG['c'][$kk];
541 unset($this->TABLECFG['c'][$kk]);
542 break;
543 case 'row_bottom':
544 $this->TABLECFG['c'][10000000] = $this->TABLECFG['c'][$kk];
545 unset($this->TABLECFG['c'][$kk]);
546 break;
547 case 'row_up':
548 $this->TABLECFG['c'][$kk - 3] = $this->TABLECFG['c'][$kk];
549 unset($this->TABLECFG['c'][$kk]);
550 break;
551 case 'row_down':
552 $this->TABLECFG['c'][$kk + 3] = $this->TABLECFG['c'][$kk];
553 unset($this->TABLECFG['c'][$kk]);
554 break;
555 }
556 ksort($this->TABLECFG['c']);
557 }
558 if (StringUtility::beginsWith($cmd, 'col_')) {
559 foreach ($this->TABLECFG['c'] as $cAK => $value) {
560 switch ($cmd) {
561 case 'col_remove':
562 unset($this->TABLECFG['c'][$cAK][$kk]);
563 break;
564 case 'col_add':
565 $this->TABLECFG['c'][$cAK][$kk + 1] = '';
566 break;
567 case 'col_start':
568 $this->TABLECFG['c'][$cAK][1] = $this->TABLECFG['c'][$cAK][$kk];
569 unset($this->TABLECFG['c'][$cAK][$kk]);
570 break;
571 case 'col_end':
572 $this->TABLECFG['c'][$cAK][1000000] = $this->TABLECFG['c'][$cAK][$kk];
573 unset($this->TABLECFG['c'][$cAK][$kk]);
574 break;
575 case 'col_left':
576 $this->TABLECFG['c'][$cAK][$kk - 3] = $this->TABLECFG['c'][$cAK][$kk];
577 unset($this->TABLECFG['c'][$cAK][$kk]);
578 break;
579 case 'col_right':
580 $this->TABLECFG['c'][$cAK][$kk + 3] = $this->TABLECFG['c'][$cAK][$kk];
581 unset($this->TABLECFG['c'][$cAK][$kk]);
582 break;
583 }
584 ksort($this->TABLECFG['c'][$cAK]);
585 }
586 }
587 }
588 // Convert line breaks to <br /> tags:
589 foreach ($this->TABLECFG['c'] as $a => $value) {
590 foreach ($this->TABLECFG['c'][$a] as $b => $value2) {
591 $this->TABLECFG['c'][$a][$b] = str_replace(
592 LF,
593 '<br />',
594 str_replace(CR, '', $this->TABLECFG['c'][$a][$b])
595 );
596 }
597 }
598 }
599
600 /**
601 * Converts the input array to a configuration code string
602 *
603 * @param array $cfgArr Array of table configuration (follows the input structure from the table wizard POST form)
604 * @return string The array converted into a string with line-based configuration.
605 * @see cfgString2CfgArray()
606 */
607 public function cfgArray2CfgString($cfgArr)
608 {
609 $inLines = array();
610 // Traverse the elements of the table wizard and transform the settings into configuration code.
611 foreach ($cfgArr as $valueA) {
612 $thisLine = array();
613 foreach ($valueA as $valueB) {
614 $thisLine[] = $this->tableParsing_quote
615 . str_replace($this->tableParsing_delimiter, '', $valueB) . $this->tableParsing_quote;
616 }
617 $inLines[] = implode($this->tableParsing_delimiter, $thisLine);
618 }
619 // Finally, implode the lines into a string:
620 return implode(LF, $inLines);
621 }
622
623 /**
624 * Converts the input configuration code string into an array
625 *
626 * @param string $configurationCode Configuration code
627 * @param int $columns Default number of columns
628 * @return array Configuration array
629 * @see cfgArray2CfgString()
630 */
631 public function cfgString2CfgArray($configurationCode, $columns)
632 {
633 // Explode lines in the configuration code - each line is a table row.
634 $tableLines = explode(LF, $configurationCode);
635 // Setting number of columns
636 // auto...
637 if (!$columns && trim($tableLines[0])) {
638 $columns = count(explode($this->tableParsing_delimiter, $tableLines[0]));
639 }
640 $columns = $columns ?: 4;
641 // Traverse the number of table elements:
642 $configurationArray = array();
643 foreach ($tableLines as $key => $value) {
644 // Initialize:
645 $valueParts = explode($this->tableParsing_delimiter, $value);
646 // Traverse columns:
647 for ($a = 0; $a < $columns; $a++) {
648 if ($this->tableParsing_quote
649 && $valueParts[$a][0] === $this->tableParsing_quote
650 && substr($valueParts[$a], -1, 1) === $this->tableParsing_quote
651 ) {
652 $valueParts[$a] = substr(trim($valueParts[$a]), 1, -1);
653 }
654 $configurationArray[$key][$a] = $valueParts[$a];
655 }
656 }
657 return $configurationArray;
658 }
659 }