public function run() { require_once TL_ROOT . '/system/config/langconfig.php'; if ($this->Database->tableExists('tl_metafields')) { return false; } if (!is_array($GLOBALS['TL_LANG']['additional_metafields'])) { return false; } if (!array_key_exists('additional_metafields_exts', $GLOBALS['TL_CONFIG'])) { return false; } if (strlen($GLOBALS['TL_CONFIG']['additional_metafields_exts']) === 0) { return false; } $exts = $GLOBALS['TL_CONFIG']['additional_metafields_exts']; $dcaExt = new DcaExtractor('tl_metafields'); $arrSql = $dcaExt->getDbInstallerArray(); $strSql = "CREATE TABLE `tl_metafields` (" . implode(',', $arrSql["TABLE_FIELDS"]) . ',' . implode(',', $arrSql["TABLE_CREATE_DEFINITIONS"]) . ')' . $arrSql["TABLE_OPTIONS"] . ';'; $this->Database->execute($strSql); foreach ($GLOBALS['TL_LANG']['additional_metafields'] as $alias => $label) { $objModel = new MetafieldsModel(); $objModel->tstamp = time(); $objModel->alias = $alias; $objModel->label = $label; $objModel->extensions = $exts; $objModel->save(); } }
/** * Build a query based on the given options * * @param array $arrOptions The options array * * @return string The query string */ public static function find($arrOptions) { $objBase = new \DcaExtractor($arrOptions['table']); if (!$objBase->hasRelations()) { $strQuery = "SELECT * FROM " . $arrOptions['table']; } else { $arrJoins = array(); $arrFields = array($arrOptions['table'] . ".*"); $intCount = 0; foreach ($objBase->getRelations() as $strKey => $arrConfig) { // Automatically join the single-relation records if ($arrConfig['load'] == 'eager' || $arrOptions['eager']) { if ($arrConfig['type'] == 'hasOne' || $arrConfig['type'] == 'belongsTo') { ++$intCount; $objRelated = new \DcaExtractor($arrConfig['table']); foreach (array_keys($objRelated->getFields()) as $strField) { $arrFields[] = 'j' . $intCount . '.' . $strField . ' AS ' . $strKey . '__' . $strField; } $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " j{$intCount} ON " . $arrOptions['table'] . "." . $strKey . "=j{$intCount}.id"; } } } // Generate the query $strQuery = "SELECT " . implode(', ', $arrFields) . " FROM " . $arrOptions['table'] . implode("", $arrJoins); } // Where condition if ($arrOptions['column'] !== null) { $strQuery .= " WHERE " . (is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?"); } // Order by if ($arrOptions['order'] !== null) { $strQuery .= " ORDER BY " . $arrOptions['order']; } return $strQuery; }
public function getTableHeader(\DataContainer $dc) { \System::loadLanguageFile('tl_anystores'); $arrLabels = array(); $arrFields = \DcaExtractor::getInstance('tl_anystores')->getFields(); foreach ($arrFields as $key => $value) { $arrLabels[$key] = $GLOBALS['TL_LANG']['tl_anystores'][$key][0] ?: $key; } return $arrLabels; }
/** * Auto-format model data based on DCA config * @param \Model * @param callable * @return \ArrayObject */ public static function generate(\Model $objModel = null, $varCallable = null) { if (null === $objModel) { return new \ArrayObject(array(), \ArrayObject::ARRAY_AS_PROPS); } $strTable = $objModel->getTable(); $objDca = new \DcaExtractor($strTable); $arrRelations = $objDca->getRelations(); $arrData = array(); \System::loadLanguageFile($strTable); \Controller::loadDataContainer($strTable); $arrFields =& $GLOBALS['TL_DCA'][$strTable]['fields']; foreach ($objModel->row() as $strField => $varValue) { $arrAdditional = array(); $strLabel = Format::dcaLabel($strTable, $strField); if (isset($arrRelations[$strField])) { $objRelated = $objModel->getRelated($strField); if ($objRelated == null) { $arrData[$strField] = new Plain('', $strLabel, $arrAdditional); } elseif ($objRelated instanceof \Model\Collection) { $arrCollection = array(); foreach ($objRelated as $objRelatedModel) { $arrCollection[] = new Relation($objRelatedModel, '', array(), $varCallable); } $arrData[$strField] = new Collection($arrCollection, $strLabel); } else { $arrData[$strField] = new Relation($objRelated, $strLabel, array(), $varCallable); } continue; } $arrAdditional['formatted'] = Format::dcaValue($strTable, $strField, $varValue); if (in_array($arrFields[$strField]['eval']['rgxp'], array('date', 'datim', 'time'))) { $arrData[$strField] = new Timestamp($varValue, $strLabel, $arrAdditional); } else { $arrData[$strField] = new Plain($varValue, $strLabel, $arrAdditional); } } if (null !== $varCallable) { call_user_func_array($varCallable, array($objModel, &$arrData)); } return new \ArrayObject($arrData, \ArrayObject::ARRAY_AS_PROPS); }
/** * FieldPaletteDcaExtractor is required to disable usage of cached dca file * if internal contao cache is active, as fields get added dynamically * * @param string $strTable * * @throws \Exception */ public function __construct($strTable) { if ($strTable == '') { throw new \Exception('The table name must not be empty'); } if ($strTable !== \Config::get('fieldpalette_table')) { parent::__construct($strTable); } $this->strTable = \Config::get('fieldpalette_table'); // prevent caching for fieldpalette $this->createExtract(); }
/** * Load the relations and optionally process a result set * * @param \Database_Result $objResult An optional database result */ public function __construct(\Database_Result $objResult = null) { parent::__construct(); $objRelations = new \DcaExtractor(static::$strTable); $this->arrRelations = $objRelations->getRelations(); if ($objResult !== null) { $this->arrData = $objResult->row(); // Look for joined fields foreach ($this->arrData as $k => $v) { if (strpos($k, '__') !== false) { list($key, $field) = explode('__', $k, 2); // Create the related model if (!isset($this->arrRelated[$key])) { $table = $this->arrRelations[$key]['table']; $strClass = $this->getModelClassFromTable($table); $this->arrRelated[$key] = new $strClass(); } $this->arrRelated[$key]->{$field} = $v; unset($this->arrData[$k]); } } } }
/** * Get the DCA table settings from the DCA cache * * @return array An array of DCA table settings */ public function getFromDca() { $return = array(); $included = array(); // Ignore the internal cache $blnBypassCache = \Config::get('bypassCache'); \Config::set('bypassCache', true); // Only check the active modules (see #4541) foreach (\ModuleLoader::getActive() as $strModule) { $strDir = 'system/modules/' . $strModule . '/dca'; if (!is_dir(TL_ROOT . '/' . $strDir)) { continue; } foreach (scan(TL_ROOT . '/' . $strDir) as $strFile) { // Ignore non PHP files and files which have been included before if (substr($strFile, -4) != '.php' || in_array($strFile, $included)) { continue; } $strTable = substr($strFile, 0, -4); $objExtract = \DcaExtractor::getInstance($strTable); if ($objExtract->isDbTable()) { $return[$strTable] = $objExtract->getDbInstallerArray(); } $included[] = $strFile; } } // Restore the cache settings \Config::set('bypassCache', $blnBypassCache); // HOOK: allow third-party developers to modify the array (see #6425) if (isset($GLOBALS['TL_HOOKS']['sqlGetFromDca']) && is_array($GLOBALS['TL_HOOKS']['sqlGetFromDca'])) { foreach ($GLOBALS['TL_HOOKS']['sqlGetFromDca'] as $callback) { $this->import($callback[0]); $return = $this->{$callback[0]}->{$callback[1]}($return); } } return $return; }
/** * Compare versions */ public function compare() { $strBuffer = ''; $arrVersions = array(); $intTo = 0; $intFrom = 0; $objVersions = $this->Database->prepare("SELECT * FROM tl_version WHERE pid=? AND fromTable=? ORDER BY version DESC")->execute($this->intPid, $this->strTable); if ($objVersions->numRows < 2) { $strBuffer = '<p>There are no versions of ' . $this->strTable . '.id=' . $this->intPid . '</p>'; } else { $intIndex = 0; $from = array(); // Store the versions and mark the active one while ($objVersions->next()) { if ($objVersions->active) { $intIndex = $objVersions->version; } $arrVersions[$objVersions->version] = $objVersions->row(); $arrVersions[$objVersions->version]['info'] = $GLOBALS['TL_LANG']['MSC']['version'] . ' ' . $objVersions->version . ' (' . \Date::parse(\Config::get('datimFormat'), $objVersions->tstamp) . ') ' . $objVersions->username; } // To if (\Input::post('to') && isset($arrVersions[\Input::post('to')])) { $intTo = \Input::post('to'); $to = deserialize($arrVersions[\Input::post('to')]['data']); } elseif (\Input::get('to') && isset($arrVersions[\Input::get('to')])) { $intTo = \Input::get('to'); $to = deserialize($arrVersions[\Input::get('to')]['data']); } else { $intTo = $intIndex; $to = deserialize($arrVersions[$intTo]['data']); } // From if (\Input::post('from') && isset($arrVersions[\Input::post('from')])) { $intFrom = \Input::post('from'); $from = deserialize($arrVersions[\Input::post('from')]['data']); } elseif (\Input::get('from') && isset($arrVersions[\Input::get('from')])) { $intFrom = \Input::get('from'); $from = deserialize($arrVersions[\Input::get('from')]['data']); } elseif ($intIndex > 1) { $intFrom = $intIndex - 1; $from = deserialize($arrVersions[$intFrom]['data']); } // Only continue if both version numbers are set if ($intTo > 0 && $intFrom > 0) { \System::loadLanguageFile($this->strTable); $this->loadDataContainer($this->strTable); // Get the order fields $objDcaExtractor = \DcaExtractor::getInstance($this->strTable); $arrOrder = $objDcaExtractor->getOrderFields(); // Find the changed fields and highlight the changes foreach ($to as $k => $v) { if ($from[$k] != $to[$k]) { if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['inputType'] == 'password' || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['doNotShow'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['hideInput']) { continue; } $blnIsBinary = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['inputType'] == 'fileTree' || in_array($k, $arrOrder); // Decrypt the values if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['encrypt']) { $to[$k] = \Encryption::decrypt($to[$k]); $from[$k] = \Encryption::decrypt($from[$k]); } // Convert serialized arrays into strings if (is_array($tmp = deserialize($to[$k])) && !is_array($to[$k])) { $to[$k] = $this->implodeRecursive($tmp, $blnIsBinary); } if (is_array($tmp = deserialize($from[$k])) && !is_array($from[$k])) { $from[$k] = $this->implodeRecursive($tmp, $blnIsBinary); } unset($tmp); // Convert binary UUIDs to their hex equivalents (see #6365) if ($blnIsBinary && \Validator::isBinaryUuid($to[$k])) { $to[$k] = \String::binToUuid($to[$k]); } if ($blnIsBinary && \Validator::isBinaryUuid($from[$k])) { $to[$k] = \String::binToUuid($from[$k]); } // Convert date fields if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'date') { $to[$k] = \Date::parse(\Config::get('dateFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('dateFormat'), $from[$k] ?: ''); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'time') { $to[$k] = \Date::parse(\Config::get('timeFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('timeFormat'), $from[$k] ?: ''); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'datim' || $k == 'tstamp') { $to[$k] = \Date::parse(\Config::get('datimFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('datimFormat'), $from[$k] ?: ''); } // Convert strings into arrays if (!is_array($to[$k])) { $to[$k] = explode("\n", $to[$k]); } if (!is_array($from[$k])) { $from[$k] = explode("\n", $from[$k]); } $objDiff = new \Diff($from[$k], $to[$k]); $strBuffer .= $objDiff->Render(new DiffRenderer(array('field' => $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['label'][0] ?: (isset($GLOBALS['TL_LANG']['MSC'][$k]) ? is_array($GLOBALS['TL_LANG']['MSC'][$k]) ? $GLOBALS['TL_LANG']['MSC'][$k][0] : $GLOBALS['TL_LANG']['MSC'][$k] : $k)))); } } } } // Identical versions if ($strBuffer == '') { $strBuffer = '<p>' . $GLOBALS['TL_LANG']['MSC']['identicalVersions'] . '</p>'; } /** @var \BackendTemplate|object $objTemplate */ $objTemplate = new \BackendTemplate('be_diff'); // Template variables $objTemplate->content = $strBuffer; $objTemplate->versions = $arrVersions; $objTemplate->to = $intTo; $objTemplate->from = $intFrom; $objTemplate->showLabel = specialchars($GLOBALS['TL_LANG']['MSC']['showDifferences']); $objTemplate->theme = \Backend::getTheme(); $objTemplate->base = \Environment::get('base'); $objTemplate->language = $GLOBALS['TL_LANGUAGE']; $objTemplate->title = specialchars($GLOBALS['TL_LANG']['MSC']['showDifferences']); $objTemplate->charset = \Config::get('characterSet'); $objTemplate->action = ampersand(\Environment::get('request')); \Config::set('debugMode', false); $objTemplate->output(); exit; }
/** * Add the table tl_files to the XML and the files to the archive * @param \DOMDocument $xml * @param \DOMNode|\DOMElement $tables * @param \Database\Result|object $objTheme * @param \ZipWriter $objArchive */ protected function addTableTlFiles(\DOMDocument $xml, \DOMElement $tables, \Database\Result $objTheme, \ZipWriter $objArchive) { // Add the table $table = $xml->createElement('table'); $table->setAttribute('name', 'tl_files'); $table = $tables->appendChild($table); // Load the DCA $this->loadDataContainer('tl_files'); // Get the order fields $objDcaExtractor = \DcaExtractor::getInstance('tl_files'); $arrOrder = $objDcaExtractor->getOrderFields(); // Add the folders $arrFolders = deserialize($objTheme->folders); if (!empty($arrFolders) && is_array($arrFolders)) { $objFolders = \FilesModel::findMultipleByUuids($arrFolders); if ($objFolders !== null) { foreach ($this->eliminateNestedPaths($objFolders->fetchEach('path')) as $strFolder) { $this->addFolderToArchive($objArchive, $strFolder, $xml, $table, $arrOrder); } } } }
/** * Add the table tl_layout * @param \DOMDocument * @param \DOMElement * @param \Database\Result */ protected function addTableTlLayout(\DOMDocument $xml, \DOMElement $tables, \Database\Result $objTheme) { // Add the table $table = $xml->createElement('table'); $table->setAttribute('name', 'tl_layout'); $table = $tables->appendChild($table); // Load the DCA $this->loadDataContainer('tl_layout'); // Get the order fields $objDcaExtractor = new \DcaExtractor('tl_layout'); $arrOrder = $objDcaExtractor->getOrderFields(); // Get all layouts $objLayout = $this->Database->prepare("SELECT * FROM tl_layout WHERE pid=? ORDER BY name")->execute($objTheme->id); // Add the rows while ($objLayout->next()) { $this->addDataRow($xml, $table, $objLayout, $arrOrder); } }
/** * Create the DCA extract cache files */ public function generateDcaExtracts() { $included = array(); $arrExtracts = array(); // Only check the active modules (see #4541) foreach (\ModuleLoader::getActive() as $strModule) { $strDir = 'system/modules/' . $strModule . '/dca'; if (!is_dir(TL_ROOT . '/' . $strDir)) { continue; } foreach (scan(TL_ROOT . '/' . $strDir) as $strFile) { // Ignore non PHP files and files which have been included before if (strncmp($strFile, '.', 1) === 0 || substr($strFile, -4) != '.php' || in_array($strFile, $included)) { continue; } $strTable = substr($strFile, 0, -4); $objExtract = \DcaExtractor::getInstance($strTable); if ($objExtract->isDbTable()) { $arrExtracts[$strTable] = $objExtract; } $included[] = $strFile; } } /** @var \DcaExtractor[] $arrExtracts */ foreach ($arrExtracts as $strTable => $objExtract) { // Create the file $objFile = new \File('system/cache/sql/' . $strTable . '.php', true); $objFile->write("<?php\n\n"); $objFile->append(sprintf("\$this->arrMeta = %s;\n", var_export($objExtract->getMeta(), true))); $objFile->append(sprintf("\$this->arrFields = %s;\n", var_export($objExtract->getFields(), true))); $objFile->append(sprintf("\$this->arrOrderFields = %s;\n", var_export($objExtract->getOrderFields(), true))); $objFile->append(sprintf("\$this->arrKeys = %s;\n", var_export($objExtract->getKeys(), true))); $objFile->append(sprintf("\$this->arrRelations = %s;\n", var_export($objExtract->getRelations(), true))); // Set the database table flag $objFile->append("\$this->blnIsDbTable = true;", "\n"); // Close the file (moves it to its final destination) $objFile->close(); } // Add a log entry $this->log('Generated the DCA extracts', __METHOD__, TL_CRON); }
/** * Load the relations and optionally process a result set * * @param \Database\Result $objResult An optional database result */ public function __construct(\Database\Result $objResult = null) { $this->arrModified = array(); $objDca = new \DcaExtractor(static::$strTable); $this->arrRelations = $objDca->getRelations(); if ($objResult !== null) { $arrRelated = array(); $arrData = $objResult->row(); // Look for joined fields foreach ($arrData as $k => $v) { if (strpos($k, '__') !== false) { list($key, $field) = explode('__', $k, 2); if (!isset($arrRelated[$key])) { $arrRelated[$key] = array(); } $arrRelated[$key][$field] = $v; unset($arrData[$k]); } } // Create the related models foreach ($arrRelated as $key => $row) { $table = $this->arrRelations[$key]['table']; $strClass = static::getClassFromTable($table); $intPk = $strClass::getPk(); // If the primary key is empty, set null (see #5356) if (!isset($row[$intPk])) { $this->arrRelated[$key] = null; } else { $objRelated = \Model\Registry::getInstance()->fetch($table, $row[$intPk]); if ($objRelated !== null) { $objRelated->mergeRow($row); } else { $objRelated = new $strClass(); $objRelated->setRow($row); } $this->arrRelated[$key] = $objRelated; } } $this->setRow($arrData); // see #5439 \Model\Registry::getInstance()->register($this); } }
/** * Return all non-excluded fields of a record as HTML table * * @return string */ public function show() { if (!strlen($this->intId)) { return ''; } $objRow = $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE id=?")->limit(1)->execute($this->intId); if ($objRow->numRows < 1) { return ''; } $count = 1; $return = ''; $row = $objRow->row(); // Get the order fields $objDcaExtractor = \DcaExtractor::getInstance($this->strTable); $arrOrder = $objDcaExtractor->getOrderFields(); // Get all fields $fields = array_keys($row); $allowedFields = array('id', 'pid', 'sorting', 'tstamp'); if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'])) { $allowedFields = array_unique(array_merge($allowedFields, array_keys($GLOBALS['TL_DCA'][$this->strTable]['fields']))); } // Use the field order of the DCA file $fields = array_intersect($allowedFields, $fields); // Show all allowed fields foreach ($fields as $i) { if (!in_array($i, $allowedFields) || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'password' || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['doNotShow'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['hideInput']) { continue; } // Special treatment for table tl_undo if ($this->strTable == 'tl_undo' && $i == 'data') { continue; } $value = deserialize($row[$i]); // Decrypt the value if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['encrypt']) { $value = \Encryption::decrypt($value); } $class = $count++ % 2 == 0 ? ' class="tl_bg"' : ''; // Get the field value if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey'])) { $temp = array(); $chunks = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey'], 2); foreach ((array) $value as $v) { $objKey = $this->Database->prepare("SELECT " . $chunks[1] . " AS value FROM " . $chunks[0] . " WHERE id=?")->limit(1)->execute($v); if ($objKey->numRows) { $temp[] = $objKey->value; } } $row[$i] = implode(', ', $temp); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'fileTree' || in_array($i, $arrOrder)) { if (is_array($value)) { foreach ($value as $kk => $vv) { $value[$kk] = $vv ? \StringUtil::binToUuid($vv) : ''; } $row[$i] = implode(', ', $value); } else { $row[$i] = $value ? \StringUtil::binToUuid($value) : ''; } } elseif (is_array($value)) { foreach ($value as $kk => $vv) { if (is_array($vv)) { $vals = array_values($vv); $value[$kk] = $vals[0] . ' (' . $vals[1] . ')'; } } $row[$i] = implode(', ', $value); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'date') { $row[$i] = $value ? \Date::parse(\Config::get('dateFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'time') { $row[$i] = $value ? \Date::parse(\Config::get('timeFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'datim' || in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['flag'], array(5, 6, 7, 8, 9, 10)) || $i == 'tstamp') { $row[$i] = $value ? \Date::parse(\Config::get('datimFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['multiple']) { $row[$i] = $value != '' ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no']; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'textarea' && ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['allowHtml'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['preserveTags'])) { $row[$i] = specialchars($value); } elseif (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'])) { $row[$i] = isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) ? is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]] : $row[$i]; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options'])) { $row[$i] = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options'][$row[$i]]; } else { $row[$i] = $value; } // Label if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'])) { $label = is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']; } else { $label = is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i]; } if ($label == '') { $label = $i; } $return .= ' <tr> <td' . $class . '><span class="tl_label">' . $label . ': </span></td> <td' . $class . '>' . $row[$i] . '</td> </tr>'; } // Special treatment for tl_undo if ($this->strTable == 'tl_undo') { $arrData = deserialize($objRow->data); foreach ($arrData as $strTable => $arrTableData) { \System::loadLanguageFile($strTable); $this->loadDataContainer($strTable); foreach ($arrTableData as $arrRow) { $count = 0; $return .= ' <tr> <td colspan="2" style="padding:0"><div style="margin-bottom:26px;line-height:24px;border-bottom:1px dotted #ccc"> </div></td> </tr>'; foreach ($arrRow as $i => $v) { if (is_array(deserialize($v))) { continue; } $class = $count++ % 2 == 0 ? ' class="tl_bg"' : ''; // Get the field label if (isset($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'])) { $label = is_array($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']; } else { $label = is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i]; } if (!strlen($label)) { $label = $i; } // Always encode special characters (thanks to Oliver Klee) $return .= ' <tr> <td' . $class . '><span class="tl_label">' . $label . ': </span></td> <td' . $class . '>' . specialchars($v) . '</td> </tr>'; } } } } // Return table return ' <div id="tl_buttons">' . (!\Input::get('popup') ? ' <a href="' . $this->getReferer(true) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a>' : '') . ' </div> <table class="tl_show">' . $return . ' </table>'; }
/** * Return select statement to load product data including multilingual fields * @param array an array of columns * @return string */ protected static function buildFindQuery(array $arrOptions) { $objBase = new \DcaExtractor($arrOptions['table']); $arrJoins = array(); $arrFields = array($arrOptions['table'] . ".*", "IF(" . $arrOptions['table'] . ".pid>0, parent.type, " . $arrOptions['table'] . ".type) AS type", "'" . str_replace('-', '_', $GLOBALS['TL_LANGUAGE']) . "' AS language"); foreach (Attribute::getMultilingualFields() as $attribute) { $arrFields[] = "IFNULL(translation.{$attribute}, " . $arrOptions['table'] . ".{$attribute}) AS {$attribute}"; } foreach (Attribute::getFetchFallbackFields() as $attribute) { $arrFields[] = "{$arrOptions['table']}.{$attribute} AS {$attribute}_fallback"; } $arrFields[] = "c.sorting"; $arrJoins[] = " LEFT OUTER JOIN " . \Isotope\Model\ProductCategory::getTable() . " c ON {$arrOptions['table']}.id=c.pid"; $arrJoins[] = " LEFT OUTER JOIN " . $arrOptions['table'] . " translation ON " . $arrOptions['table'] . ".id=translation.pid AND translation.language='" . str_replace('-', '_', $GLOBALS['TL_LANGUAGE']) . "'"; $arrJoins[] = " LEFT OUTER JOIN " . $arrOptions['table'] . " parent ON " . $arrOptions['table'] . ".pid=parent.id"; if ($objBase->hasRelations()) { $intCount = 0; foreach ($objBase->getRelations() as $strKey => $arrConfig) { // Automatically join the single-relation records if ($arrConfig['load'] == 'eager' || $arrOptions['eager']) { if ($arrConfig['type'] == 'hasOne' || $arrConfig['type'] == 'belongsTo') { if (is_array($arrOptions['joinAliases']) && ($key = array_search($arrConfig['table'], $arrOptions['joinAliases'])) !== false) { $strJoinAlias = $key; unset($arrOptions['joinAliases'][$key]); } else { ++$intCount; $strJoinAlias = 'j' . $intCount; } $objRelated = new \DcaExtractor($arrConfig['table']); foreach (array_keys($objRelated->getFields()) as $strField) { $arrFields[] = $strJoinAlias . '.' . $strField . ' AS ' . $strKey . '__' . $strField; } $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " {$strJoinAlias} ON " . $arrOptions['table'] . "." . $strKey . "={$strJoinAlias}.id"; } } } } // Generate the query $strQuery = "SELECT " . implode(', ', $arrFields) . " FROM " . $arrOptions['table'] . implode("", $arrJoins); // Where condition if (!is_array($arrOptions['column'])) { $arrOptions['column'] = array($arrOptions['table'] . '.' . $arrOptions['column'] . '=?'); } // The model must never find a language record $strQuery .= " WHERE {$arrOptions['table']}.language='' AND " . implode(" AND ", $arrOptions['column']); // Group by if ($arrOptions['group'] !== null) { $strQuery .= " GROUP BY " . $arrOptions['group']; } // Order by if ($arrOptions['order'] !== null) { $strQuery .= " ORDER BY " . $arrOptions['order']; } return $strQuery; }
/** * Create the DCA extract cache files */ public function generateDcaExtracts() { $included = array(); $arrExtracts = array(); // Only check the active modules (see #4541) foreach (\ModuleLoader::getActive() as $strModule) { $strDir = 'system/modules/' . $strModule . '/dca'; if (!is_dir(TL_ROOT . '/' . $strDir)) { continue; } foreach (scan(TL_ROOT . '/' . $strDir) as $strFile) { // Ignore non PHP files and files which have been included before if (strncmp($strFile, '.', 1) === 0 || substr($strFile, -4) != '.php' || in_array($strFile, $included)) { continue; } $strTable = substr($strFile, 0, -4); $objExtract = new \DcaExtractor($strTable); if ($objExtract->isDbTable()) { $arrExtracts[$strTable] = $objExtract; } $included[] = $strFile; } } // Create one file per table foreach ($arrExtracts as $strTable => $objExtract) { // Create the file $objFile = new \File('system/cache/sql/' . $strTable . '.php', true); $objFile->write("<?php\n\n"); // Meta $arrMeta = $objExtract->getMeta(); $objFile->append("\$this->arrMeta = array\n("); $objFile->append("\t'engine' => '{$arrMeta['engine']}',"); $objFile->append("\t'charset' => '{$arrMeta['charset']}',"); $objFile->append(');', "\n\n"); // Fields $arrFields = $objExtract->getFields(); $objFile->append("\$this->arrFields = array\n("); foreach ($arrFields as $field => $sql) { $sql = str_replace('"', '\\"', $sql); $objFile->append("\t'{$field}' => \"{$sql}\","); } $objFile->append(');', "\n\n"); // Order fields $arrFields = $objExtract->getOrderFields(); $objFile->append("\$this->arrOrderFields = array\n("); foreach ($arrFields as $field) { $objFile->append("\t'{$field}',"); } $objFile->append(');', "\n\n"); // Keys $arrKeys = $objExtract->getKeys(); $objFile->append("\$this->arrKeys = array\n("); foreach ($arrKeys as $field => $type) { $objFile->append("\t'{$field}' => '{$type}',"); } $objFile->append(');', "\n\n"); // Relations $arrRelations = $objExtract->getRelations(); $objFile->append("\$this->arrRelations = array\n("); foreach ($arrRelations as $field => $config) { $objFile->append("\t'{$field}' => array\n\t("); foreach ($config as $k => $v) { $objFile->append("\t\t'{$k}' => '{$v}',"); } $objFile->append("\t),"); } $objFile->append(');', "\n\n"); // Set the database table flag $objFile->append("\$this->blnIsDbTable = true;", "\n"); // Close the file (moves it to its final destination) $objFile->close(); } // Add a log entry $this->log('Generated the DCA extracts', __METHOD__, TL_CRON); }
/** * Get the DCA table settings from the DCA cache * * @return array An array of DCA table settings */ protected function getFromDca() { $arrTables = array(); // Scan the modules foreach (scan(TL_ROOT . '/system/modules') as $strModule) { $dir = TL_ROOT . '/system/modules/' . $strModule . '/dca'; if (!is_dir($dir)) { continue; } foreach (scan($dir) as $strTable) { if (strncmp($strTable, '.', 1) === 0 || strrchr($strTable, '.') != '.php') { continue; } if ($strTable == 'tl_settings.php' || $strTable == 'tl_templates.php') { continue; } $arrTables[] = str_replace('.php', '', $strTable); } } $return = array(); $arrTables = array_values(array_unique($arrTables)); foreach ($arrTables as $strTable) { $objTable = new \DcaExtractor($strTable); $return[$strTable] = $objTable->getDbInstallerArray(); } return $return; }
/** * Get the DCA table settings from the DCA cache * * @return array An array of DCA table settings */ protected function getFromDca() { $arrReturn = array(); $arrTables = \DcaExtractor::createAllExtracts(); foreach ($arrTables as $strTable => $objTable) { $arrReturn[$strTable] = $objTable->getDbInstallerArray(); } return $arrReturn; }
/** * Create all extracts * * @return array An array of DcaExtractors */ public static function createAllExtracts() { $included = array(); $arrExtracts = array(); // Only check the active modules (see #4541) foreach (\Config::getInstance()->getActiveModules() as $strModule) { $strDir = TL_ROOT . '/system/modules/' . $strModule . '/dca'; if (!is_dir($strDir)) { continue; } foreach (scan($strDir) as $strFile) { if (in_array($strFile, $included) || $strFile == '.htaccess') { continue; } $included[] = $strFile; $strTable = str_replace('.php', '', $strFile); $objExtract = new \DcaExtractor($strTable); if ($objExtract->isDbTable()) { $arrExtracts[$strTable] = $objExtract; } } } return $arrExtracts; }
/** * Get the DCA table settings from the DCA cache * * @return array An array of DCA table settings */ public function getFromDca() { $return = array(); $processed = array(); /** @var SplFileInfo[] $files */ $files = \System::getContainer()->get('contao.resource_finder')->findIn('dca')->depth(0)->files()->name('*.php'); foreach ($files as $file) { if (in_array($file->getBasename(), $processed)) { continue; } $processed[] = $file->getBasename(); $strTable = $file->getBasename('.php'); $objExtract = \DcaExtractor::getInstance($strTable); if ($objExtract->isDbTable()) { $return[$strTable] = $objExtract->getDbInstallerArray(); } } // HOOK: allow third-party developers to modify the array (see #6425) if (isset($GLOBALS['TL_HOOKS']['sqlGetFromDca']) && is_array($GLOBALS['TL_HOOKS']['sqlGetFromDca'])) { foreach ($GLOBALS['TL_HOOKS']['sqlGetFromDca'] as $callback) { $this->import($callback[0]); $return = $this->{$callback[0]}->{$callback[1]}($return); } } return $return; }
/** * Version 3.0.0 update */ public function run300Update() { // Create the files table $this->Database->query("CREATE TABLE `tl_files` (\n\t\t\t `id` int(10) unsigned NOT NULL auto_increment,\n\t\t\t `pid` int(10) unsigned NOT NULL default '0',\n\t\t\t `tstamp` int(10) unsigned NOT NULL default '0',\n\t\t\t `type` varchar(16) NOT NULL default '',\n\t\t\t `path` varchar(255) NOT NULL default '',\n\t\t\t `extension` varchar(16) NOT NULL default '',\n\t\t\t `hash` varchar(32) NOT NULL default '',\n\t\t\t `found` char(1) NOT NULL default '1',\n\t\t\t `name` varchar(64) NOT NULL default '',\n\t\t\t `meta` blob NULL,\n\t\t\t PRIMARY KEY (`id`),\n\t\t\t KEY `pid` (`pid`),\n\t\t\t UNIQUE KEY `path` (`path`),\n\t\t\t KEY `extension` (`extension`)\n\t\t\t) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); // Create the DCA extracts (will also create the DCA cache) \DcaExtractor::createAllExtracts(); // Add the "numberOfItems" field $this->Database->query("ALTER TABLE `tl_module` ADD `numberOfItems` smallint(5) unsigned NOT NULL default '0'"); $this->Database->query("UPDATE `tl_module` SET `numberOfItems`=`rss_numberOfItems` WHERE `rss_numberOfItems`>0"); $this->Database->query("UPDATE `tl_module` SET `numberOfItems`=`news_numberOfItems` WHERE `news_numberOfItems`>0"); // Add the "addMooTools" field $this->Database->query("ALTER TABLE `tl_layout` ADD `addMooTools` char(1) NOT NULL default ''"); $this->Database->query("UPDATE `tl_layout` SET `addMooTools`=1 WHERE `mootools`!=''"); // Add the "notified" field $this->Database->query("ALTER TABLE `tl_comments` ADD `notified` char(1) NOT NULL default ''"); $this->Database->query("UPDATE `tl_comments` SET `notified`=1"); // Add the "rows" field $this->Database->query("ALTER TABLE `tl_layout` ADD `rows` varchar(8) NOT NULL default ''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='1rw' WHERE `header`='' AND `footer`=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='2rwh' WHERE `header`!='' AND `footer`=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='2rwf' WHERE `header`='' AND `footer`!=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='3rw' WHERE `header`!='' AND `footer`!=''"); // Update the "mooType" field $this->Database->query("UPDATE `tl_content` SET `mooType`='mooStart' WHERE `mooType`='start'"); $this->Database->query("UPDATE `tl_content` SET `mooType`='mooStop' WHERE `mooType`='stop'"); $this->Database->query("UPDATE `tl_content` SET `mooType`='mooSingle' WHERE `mooType`='single'"); // Add the "framework" field $this->Database->query("ALTER TABLE `tl_layout` ADD `framework` varchar(255) NOT NULL default ''"); $this->Database->query("UPDATE `tl_layout` SET `framework`='a:2:{i:0;s:10:\"layout.css\";i:1;s:11:\"tinymce.css\";}'"); $this->Database->query("UPDATE `tl_layout` SET `framework`='a:1:{i:0;s:10:\"layout.css\";}' WHERE skipTinymce=1"); // Make sure the "skipFramework" field exists (see #4624) if ($this->Database->fieldExists('skipFramework', 'tl_layout')) { $this->Database->query("UPDATE `tl_layout` SET `framework`='' WHERE skipFramework=1"); } // Add the "ptable" field $this->Database->query("ALTER TABLE `tl_content` ADD ptable varchar(64) NOT NULL default ''"); // Create a content element for each news article $objNews = $this->Database->execute("SELECT * FROM tl_news WHERE text!=''"); while ($objNews->next()) { $this->createContentElement($objNews, 'tl_news', 'text'); } // Create a content element for each event $objEvents = $this->Database->execute("SELECT * FROM tl_calendar_events WHERE details!=''"); while ($objEvents->next()) { $this->createContentElement($objEvents, 'tl_calendar_events', 'details'); } // Add an .htaccess file to the modules' html folders so they can be accessed via HTTP foreach (scan(TL_ROOT . '/system/modules') as $strFolder) { if (is_dir(TL_ROOT . '/system/modules/' . $strFolder) && is_dir(TL_ROOT . '/system/modules/' . $strFolder . '/html')) { if (!file_exists(TL_ROOT . '/system/modules/' . $strFolder . '/html/.htaccess')) { $objFile = new \File('system/modules/' . $strFolder . '/html/.htaccess'); $objFile->write("order deny,allow\nallow from all"); $objFile->close(); } } } // Convert the gradient angle syntax (see #4569) if ($this->Database->fieldExists('gradientAngle', 'tl_style')) { $objStyle = $this->Database->execute("SELECT id, gradientAngle FROM tl_style WHERE gradientAngle!=''"); while ($objStyle->next()) { if (strpos($objStyle->gradientAngle, 'deg') !== false) { $angle = abs(450 - intval($objStyle->gradientAngle)) % 360 . 'deg'; } else { switch ($objStyle->gradientAngle) { case 'top': $angle = 'to bottom'; break; case 'right': $angle = 'to left'; break; case 'bottom': $angle = 'to top'; break; case 'left': $angle = 'to right'; break; case 'top left': $angle = 'to bottom right'; break; case 'top right': $angle = 'to bottom left'; break; case 'bottom left': $angle = 'to top right'; break; case 'bottom right': $angle = 'to top left'; break; } } $this->Database->prepare("UPDATE tl_style SET gradientAngle=? WHERE id=?")->execute($angle, $objStyle->id); } } // Make unlimited recurrences end on 2038-01-01 00:00:00 (see #4862) $this->Database->query("UPDATE `tl_calendar_events` SET `repeatEnd`=2145913200 WHERE `recurring`=1 AND `recurrences`=0"); }
/** * Version 3.0.0 update */ public function run300Update() { // Create the files table $this->Database->query("CREATE TABLE `tl_files` (\n\t\t\t `id` int(10) unsigned NOT NULL auto_increment,\n\t\t\t `pid` int(10) unsigned NOT NULL default '0',\n\t\t\t `tstamp` int(10) unsigned NOT NULL default '0',\n\t\t\t `type` varchar(16) NOT NULL default '',\n\t\t\t `path` varchar(255) NOT NULL default '',\n\t\t\t `extension` varchar(16) NOT NULL default '',\n\t\t\t `hash` varchar(32) NOT NULL default '',\n\t\t\t `found` char(1) NOT NULL default '1',\n\t\t\t `name` varchar(64) NOT NULL default '',\n\t\t\t `meta` blob NULL,\n\t\t\t PRIMARY KEY (`id`),\n\t\t\t KEY `pid` (`pid`),\n\t\t\t KEY `path` (`path`),\n\t\t\t KEY `extension` (`extension`)\n\t\t\t) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); // Create the DCA extracts (will also create the DCA cache) \DcaExtractor::createAllExtracts(); // Add the "numberOfItems" field $this->Database->query("ALTER TABLE `tl_module` ADD `numberOfItems` smallint(5) unsigned NOT NULL default '0'"); $this->Database->query("UPDATE `tl_module` SET `numberOfItems`=`rss_numberOfItems` WHERE `rss_numberOfItems`>0"); $this->Database->query("UPDATE `tl_module` SET `numberOfItems`=`news_numberOfItems` WHERE `news_numberOfItems`>0"); // Add the "addMooTools" field $this->Database->query("ALTER TABLE `tl_layout` ADD `addMooTools` char(1) NOT NULL default ''"); $this->Database->query("UPDATE `tl_layout` SET `addMooTools`=1 WHERE `mooSource`!=''"); // Add the "rows" field $this->Database->query("ALTER TABLE `tl_layout` ADD `rows` varchar(8) NOT NULL default ''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='1rw' WHERE `header`='' AND `footer`=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='2rwh' WHERE `header`!='' AND `footer`=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='2rwf' WHERE `header`='' AND `footer`!=''"); $this->Database->query("UPDATE `tl_layout` SET `rows`='3rw' WHERE `header`!='' AND `footer`!=''"); }
/** * Return an array of unique field/column names (without the PK) * * @return array */ public static function getUniqueFields() { $objDca = \DcaExtractor::getInstance(static::getTable()); return $objDca->getUniqueFields(); }
/** * Build model based on database result * * @param \Database\Result $objResult * * @return \Model */ public static function createModelFromDbResult(\Database\Result $objResult) { $strClass = ''; if (is_numeric($objResult->type)) { $objRelations = new \DcaExtractor(static::$strTable); $arrRelations = $objRelations->getRelations(); if (isset($arrRelations['type'])) { $strTypeClass = static::getClassFromTable($arrRelations['type']['table']); $objType = $strTypeClass::findOneBy($arrRelations['type']['field'], $objResult->type); if (null !== $objType) { $strClass = static::getClassForModelType($objType->class); } } } else { $strClass = static::getClassForModelType($objResult->type); } // Try to use the current class as fallback if ($strClass == '') { $strClass = get_called_class(); $objReflection = new \ReflectionClass($strClass); if ($objReflection->isAbstract()) { return null; } } $objModel = new $strClass($objResult); if (null !== static::$strInterface && !is_a($objModel, static::$strInterface)) { throw new \RuntimeException(get_class($objModel) . ' must implement interface ' . static::$strInterface); } return $objModel; }