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