/** * @param string $string * @param array $expectedInlineStructure * @param array $expectedInlineNames * @dataProvider structureStringIsParsedDataProvider * @test */ public function structureStringIsParsed($string, array $expectedInlineStructure, array $expectedInlineNames) { $this->fixture->parseStructureString($string, FALSE); $this->assertEquals('pageId', $this->fixture->inlineFirstPid); $this->assertEquals($expectedInlineStructure, $this->fixture->inlineStructure); $this->assertEquals($expectedInlineNames, $this->fixture->inlineNames); }
/** * Prints the selector box form-field for the db/file/select elements (multiple) * * @param string $fName Form element name * @param string $mode Mode "db", "file" (internal_type for the "group" type) OR blank (then for the "select" type) * @param string $allowed Commalist of "allowed * @param array $itemArray The array of items. For "select" and "group"/"file" this is just a set of value. For "db" its an array of arrays with table/uid pairs. * @param string $selector Alternative selector box. * @param array $params An array of additional parameters, eg: "size", "info", "headers" (array with "selector" and "items"), "noBrowser", "thumbnails * @param string $onFocus On focus attribute string * @param string $table (optional) Table name processing for * @param string $field (optional) Field of table name processing for * @param string $uid (optional) uid of table record processing for * @param array $config (optional) The TCA field config * @return string The form fields for the selection. * @throws \UnexpectedValueException * @todo Define visibility */ public function dbFileIcons($fName, $mode, $allowed, $itemArray, $selector = '', $params = array(), $onFocus = '', $table = '', $field = '', $uid = '', $config = array()) { $disabled = ''; if ($this->renderReadonly || $params['readOnly']) { $disabled = ' disabled="disabled"'; } // Sets a flag which means some JavaScript is included on the page to support this element. $this->printNeededJS['dbFileIcons'] = 1; // INIT $uidList = array(); $opt = array(); $itemArrayC = 0; // Creating <option> elements: if (is_array($itemArray)) { $itemArrayC = count($itemArray); switch ($mode) { case 'db': foreach ($itemArray as $pp) { $pRec = BackendUtility::getRecordWSOL($pp['table'], $pp['id']); if (is_array($pRec)) { $pTitle = BackendUtility::getRecordTitle($pp['table'], $pRec, FALSE, TRUE); $pUid = $pp['table'] . '_' . $pp['id']; $uidList[] = $pUid; $title = htmlspecialchars($pTitle); $opt[] = '<option value="' . htmlspecialchars($pUid) . '" title="' . $title . '">' . $title . '</option>'; } } break; case 'file_reference': case 'file': foreach ($itemArray as $item) { $itemParts = explode('|', $item); $uidList[] = $pUid = $pTitle = $itemParts[0]; $title = htmlspecialchars(rawurldecode($itemParts[1])); $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0])) . '" title="' . $title . '">' . $title . '</option>'; } break; case 'folder': foreach ($itemArray as $pp) { $pParts = explode('|', $pp); $uidList[] = $pUid = $pTitle = $pParts[0]; $title = htmlspecialchars(rawurldecode($pParts[0])); $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pParts[0])) . '" title="' . $title . '">' . $title . '</option>'; } break; default: foreach ($itemArray as $pp) { $pParts = explode('|', $pp, 2); $uidList[] = $pUid = $pParts[0]; $pTitle = $pParts[1]; $title = htmlspecialchars(rawurldecode($pTitle)); $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pUid)) . '" title="' . $title . '">' . $title . '</option>'; } } } // Create selector box of the options $sSize = $params['autoSizeMax'] ? MathUtility::forceIntegerInRange($itemArrayC + 1, MathUtility::forceIntegerInRange($params['size'], 1), $params['autoSizeMax']) : $params['size']; if (!$selector) { $isMultiple = $params['maxitems'] != 1 && $params['size'] != 1; $selector = '<select id="' . uniqid('tceforms-multiselect-') . '" ' . ($params['noList'] ? 'style="display: none"' : 'size="' . $sSize . '"' . $this->insertDefStyle('group', 'tceforms-multiselect')) . ($isMultiple ? ' multiple="multiple"' : '') . ' name="' . $fName . '_list" ' . $onFocus . $params['style'] . $disabled . '>' . implode('', $opt) . '</select>'; } $icons = array('L' => array(), 'R' => array()); $rOnClickInline = ''; if (!$params['readOnly'] && !$params['noList']) { if (!$params['noBrowser']) { // Check against inline uniqueness $inlineParent = $this->inline->getStructureLevel(-1); $aOnClickInline = ''; if (is_array($inlineParent) && $inlineParent['uid']) { if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) { $objectPrefix = $this->inline->inlineNames['object'] . InlineElement::Structure_Separator . $table; $aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement'; $rOnClickInline = 'inline.revertUnique(\'' . $objectPrefix . '\',null,\'' . $uid . '\');'; } } if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserType'])) { $elementBrowserType = $config['appearance']['elementBrowserType']; } else { $elementBrowserType = $mode; } if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserAllowed'])) { $elementBrowserAllowed = $config['appearance']['elementBrowserAllowed']; } else { $elementBrowserAllowed = $allowed; } $aOnClick = 'setFormValueOpenBrowser(\'' . $elementBrowserType . '\',\'' . ($fName . '|||' . $elementBrowserAllowed . '|' . $aOnClickInline) . '\'); return false;'; $spriteIcon = IconUtility::getSpriteIcon('actions-insert-record', array('title' => htmlspecialchars($this->getLL('l_browse_' . ($mode == 'db' ? 'db' : 'file'))))); $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $spriteIcon . '</a>'; } if (!$params['dontShowMoveIcons']) { if ($sSize >= 5) { $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-top', array('data-fieldname' => $fName, 'class' => 't3-btn t3-btn-moveoption-top', 'title' => htmlspecialchars($this->getLL('l_move_to_top')))); } $icons['L'][] = IconUtility::getSpriteIcon('actions-move-up', array('data-fieldname' => $fName, 'class' => 't3-btn t3-btn-moveoption-up', 'title' => htmlspecialchars($this->getLL('l_move_up')))); $icons['L'][] = IconUtility::getSpriteIcon('actions-move-down', array('data-fieldname' => $fName, 'class' => 't3-btn t3-btn-moveoption-down', 'title' => htmlspecialchars($this->getLL('l_move_down')))); if ($sSize >= 5) { $icons['L'][] = IconUtility::getSpriteIcon('actions-move-to-bottom', array('data-fieldname' => $fName, 'class' => 't3-btn t3-btn-moveoption-bottom', 'title' => htmlspecialchars($this->getLL('l_move_to_bottom')))); } } $clipElements = $this->getClipboardElements($allowed, $mode); if (count($clipElements)) { $aOnClick = ''; foreach ($clipElements as $elValue) { if ($mode == 'db') { list($itemTable, $itemUid) = explode('|', $elValue); $recordTitle = BackendUtility::getRecordTitle($itemTable, BackendUtility::getRecordWSOL($itemTable, $itemUid)); $itemTitle = GeneralUtility::quoteJSvalue($recordTitle); $elValue = $itemTable . '_' . $itemUid; } else { // 'file', 'file_reference' and 'folder' mode $itemTitle = 'unescape(\'' . rawurlencode(basename($elValue)) . '\')'; } $aOnClick .= 'setFormValueFromBrowseWin(\'' . $fName . '\',unescape(\'' . rawurlencode(str_replace('%20', ' ', $elValue)) . '\'),' . $itemTitle . ',' . $itemTitle . ');'; } $aOnClick .= 'return false;'; $spriteIcon1 = IconUtility::getSpriteIcon('actions-document-paste-into', array('title' => htmlspecialchars(sprintf($this->getLL('l_clipInsert_' . ($mode == 'db' ? 'db' : 'file')), count($clipElements))))); $icons['R'][] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $spriteIcon1 . '</a>'; } } if (!$params['readOnly'] && !$params['noDelete']) { $icons['L'][] = IconUtility::getSpriteIcon('actions-selection-delete', array('onclick' => $rOnClickInline, 'data-fieldname' => $fName, 'class' => 't3-btn t3-btn-removeoption', 'title' => htmlspecialchars($this->getLL('l_remove_selected')))); } $imagesOnly = FALSE; if ($params['thumbnails'] && $params['info']) { // In case we have thumbnails, check if only images are allowed. // In this case, render them below the field, instead of to the right $allowedExtensionList = GeneralUtility::trimExplode(' ', strtolower($params['info']), TRUE); $imageExtensionList = GeneralUtility::trimExplode(',', strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), TRUE); $imagesOnly = TRUE; foreach ($allowedExtensionList as $allowedExtension) { if (!GeneralUtility::inArray($imageExtensionList, $allowedExtension)) { $imagesOnly = FALSE; break; } } } if ($imagesOnly) { $rightbox = ''; $thumbnails = '<div class="imagethumbs">' . $this->wrapLabels($params['thumbnails']) . '</div>'; } else { $rightbox = $this->wrapLabels($params['thumbnails']); $thumbnails = ''; } // Hook: dbFileIcons_postProcess (requested by FAL-team for use with the "fal" extension) if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'] as $classRef) { $hookObject = GeneralUtility::getUserObj($classRef); if (!$hookObject instanceof DatabaseFileIconsHookInterface) { throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\Form\\DatabaseFileIconsHookInterface', 1290167704); } $additionalParams = array('mode' => $mode, 'allowed' => $allowed, 'itemArray' => $itemArray, 'onFocus' => $onFocus, 'table' => $table, 'field' => $field, 'uid' => $uid, 'config' => $GLOBALS['TCA'][$table]['columns'][$field]); $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this); } } $str = '<table border="0" cellpadding="0" cellspacing="0" width="1" class="t3-form-field-group-file"> ' . ($params['headers'] ? ' <tr> <td>' . $this->wrapLabels($params['headers']['selector']) . '</td> <td></td> <td></td> <td>' . ($params['thumbnails'] ? $this->wrapLabels($params['headers']['items']) : '') . '</td> </tr>' : '') . ' <tr> <td>' . $selector . $thumbnails; if (!$params['noList'] && $params['info'] !== '') { $str .= '<span class="filetypes">' . $this->wrapLabels($params['info']) . '</span>'; } $str .= '</td> <td class="icons">' . implode('<br />', $icons['L']) . '</td> <td class="icons">' . implode('<br />', $icons['R']) . '</td> <td>' . $rightbox . '</td> </tr> </table>'; // Creating the hidden field which contains the actual value as a comma list. $str .= '<input type="hidden" name="' . $fName . '" value="' . htmlspecialchars(implode(',', $uidList)) . '" />'; return $str; }
/** * Do processing of data, submitting it to TCEmain. * * @return void */ public function processData() { // GPvars specifically for processing: $control = GeneralUtility::_GP('control'); $this->data = GeneralUtility::_GP('data'); $this->cmd = GeneralUtility::_GP('cmd'); $this->mirror = GeneralUtility::_GP('mirror'); $this->cacheCmd = GeneralUtility::_GP('cacheCmd'); $this->redirect = GeneralUtility::_GP('redirect'); $this->returnNewPageId = GeneralUtility::_GP('returnNewPageId'); $this->vC = GeneralUtility::_GP('vC'); // See tce_db.php for relevate options here: // Only options related to $this->data submission are included here. /** @var $tce \TYPO3\CMS\Core\DataHandling\DataHandler */ $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler'); $tce->stripslashes_values = 0; if (!empty($control)) { $tce->setControl($control); } if (isset($_POST['_translation_savedok_x'])) { $tce->updateModeL10NdiffData = 'FORCE_FFUPD'; } if (isset($_POST['_translation_savedokclear_x'])) { $tce->updateModeL10NdiffData = 'FORCE_FFUPD'; $tce->updateModeL10NdiffDataClear = TRUE; } // Setting default values specific for the user: $TCAdefaultOverride = $GLOBALS['BE_USER']->getTSConfigProp('TCAdefaults'); if (is_array($TCAdefaultOverride)) { $tce->setDefaultsFromUserTS($TCAdefaultOverride); } // Setting internal vars: if ($GLOBALS['BE_USER']->uc['neverHideAtCopy']) { $tce->neverHideAtCopy = 1; } $tce->debug = 0; $tce->disableRTE = !$GLOBALS['BE_USER']->isRTE(); // Loading TCEmain with data: $tce->start($this->data, $this->cmd); if (is_array($this->mirror)) { $tce->setMirror($this->mirror); } // If pages are being edited, we set an instruction about updating the page tree after this operation. if (isset($this->data['pages']) || $GLOBALS['BE_USER']->workspace != 0 && count($this->data)) { BackendUtility::setUpdateSignal('updatePageTree'); } // Checking referer / executing $refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER')); $httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'); if ($httpHost != $refInfo['host'] && $this->vC != $GLOBALS['BE_USER']->veriCode() && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']) { $tce->log('', 0, 0, 0, 1, 'Referer host \'%s\' and server host \'%s\' did not match and veriCode was not valid either!', 1, array($refInfo['host'], $httpHost)); debug('Error: Referer host did not match with server host.'); } else { // Perform the saving operation with TCEmain: $tce->process_uploads($_FILES); $tce->process_datamap(); $tce->process_cmdmap(); // If there was saved any new items, load them: if (count($tce->substNEWwithIDs_table)) { // save the expanded/collapsed states for new inline records, if any \TYPO3\CMS\Backend\Form\Element\InlineElement::updateInlineView($this->uc, $tce); $newEditConf = array(); foreach ($this->editconf as $tableName => $tableCmds) { $keys = array_keys($tce->substNEWwithIDs_table, $tableName); if (count($keys) > 0) { foreach ($keys as $key) { $editId = $tce->substNEWwithIDs[$key]; // Check if the $editId isn't a child record of an IRRE action if (!(is_array($tce->newRelatedIDs[$tableName]) && in_array($editId, $tce->newRelatedIDs[$tableName]))) { // Translate new id to the workspace version: if ($versionRec = BackendUtility::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $tableName, $editId, 'uid')) { $editId = $versionRec['uid']; } $newEditConf[$tableName][$editId] = 'edit'; } // Traverse all new records and forge the content of ->editconf so we can continue to EDIT these records! if ($tableName == 'pages' && $this->retUrl != 'dummy.php' && $this->returnNewPageId) { $this->retUrl .= '&id=' . $tce->substNEWwithIDs[$key]; } } } else { $newEditConf[$tableName] = $tableCmds; } } // Resetting editconf if newEditConf has values: if (count($newEditConf)) { $this->editconf = $newEditConf; } // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed. $this->R_URL_getvars['edit'] = $this->editconf; // Unsetting default values since we don't need them anymore. unset($this->R_URL_getvars['defVals']); // Re-compile the store* values since editconf changed... $this->compileStoreDat(); } // See if any records was auto-created as new versions? if (count($tce->autoVersionIdMap)) { $this->fixWSversioningInEditConf($tce->autoVersionIdMap); } // If a document is saved and a new one is created right after. if (isset($_POST['_savedoknew_x']) && is_array($this->editconf)) { // Finding the current table: reset($this->editconf); $nTable = key($this->editconf); // Finding the first id, getting the records pid+uid reset($this->editconf[$nTable]); $nUid = key($this->editconf[$nTable]); $nRec = BackendUtility::getRecord($nTable, $nUid, 'pid,uid'); // Setting a blank editconf array for a new record: $this->editconf = array(); if ($this->getNewIconMode($nTable) == 'top') { $this->editconf[$nTable][$nRec['pid']] = 'new'; } else { $this->editconf[$nTable][-$nRec['uid']] = 'new'; } // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed. $this->R_URL_getvars['edit'] = $this->editconf; // Re-compile the store* values since editconf changed... $this->compileStoreDat(); } $tce->printLogErrorMessages(isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x']) ? $this->retUrl : $this->R_URL_parts['path'] . '?' . GeneralUtility::implodeArrayForUrl('', $this->R_URL_getvars)); } // || count($tce->substNEWwithIDs)... If any new items has been save, the document is CLOSED // because if not, we just get that element re-listed as new. And we don't want that! if (isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x']) || $this->closeDoc < 0) { $this->closeDocument(abs($this->closeDoc)); } }