/** * Compile buttons from the table configuration array and return them as HTML * * @param InterfaceGeneralModel $objModelRow * @param string $strTable * @param array $arrRootIds * @param boolean $blnCircularReference * @param array $arrChildRecordIds * @param int $strPrevious * @param int $strNext * @return string */ protected function generateButtons(InterfaceGeneralModel $objModelRow, $strTable, $arrRootIds = array(), $blnCircularReference = false, $arrChildRecordIds = null, $strPrevious = null, $strNext = null) { $arrDCA = $this->getDC()->getDCA(); if (!count($arrDCA['list']['operations'])) { return ''; } $return = ''; foreach ($arrDCA['list']['operations'] as $k => $v) { // Check if we have a array if (!is_array($v)) { $v = array($v); } // Set basic informations $label = strlen($v['label'][0]) ? $v['label'][0] : $k; $title = sprintf(strlen($v['label'][1]) ? $v['label'][1] : $k, $objModelRow->getID()); $attributes = strlen($v['attributes']) ? ' ' . ltrim(sprintf($v['attributes'], $objModelRow->getID(), $objModelRow->getID())) : ''; // Call a custom function instead of using the default button $strButtonCallback = $this->getDC()->getCallbackClass()->buttonCallback($objModelRow, $v, $label, $title, $attributes, $strTable, $arrRootIds, $arrChildRecordIds, $blnCircularReference, $strPrevious, $strNext); if (!is_null($strButtonCallback)) { $return .= ' ' . trim($strButtonCallback); continue; } // Generate all buttons except "move up" and "move down" buttons if ($k != 'move' && $v != 'move') { switch ($k) { // Cute needs some special informations case 'cut': // Get dataprovider from current and parent $strCDP = $objModelRow->getProviderName(); $strPDP = $objModelRow->getMeta(DCGE::MODEL_PTABLE); $strAdd2Url = ""; // Add url + id + currentDataProvider $strAdd2Url .= $v['href'] . '&cdp=' . $strCDP; // Add parent provider if exsists if ($strPDP != null) { $strPDP = $strPDP; $strAdd2Url .= '&pdp=' . $strPDP; } // If we have a id add it, used for mode 4 and all parent -> current views if (strlen($this->Input->get('id')) != 0) { $strAdd2Url .= '&id=' . $this->Input->get('id'); } // Source is the id of the element which should move $strAdd2Url .= '&source=' . $objModelRow->getID(); // Build whole button mark up $return .= ' <a href="' . $this->addToUrl($strAdd2Url) . '" title="' . specialchars($title) . '"' . $attributes . '>' . $this->generateImage($v['icon'], $label) . '</a>'; break; default: $idParam = $v['idparam'] ? 'id=&' . $v['idparam'] : 'id'; $strUrl = $this->addToUrl($v['href'] . '&' . $idParam . '=' . $objModelRow->getID()); $return .= ' <a href="' . $strUrl . '" title="' . specialchars($title) . '"' . $attributes . '>' . $this->generateImage($v['icon'], $label) . '</a>'; break; } continue; } $arrRootIds = is_array($arrRootIds) ? $arrRootIds : array($arrRootIds); foreach (array('up', 'down') as $dir) { $label = strlen($GLOBALS['TL_LANG'][$strTable][$dir][0]) ? $GLOBALS['TL_LANG'][$strTable][$dir][0] : $dir; $title = strlen($GLOBALS['TL_LANG'][$strTable][$dir][1]) ? $GLOBALS['TL_LANG'][$strTable][$dir][1] : $dir; $label = $this->generateImage($dir . '.gif', $label); $href = strlen($v['href']) ? $v['href'] : '&act=move'; if ($dir == 'up') { $return .= (is_numeric($strPrevious) && (!in_array($objModelRow->getID(), $arrRootIds) || !count($GLOBALS['TL_DCA'][$strTable]['list']['sorting']['root'])) ? ' <a href="' . $this->addToUrl($href . '&id=' . $objModelRow->getID()) . '&sid=' . intval($strPrevious) . '" title="' . specialchars($title) . '"' . $attributes . '>' . $label . '</a> ' : $this->generateImage('up_.gif')) . ' '; continue; } $return .= (is_numeric($strNext) && (!in_array($objModelRow->getID(), $arrRootIds) || !count($GLOBALS['TL_DCA'][$strTable]['list']['sorting']['root'])) ? ' <a href="' . $this->addToUrl($href . '&id=' . $objModelRow->getID()) . '&sid=' . intval($strNext) . '" title="' . specialchars($title) . '"' . $attributes . '>' . $label . '</a> ' : $this->generateImage('down_.gif')) . ' '; } } // Add paste into/after icons if ($this->getDC()->isClipboard()) { $arrClipboard = $this->getDC()->getClipboard(); // Check if the id is in the ignore list if ($arrClipboard['mode'] == 'cut' && in_array($objModelRow->getID(), $arrClipboard['ignoredIDs'])) { switch ($this->getDC()->arrDCA['list']['sorting']['mode']) { default: case 4: $return .= ' '; $return .= $imagePasteAfter = $this->generateImage('pasteafter_.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0], 'class="blink"'); break; case 5: $return .= ' '; $return .= $imagePasteAfter = $this->generateImage('pasteafter_.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0], 'class="blink"'); $return .= ' '; $return .= $imagePasteInto = $this->generateImage('pasteinto_.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteinto'][0], 'class="blink"'); break; } } else { // $strAdd2Url = ""; // $strAdd2Url .= 'act=' . $arrClipboard['mode']; // $strAdd2Url .= 'act=' . $arrClipboard['mode']; // // Switch mode // Add ext. information $strAdd2UrlAfter = 'act=' . $arrClipboard['mode'] . '&mode=1&pid=' . $arrClipboard['id'] . '&after=' . $objModelRow->getID() . '&source=' . $arrClipboard['source'] . '&childs=' . $arrClipboard['childs']; $strAdd2UrlInto = 'act=' . $arrClipboard['mode'] . '&mode=2&pid=' . $arrClipboard['id'] . '&after=' . $objModelRow->getID() . '&source=' . $arrClipboard['source'] . '&childs=' . $arrClipboard['childs']; if ($arrClipboard['pdp'] != '') { $strAdd2UrlAfter .= '&pdp=' . $arrClipboard['pdp']; $strAdd2UrlInto .= '&pdp=' . $arrClipboard['pdp']; } if ($arrClipboard['cdp'] != '') { $strAdd2UrlAfter .= '&cdp=' . $arrClipboard['cdp']; $strAdd2UrlInto .= '&cdp=' . $arrClipboard['cdp']; } switch ($this->getDC()->arrDCA['list']['sorting']['mode']) { default: case 4: $imagePasteAfter = $this->generateImage('pasteafter.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0], 'class="blink"'); $strPasteBtt = ' <a href="' . $this->addToUrl($strAdd2UrlAfter) . '" title="' . specialchars($GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0]) . '" onclick="Backend.getScrollOffset()">' . $imagePasteAfter . '</a> '; // Callback for paste btt $strButtonCallback = $this->getDC()->getCallbackClass()->pasteButtonCallback($this->objDC, $objModelRow->getPropertiesAsArray(), $strTable, false, $arrClipboard, null, null); if ($strButtonCallback === false) { $return .= $strPasteBtt; } else { $return .= $strButtonCallback; } break; case 5: // Btn paste after. $imagePasteAfter = $this->generateImage('pasteafter.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0], 'class="blink"'); $strPasteBtt = ' <a href="' . $this->addToUrl($strAdd2UrlAfter) . '" title="' . specialchars($GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteafter'][0]) . '" onclick="Backend.getScrollOffset()">' . $imagePasteAfter . '</a> '; // Btn paste into. $imagePasteInto = $this->generateImage('pasteinto.gif', $GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteinto'][0], 'class="blink"'); $strPasteBtt .= ' <a href="' . $this->addToUrl($strAdd2UrlInto) . '" title="' . specialchars($GLOBALS['TL_LANG'][$this->getDC()->getTable()]['pasteinto'][0]) . '" onclick="Backend.getScrollOffset()">' . $imagePasteInto . '</a> '; // Callback for paste btn. $strButtonCallback = $this->getDC()->getCallbackClass()->pasteButtonCallback($this->objDC, $objModelRow->getPropertiesAsArray(), $strTable, false, $arrClipboard, null, null); if ($strButtonCallback === false) { $return .= $strPasteBtt; } else { $return .= $strButtonCallback; } break; } } } return trim($return); }
/** * Parse|Check|Validate each field and save it. * * @param string $strField Name of current field * @return void */ public function processInput($strField) { if (in_array($strField, $this->arrProcessedNames)) { return $this->arrProcessed[$strField]; } $this->arrProcessedNames[] = $strField; $strInputName = $strField . '_' . $this->mixWidgetID; // Return if no submit, field is not editable or not in input if (!($this->blnSubmitted && isset($this->arrInputs[$strInputName]) && $this->isEditableField($strField) && !(isset($this->arrDCA['fields'][$strField]['eval']['readonly']) && $this->arrDCA['fields'][$strField]['eval']['readonly']))) { return $this->arrProcessed[$strField] = null; } // Build widget $objWidget = $this->getWidget($strField); if (!$objWidget instanceof Widget) { return $this->arrProcessed[$strField] = null; } // Validate $objWidget->validate(); if (Input::getInstance()->post('SUBMIT_TYPE') == 'auto') { // HACK: we would need a Widget::clearErrors() here but something like this does not exist, hence we have a class that does this for us. WidgetAccessor::resetErrors($objWidget); } // Check if ($objWidget->hasErrors()) { $this->blnNoReload = true; return $this->arrProcessed[$strField] = null; } if (!$objWidget->submitInput()) { return $this->arrProcessed[$strField] = $this->objCurrentModel->getProperty($strField); } // Get value and config $varNew = $objWidget->value; $arrConfig = $this->getFieldDefinition($strField); // If array sort if (is_array($varNew)) { ksort($varNew); } else { if ($varNew != '' && isset(self::$arrDates[$arrConfig['eval']['rgxp']])) { // OH: this should be a widget feature $objDate = new Date($varNew, $GLOBALS['TL_CONFIG'][$arrConfig['eval']['rgxp'] . 'Format']); $varNew = $objDate->tstamp; } } $this->import('Input'); //Handle multi-select fields in "override all" mode // OH: this should be a widget feature if (($arrConfig['inputType'] == 'checkbox' || $arrConfig['inputType'] == 'checkboxWizard') && $arrConfig['eval']['multiple'] && $this->Input->get('act') == 'overrideAll') { if ($arrNew == null || !is_array($arrNew)) { $arrNew = array(); } // FIXME: this will NOT work, as it still uses activeRecord - otoh, what is this intended for? wizards? switch ($this->Input->post($objWidget->name . '_update')) { case 'add': $varNew = array_values(array_unique(array_merge(deserialize($this->objActiveRecord->{$strField}, true), $arrNew))); break; case 'remove': $varNew = array_values(array_diff(deserialize($this->objActiveRecord->{$strField}, true), $arrNew)); break; case 'replace': $varNew = $arrNew; break; } if (!$varNew) { $varNew = ''; } } // Call the save callbacks try { $varNew = $this->objCallbackClass->saveCallback($arrConfig, $varNew); } catch (Exception $e) { $this->blnNoReload = true; $objWidget->addError($e->getMessage()); return $this->arrProcessed[$strField] = null; } // Check on value empty if ($varNew == '' && $arrConfig['eval']['doNotSaveEmpty']) { $this->blnNoReload = true; $objWidget->addError($GLOBALS['TL_LANG']['ERR']['mdtryNoLabel']); return $this->arrProcessed[$strField] = null; } if ($varNew != '') { if ($arrConfig['eval']['encrypt']) { $varNew = $this->Encryption->encrypt(is_array($varNew) ? serialize($varNew) : $varNew); } else { if ($arrConfig['eval']['unique'] && !$this->getDataProvider($this->objCurrentModel->getProviderName())->isUniqueValue($strField, $varNew, $this->objCurrentModel->getID())) { $this->blnNoReload = true; $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $objWidget->label)); return $this->arrProcessed[$strField] = null; } else { if ($arrConfig['eval']['fallback']) { $this->getDataProvider($this->objCurrentModel->getProviderName())->resetFallback($strField); } } } } $this->arrProcessed[$strField] = $varNew; return $varNew; }
/** * Save a new version of a row. * * @param InterfaceGeneralModel $objModel The model for which a new version shall be created. * * @param string $strUsername The username to attach to the version as creator. * * @return void */ public function saveVersion(InterfaceGeneralModel $objModel, $strUsername) { $objCount = $this->objDatabase->prepare("SELECT count(*) as mycount FROM tl_version WHERE pid=? AND fromTable = ?")->execute($objModel->getID(), $this->strSource); $mixNewVersion = intval($objCount->mycount) + 1; $mixData = $objModel->getPropertiesAsArray(); $mixData["id"] = $objModel->getID(); $mixData = serialize($mixData); $arrInsert = array(); $arrInsert['pid'] = $objModel->getID(); $arrInsert['tstamp'] = time(); $arrInsert['version'] = $mixNewVersion; $arrInsert['fromTable'] = $this->strSource; $arrInsert['username'] = $strUsername; $arrInsert['data'] = $mixData; $this->objDatabase->prepare('INSERT INTO tl_version %s')->set($arrInsert)->execute(); $this->setVersionActive($objModel->getID(), $mixNewVersion); }
/** * Save a model to the database. * * In general, this method fetches the solely property "rows" from the model and updates the local table against * these contents. * * The parent id (id of the model) will get checked and reflected also for new items. * * When rows with duplicate ids are encountered (like from MCW for example), the dupes are inserted as new rows. * * @param InterfaceGeneralModel $objItem The model to save. * * @param bool $recursive Ignored as not relevant in this data provider. * * @return InterfaceGeneralModel The passed Model. * * @throws Exception When the passed model does not contain a property named "rows", an Exception is thrown. */ public function save(InterfaceGeneralModel $objItem, $recursive = false) { $arrData = $objItem->getProperty('rows'); if (!($objItem->getID() && $arrData)) { throw new Exception('invalid input data in model.', 1); } $arrKeep = array(); foreach ($arrData as $i => $arrRow) { // TODO: add an option to restrict this to some allowed fields? $arrSQL = $arrRow; // update all. $intId = intval($arrRow['id']); // Work around the fact that multicolumnwizard does not clear any hidden fields when copying a dataset. // therefore we do consider any dupe as new dataset and save it accordingly. if (in_array($intId, $arrKeep)) { $intId = 0; unset($arrSQL['id']); } if ($intId > 0) { $this->objDatabase->prepare(sprintf('UPDATE tl_metamodel_dca_combine %%s WHERE id=? AND %s=?', $this->strGroupCol))->set($arrSQL)->execute($intId, $objItem->getId()); $arrKeep[] = $intId; } else { // force group col value: $arrSQL[$this->strGroupCol] = $objItem->getId(); $arrKeep[] = $this->objDatabase->prepare('INSERT INTO tl_metamodel_dca_combine %s')->set($arrSQL)->execute()->insertId; } } // house keeping, kill the rest. $this->objDatabase->prepare(sprintf('DELETE FROM tl_metamodel_dca_combine WHERE %s=? AND id NOT IN (%s)', $this->strGroupCol, implode(',', $arrKeep)))->execute($objItem->getId()); return $objItem; }