/** * @return string */ protected function resolveTableDefinitions() { $tableDefinitions = ''; foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $loadedExtConf) { if (is_array($loadedExtConf) && $loadedExtConf['ext_tables.sql']) { $extensionSqlContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($loadedExtConf['ext_tables.sql']); $tableDefinitions .= PHP_EOL . PHP_EOL . PHP_EOL . PHP_EOL . $extensionSqlContent; } } // Add SQL content coming from the caching framework $tableDefinitions .= \TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions(); // Add SQL content coming from the category registry $tableDefinitions .= \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->getDatabaseTableDefinitions(); return $tableDefinitions; }
/** * Load TCA * Mostly a copy of ExtensionManagementUtility to include TCA without migrations. * To be used in install tool only. * * This will set up $GLOBALS['TCA'] * * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::buildBaseTcaFromSingleFiles */ public function loadExtensionTablesWithoutMigration() { $GLOBALS['TCA'] = []; $activePackages = GeneralUtility::makeInstance(PackageManager::class)->getActivePackages(); // First load "full table" files from Configuration/TCA foreach ($activePackages as $package) { $tcaConfigurationDirectory = $package->getPackagePath() . 'Configuration/TCA'; if (is_dir($tcaConfigurationDirectory)) { $files = scandir($tcaConfigurationDirectory); foreach ($files as $file) { if (is_file($tcaConfigurationDirectory . '/' . $file) && $file !== '.' && $file !== '..' && substr($file, -4, 4) === '.php') { $tcaOfTable = (require $tcaConfigurationDirectory . '/' . $file); if (is_array($tcaOfTable)) { // TCA table name is filename without .php suffix, eg 'sys_notes', not 'sys_notes.php' $tcaTableName = substr($file, 0, -4); $GLOBALS['TCA'][$tcaTableName] = $tcaOfTable; } } } } } // Apply category stuff CategoryRegistry::getInstance()->applyTcaForPreRegisteredTables(); // Execute override files from Configuration/TCA/Overrides foreach ($activePackages as $package) { $tcaOverridesPathForPackage = $package->getPackagePath() . 'Configuration/TCA/Overrides'; if (is_dir($tcaOverridesPathForPackage)) { $files = scandir($tcaOverridesPathForPackage); foreach ($files as $file) { if (is_file($tcaOverridesPathForPackage . '/' . $file) && $file !== '.' && $file !== '..' && substr($file, -4, 4) === '.php') { require $tcaOverridesPathForPackage . '/' . $file; } } } } }
/** * Makes a table categorizable by adding value into the category registry. * FOR USE IN ext_localconf.php FILES or files in Configuration/TCA/Overrides/*.php Use the latter to benefit from TCA caching! * * @param string $extensionKey Extension key to be used * @param string $tableName Name of the table to be categorized * @param string $fieldName Name of the field to be used to store categories * @param array $options Additional configuration options * @param bool $override If TRUE, any category configuration for the same table / field is removed before the new configuration is added * @see addTCAcolumns * @see addToAllTCAtypes */ public static function makeCategorizable($extensionKey, $tableName, $fieldName = 'categories', array $options = array(), $override = false) { // Update the category registry $result = CategoryRegistry::getInstance()->add($extensionKey, $tableName, $fieldName, $options, $override); if ($result === false) { $message = CategoryRegistry::class . ': no category registered for table "%s". Key was already registered.'; /** @var $logger \TYPO3\CMS\Core\Log\Logger */ $logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__); $logger->warning(sprintf($message, $tableName)); } }
/** * The Database Analyzer * * @return void * @todo Define visibility */ public function checkTheDatabase() { if (!$this->config_array['mysqlConnect']) { $this->message('Database Analyser', 'Your database connection failed', ' <p> Please go to the \'Basic Configuration\' section and correct this problem first. </p> ', 2); $this->output($this->outputWrapper($this->printAll())); return; } if ($this->config_array['no_database']) { $this->message('Database Analyser', 'No database selected', ' <p> Please go to the \'Basic Configuration\' section and correct this problem first. </p> ', 2); $this->output($this->outputWrapper($this->printAll())); return; } // Getting current tables $whichTables = $this->sqlHandler->getListOfTables(); // Getting number of static_template records if ($whichTables['static_template']) { $static_template_count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', 'static_template'); } $static_template_count = intval($static_template_count); $headCode = 'Database Analyser'; $this->message($headCode, 'What is it?', ' <p> In this section you can get an overview of your currently selected database compared to sql-files. You can also import sql-data directly into the database or upgrade tables from earlier versions of TYPO3. </p> ', 0); $this->message($headCode, 'Connected to SQL database successfully', ' <dl id="t3-install-databaseconnected"> <dt> Username: </dt> <dd> ' . htmlspecialchars(TYPO3_db_username) . ' </dd> <dt> Host: </dt> <dd> ' . htmlspecialchars(TYPO3_db_host) . ' </dd> </dl> ', -1, 1); $this->message($headCode, 'Database', ' <p> <strong>' . htmlspecialchars(TYPO3_db) . '</strong> is selected as database. <br /> Has <strong>' . count($whichTables) . '</strong> tables. </p> ', -1, 1); // Menu $sql_files = array_merge(\TYPO3\CMS\Core\Utility\GeneralUtility::getFilesInDir(PATH_typo3conf, 'sql', 1, 1), array()); $action_type = $this->INSTALL['database_type']; $actionParts = explode('|', $action_type); if (count($actionParts) < 2) { $action_type = ''; } // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseMenu.html'); // Get the template part from the file $menu = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###MENU###'); $menuMarkers = array('action' => $this->action, 'updateRequiredTables' => 'Update required tables', 'compare' => 'COMPARE', 'noticeCmpFileCurrent' => $action_type == 'cmpFile|CURRENT_TABLES' ? ' class="notice"' : '', 'dumpStaticData' => 'Dump static data', 'import' => 'IMPORT', 'noticeImportCurrent' => $action_type == 'import|CURRENT_STATIC' ? ' class="notice"' : '', 'noticeCmpTca' => $action_type == 'cmpTCA|' ? ' class="notice"' : '', 'compareWithTca' => 'Compare with $TCA', 'noticeAdminUser' => $action_type == 'adminUser|' ? ' class="notice"' : '', 'createAdminUser' => 'Create "admin" user', 'noticeUc' => $action_type == 'UC|' ? ' class="notice"' : '', 'resetUserPreferences' => 'Reset user preferences', 'noticeCache' => $action_type == 'cache|' ? ' class="notice"' : '', 'clearTables' => 'Clear tables'); // Get the subpart for extra SQL $extraSql = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($menu, '###EXTRASQL###'); $directJump = ''; $extraSqlFiles = array(); foreach ($sql_files as $k => $file) { if ($this->mode == '123' && !count($whichTables) && strstr($file, '_testsite')) { $directJump = $this->action . '&TYPO3_INSTALL[database_type]=import|' . rawurlencode($file); } $lf = \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($k); $fShortName = substr($file, strlen(PATH_site)); $spec1 = $spec2 = ''; // Define the markers content $extraSqlMarkers = array('fileShortName' => $fShortName, 'fileSize' => \TYPO3\CMS\Core\Utility\GeneralUtility::formatSize(filesize($file)), 'noticeCmpFile' => $action_type == 'cmpFile|' . $file ? ' class="notice"' : '', 'file' => rawurlencode($file), 'noticeImport' => $action_type == 'import|' . $file ? ' class="notice"' : '', 'specs' => $spec1 . $spec2, 'noticeView' => $action_type == 'view|' . $file ? ' class="notice"' : '', 'view' => 'VIEW'); // Fill the markers in the subpart $extraSqlFiles[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($extraSql, $extraSqlMarkers, '###|###', TRUE, FALSE); } // Substitute the subpart for extra SQL $menu = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($menu, '###EXTRASQL###', implode(LF, $extraSqlFiles)); // Fill the markers $menu = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($menu, $menuMarkers, '###|###', TRUE, FALSE); if ($directJump) { if (!$action_type) { $this->message($headCode, 'Menu', ' <script language="javascript" type="text/javascript"> window.location.href = "' . $directJump . '"; </script>', 0, 1); } } else { $this->message($headCode, 'Menu', ' <p> From this menu you can select which of the available SQL files you want to either compare or import/merge with the existing database. </p> <dl id="t3-install-checkthedatabaseexplanation"> <dt> COMPARE: </dt> <dd> Compares the tables and fields of the current database and the selected file. It also offers to \'update\' the difference found. </dd> <dt> IMPORT: </dt> <dd> Imports the SQL-dump file into the current database. You can either dump the raw file or choose which tables to import. In any case, you\'ll see a new screen where you must confirm the operation. </dd> <dt> VIEW: </dt> <dd> Shows the content of the SQL-file, limiting characters on a single line to a reader-friendly amount. </dd> </dl> <p> The SQL-files are selected from typo3conf/ (here you can put your own) and t3lib/stddb/ (TYPO3 distribution). The SQL-files should be made by the <em>mysqldump</em> tool or at least be formatted like that tool would do. </p> ' . $menu, 0, 1); } if ($action_type) { switch ($actionParts[0]) { case 'cmpFile': $tblFileContent = ''; $hookObjects = array(); // Load TCA first $this->includeTCA(); if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install/mod/class.tx_install.php']['checkTheDatabase'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install/mod/class.tx_install.php']['checkTheDatabase'] as $classData) { /** @var $hookObject Tx_Install_Interfaces_CheckTheDatabaseHook * */ $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData); if (!$hookObject instanceof \TYPO3\CMS\Install\CheckTheDatabaseHookInterface) { throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Install\\CheckTheDatabaseHookInterface', 1315554770); } $hookObjects[] = $hookObject; } } if (!strcmp($actionParts[1], 'CURRENT_TABLES')) { $tblFileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl(PATH_t3lib . 'stddb/tables.sql'); foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extKey => $loadedExtConf) { if (is_array($loadedExtConf) && $loadedExtConf['ext_tables.sql']) { $extensionSqlContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($loadedExtConf['ext_tables.sql']); $tblFileContent .= LF . LF . LF . LF . $extensionSqlContent; foreach ($hookObjects as $hookObject) { /** @var $hookObject Tx_Install_Interfaces_CheckTheDatabaseHook * */ $appendableTableDefinitions = $hookObject->appendExtensionTableDefinitions($extKey, $loadedExtConf, $extensionSqlContent, $this->sqlHandler, $this); if ($appendableTableDefinitions) { $tblFileContent .= $appendableTableDefinitions; break; } } } } } elseif (@is_file($actionParts[1])) { $tblFileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($actionParts[1]); } foreach ($hookObjects as $hookObject) { /** @var $hookObject Tx_Install_Interfaces_CheckTheDatabaseHook * */ $appendableTableDefinitions = $hookObject->appendGlobalTableDefinitions($tblFileContent, $this->sqlHandler, $this); if ($appendableTableDefinitions) { $tblFileContent .= $appendableTableDefinitions; break; } } // Add SQL content coming from the caching framework $tblFileContent .= \TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions(); // Add SQL content coming from the category registry $tblFileContent .= \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->getDatabaseTableDefinitions(); if ($tblFileContent) { $fileContent = implode(LF, $this->sqlHandler->getStatementArray($tblFileContent, 1, '^CREATE TABLE ')); $FDfile = $this->sqlHandler->getFieldDefinitions_fileContent($fileContent); if (!count($FDfile)) { die('Error: There were no \'CREATE TABLE\' definitions in the provided file'); } // Updating database... if (is_array($this->INSTALL['database_update'])) { $FDdb = $this->sqlHandler->getFieldDefinitions_database(); $diff = $this->sqlHandler->getDatabaseExtra($FDfile, $FDdb); $update_statements = $this->sqlHandler->getUpdateSuggestions($diff); $diff = $this->sqlHandler->getDatabaseExtra($FDdb, $FDfile); $remove_statements = $this->sqlHandler->getUpdateSuggestions($diff, 'remove'); $results = array(); $results[] = $this->sqlHandler->performUpdateQueries($update_statements['clear_table'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($update_statements['add'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($update_statements['change'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($remove_statements['change'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($remove_statements['drop'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($update_statements['create_table'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($remove_statements['change_table'], $this->INSTALL['database_update']); $results[] = $this->sqlHandler->performUpdateQueries($remove_statements['drop_table'], $this->INSTALL['database_update']); $this->databaseUpdateErrorMessages = array(); foreach ($results as $resultSet) { if (is_array($resultSet)) { foreach ($resultSet as $key => $errorMessage) { $this->databaseUpdateErrorMessages[$key] = $errorMessage; } } } } // Init again / first time depending... $FDdb = $this->sqlHandler->getFieldDefinitions_database(); $diff = $this->sqlHandler->getDatabaseExtra($FDfile, $FDdb); $update_statements = $this->sqlHandler->getUpdateSuggestions($diff); $diff = $this->sqlHandler->getDatabaseExtra($FDdb, $FDfile); $remove_statements = $this->sqlHandler->getUpdateSuggestions($diff, 'remove'); $tLabel = 'Update database tables and fields'; if ($remove_statements || $update_statements) { $formContent = $this->generateUpdateDatabaseForm('get_form', $update_statements, $remove_statements, $action_type); $this->message($tLabel, 'Table and field definitions should be updated', ' <p> There seems to be a number of differences between the database and the selected SQL-file. <br /> Please select which statements you want to execute in order to update your database: </p> ' . $formContent, 2); } else { $formContent = $this->generateUpdateDatabaseForm('get_form', $update_statements, $remove_statements, $action_type); $this->message($tLabel, 'Table and field definitions are OK.', ' <p> The tables and fields in the current database corresponds perfectly to the database in the selected SQL-file. </p> ', -1); } } break; case 'cmpTCA': $this->includeTCA(); $FDdb = $this->sqlHandler->getFieldDefinitions_database(); // Displaying configured fields which are not in the database $tLabel = 'Tables and fields in $TCA, but not in database'; $cmpTCA_DB = $this->compareTCAandDatabase($GLOBALS['TCA'], $FDdb); if (!count($cmpTCA_DB['extra'])) { $this->message($tLabel, 'Table and field definitions OK', ' <p> All fields and tables configured in $TCA appeared to exist in the database as well </p> ', -1); } else { $this->message($tLabel, 'Invalid table and field definitions in $TCA!', ' <p> There are some tables and/or fields configured in the $TCA array which do not exist in the database! <br /> This will most likely cause you trouble with the TYPO3 backend interface! </p> ', 3); foreach ($cmpTCA_DB['extra'] as $tableName => $conf) { $this->message($tLabel, $tableName, $this->displayFields($conf['fields'], 0, 'Suggested database field:'), 2); } } // Displaying tables that are not setup in $cmpDB_TCA = $this->compareDatabaseAndTCA($FDdb, $GLOBALS['TCA']); $excludeTables = 'be_sessions,fe_session_data,fe_sessions'; if (TYPO3_OS == 'WIN') { $excludeTables = strtolower($excludeTables); } $excludeFields = array('be_users' => 'uc,lastlogin,usergroup_cached_list', 'fe_users' => 'uc,lastlogin,fe_cruser_id', 'pages' => 'SYS_LASTCHANGED', 'sys_dmail' => 'mailContent', 'tt_board' => 'doublePostCheck', 'tt_guest' => 'doublePostCheck', 'tt_products' => 'ordered'); $tCount = 0; $fCount = 0; $tLabel = 'Tables from database, but not in \\$TCA'; $fLabel = 'Fields from database, but not in \\$TCA'; $this->message($tLabel); if (is_array($cmpDB_TCA['extra'])) { foreach ($cmpDB_TCA['extra'] as $tableName => $conf) { if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($excludeTables, $tableName) && substr($tableName, 0, 4) != 'sys_' && substr($tableName, -3) != '_mm' && substr($tableName, 0, 6) != 'index_' && substr($tableName, 0, 6) != 'cache_') { if ($conf['whole_table']) { $this->message($tLabel, $tableName, $this->displayFields($conf['fields']), 1); $tCount++; } else { list($theContent, $fC) = $this->displaySuggestions($conf['fields'], $excludeFields[$tableName]); $fCount += $fC; if ($fC) { $this->message($fLabel, $tableName, $theContent, 1); } } } } } if (!$tCount) { $this->message($tLabel, 'Correct number of tables in the database', ' <p> There are no extra tables in the database compared to the configured tables in the $TCA array. </p> ', -1); } else { $this->message($tLabel, 'Extra tables in the database', ' <p> There are some tables in the database which are not configured in the $TCA array. <br /> You should probably not worry about this, but please make sure that you know what these tables are about and why they are not configured in $TCA. </p> ', 2); } if (!$fCount) { $this->message($fLabel, 'Correct number of fields in the database', ' <p> There are no additional fields in the database tables compared to the configured fields in the $TCA array. </p> ', -1); } else { $this->message($fLabel, 'Extra fields in the database', ' <p> There are some additional fields the database tables which are not configured in the $TCA array. <br /> You should probably not worry about this, but please make sure that you know what these fields are about and why they are not configured in $TCA. </p> ', 2); } // Displaying actual and suggested field database defitions if (is_array($cmpTCA_DB['matching'])) { $tLabel = 'Comparison between database and $TCA'; $this->message($tLabel, 'Actual and suggested field definitions', ' <p> This table shows you the suggested field definitions which are calculated based on the configuration in $TCA. <br /> If the suggested value differs from the actual current database value, you should not panic, but simply check if the datatype of that field is sufficient compared to the data, you want TYPO3 to put there. </p> ', 0); foreach ($cmpTCA_DB['matching'] as $tableName => $conf) { $this->message($tLabel, $tableName, $this->displayFieldComp($conf['fields'], $FDdb[$tableName]['fields']), 1); } } break; case 'import': $mode123Imported = 0; $tblFileContent = ''; if (preg_match('/^CURRENT_/', $actionParts[1])) { if (!strcmp($actionParts[1], 'CURRENT_TABLES') || !strcmp($actionParts[1], 'CURRENT_TABLES+STATIC')) { $tblFileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl(PATH_t3lib . 'stddb/tables.sql'); foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $loadedExtConf) { if (is_array($loadedExtConf) && $loadedExtConf['ext_tables.sql']) { $tblFileContent .= LF . LF . LF . LF . \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($loadedExtConf['ext_tables.sql']); } } } if (!strcmp($actionParts[1], 'CURRENT_STATIC') || !strcmp($actionParts[1], 'CURRENT_TABLES+STATIC')) { foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $loadedExtConf) { if (is_array($loadedExtConf) && $loadedExtConf['ext_tables_static+adt.sql']) { $tblFileContent .= LF . LF . LF . LF . \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($loadedExtConf['ext_tables_static+adt.sql']); } } } $tblFileContent .= LF . LF . LF . LF . \TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions(); } elseif (@is_file($actionParts[1])) { $tblFileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($actionParts[1]); } if ($tblFileContent) { $tLabel = 'Import SQL dump'; // Getting statement array from $statements = $this->sqlHandler->getStatementArray($tblFileContent, 1); list($statements_table, $insertCount) = $this->sqlHandler->getCreateTables($statements, 1); // Updating database... if ($this->INSTALL['database_import_all']) { $r = 0; foreach ($statements as $k => $v) { $res = $GLOBALS['TYPO3_DB']->admin_query($v); $r++; } // Make a database comparison because some tables that are defined twice have // not been created at this point. This applies to the "pages.*" // fields defined in sysext/cms/ext_tables.sql for example. $fileContent = implode(LF, $this->sqlHandler->getStatementArray($tblFileContent, 1, '^CREATE TABLE ')); $FDfile = $this->sqlHandler->getFieldDefinitions_fileContent($fileContent); $FDdb = $this->sqlHandler->getFieldDefinitions_database(); $diff = $this->sqlHandler->getDatabaseExtra($FDfile, $FDdb); $update_statements = $this->sqlHandler->getUpdateSuggestions($diff); if (is_array($update_statements['add'])) { foreach ($update_statements['add'] as $statement) { $res = $GLOBALS['TYPO3_DB']->admin_query($statement); } } if ($this->mode == '123') { // Create default be_user admin/password $username = '******'; $pass = '******'; $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', 'be_users', 'username='******'TYPO3_DB']->fullQuoteStr($username, 'be_users')); if (!$count) { $insertFields = array('username' => $username, 'password' => md5($pass), 'admin' => 1, 'uc' => '', 'fileoper_perms' => 0, 'tstamp' => $GLOBALS['EXEC_TIME'], 'crdate' => $GLOBALS['EXEC_TIME']); $GLOBALS['TYPO3_DB']->exec_INSERTquery('be_users', $insertFields); } } $this->message($tLabel, 'Imported ALL', ' <p> Queries: ' . $r . ' </p> ', 1, 1); if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('goto_step')) { $this->action .= '&step=' . \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('goto_step'); \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->action); } } elseif (is_array($this->INSTALL['database_import'])) { // Traverse the tables foreach ($this->INSTALL['database_import'] as $table => $md5str) { if ($md5str == md5($statements_table[$table])) { $res = $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table); $res = $GLOBALS['TYPO3_DB']->admin_query($statements_table[$table]); if ($insertCount[$table]) { $statements_insert = $this->sqlHandler->getTableInsertStatements($statements, $table); foreach ($statements_insert as $k => $v) { $res = $GLOBALS['TYPO3_DB']->admin_query($v); } } $this->message($tLabel, 'Imported \'' . $table . '\'', ' <p> Rows: ' . $insertCount[$table] . ' </p> ', 1, 1); } } } $mode123Imported = $this->isBasicComplete($tLabel); if (!$mode123Imported) { // Re-Getting current tables - may have been changed during import $whichTables = $this->sqlHandler->getListOfTables(); if (count($statements_table)) { reset($statements_table); $out = ''; // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseImport.html'); // Get the template part from the file $content = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###IMPORT###'); if ($this->mode != '123') { $tables = array(); // Get the subpart for regular mode $regularModeSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($content, '###REGULARMODE###'); foreach ($statements_table as $table => $definition) { // Get the subpart for rows $tableSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($content, '###ROWS###'); // Fill the 'table exists' part when it exists $exist = isset($whichTables[$table]); if ($exist) { // Get the subpart for table exists $existSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($tableSubpart, '###EXIST###'); // Define the markers content $existMarkers = array('tableExists' => 'Table exists!', 'backPath' => $this->backPath); // Fill the markers in the subpart $existSubpart = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($existSubpart, $existMarkers, '###|###', TRUE, FALSE); } // Substitute the subpart for table exists $tableHtml = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($tableSubpart, '###EXIST###', $existSubpart); // Define the markers content $tableMarkers = array('table' => $table, 'definition' => md5($definition), 'count' => $insertCount[$table] ? $insertCount[$table] : '', 'rowLabel' => $insertCount[$table] ? 'Rows: ' : '', 'tableExists' => 'Table exists!', 'backPath' => $this->backPath); // Fill the markers $tables[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($tableHtml, $tableMarkers, '###|###', TRUE, FALSE); } // Substitute the subpart for the rows $regularModeSubpart = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($regularModeSubpart, '###ROWS###', implode(LF, $tables)); } // Substitute the subpart for the regular mode $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($content, '###REGULARMODE###', $regularModeSubpart); // Define the markers content $contentMarkers = array('checked' => $this->mode == '123' || \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('presetWholeTable') ? 'checked="checked"' : '', 'label' => 'Import the whole file \'' . basename($actionParts[1]) . '\' directly (ignores selections above)'); // Fill the markers $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $contentMarkers, '###|###', TRUE, FALSE); $form = $this->getUpdateDbFormWrap($action_type, $content); $this->message($tLabel, 'Select tables to import', ' <p> This is an overview of the CREATE TABLE definitions in the SQL file. <br /> Select which tables you want to dump to the database. <br /> Any table you choose dump to the database is dropped from the database first, so you\'ll lose all data in existing tables. </p> ' . $form, 1, 1); } else { $this->message($tLabel, 'No tables', ' <p> There seems to be no CREATE TABLE definitions in the SQL file. <br /> This tool is intelligently creating one table at a time and not just dumping the whole content of the file uncritically. That\'s why there must be defined tables in the SQL file. </p> ', 3, 1); } } } break; case 'view': if (@is_file($actionParts[1])) { $tLabel = 'Import SQL dump'; // Getting statement array from $fileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($actionParts[1]); $statements = $this->sqlHandler->getStatementArray($fileContent, 1); $maxL = 1000; $strLen = strlen($fileContent); $maxlen = 200 + ($maxL - \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(($strLen - 20000) / 100, 0, $maxL)); if (count($statements)) { $out = ''; foreach ($statements as $statement) { $out .= '<p>' . nl2br(htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($statement, $maxlen))) . '</p>'; } } $this->message($tLabel, 'Content of ' . basename($actionParts[1]), $out, 1); } break; case 'adminUser': if ($whichTables['be_users']) { if (is_array($this->INSTALL['database_adminUser'])) { $username = preg_replace('/[^\\da-z._-]/i', '', trim($this->INSTALL['database_adminUser']['username'])); $pass = trim($this->INSTALL['database_adminUser']['password']); $pass2 = trim($this->INSTALL['database_adminUser']['password2']); if ($username && $pass && $pass2) { if ($pass != $pass2) { $this->message($headCode, 'Passwords are not equal!', ' <p> The passwords entered twice are not equal. </p> ', 2, 1); } else { $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'be_users', 'username='******'TYPO3_DB']->fullQuoteStr($username, 'be_users')); if (!$GLOBALS['TYPO3_DB']->sql_num_rows($res)) { $insertFields = array('username' => $username, 'password' => md5($pass), 'admin' => 1, 'uc' => '', 'fileoper_perms' => 0, 'tstamp' => $GLOBALS['EXEC_TIME'], 'crdate' => $GLOBALS['EXEC_TIME']); $result = $GLOBALS['TYPO3_DB']->exec_INSERTquery('be_users', $insertFields); $this->isBasicComplete($headCode); if ($result) { $this->message($headCode, 'User created', ' <p> Username: <strong>' . htmlspecialchars($username) . ' </strong> </p> ', 1, 1); } else { $this->message($headCode, 'User not created', ' <p> Error: <strong>' . htmlspecialchars($GLOBALS['TYPO3_DB']->sql_error()) . ' </strong> </p> ', 3, 1); } } else { $this->message($headCode, 'Username not unique!', ' <p> The username, <strong>' . htmlspecialchars($username) . ' </strong> , was not unique. </p> ', 2, 1); } } } else { $this->message($headCode, 'Missing data!', ' <p> Not all required form fields have been filled. </p> ', 2, 1); } } // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseAdminUser.html'); // Get the template part from the file $content = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###TEMPLATE###'); // Define the markers content $contentMarkers = array('userName' => 'username - unique, no space, lowercase', 'password' => 'password', 'repeatPassword' => 'password (repeated)'); // Fill the markers $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $contentMarkers, '###|###', TRUE, FALSE); $form = $this->getUpdateDbFormWrap($action_type, $content); $this->message($headCode, 'Create admin user', ' <p> Enter username and password for a new admin user. <br /> You should use this function only if there are no admin users in the database, for instance if this is a blank database. <br /> After you\'ve created the user, log in and add the rest of the user information, like email and real name. </p> ' . $form, 0, 1); } else { $this->message($headCode, 'Required table not in database', ' <p> \'be_users\' must be a table in the database! </p> ', 3, 1); } break; case 'UC': if ($whichTables['be_users']) { if (!strcmp($this->INSTALL['database_UC'], 1)) { $GLOBALS['TYPO3_DB']->exec_UPDATEquery('be_users', '', array('uc' => '')); $this->message($headCode, 'Clearing be_users.uc', ' <p> Done. </p> ', 1); } // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseUc.html'); // Get the template part from the file $content = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###TEMPLATE###'); // Define the markers content $contentMarkers = array('clearBeUsers' => 'Clear be_users preferences ("uc" field)'); // Fill the markers $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $contentMarkers, '###|###', TRUE, FALSE); $form = $this->getUpdateDbFormWrap($action_type, $content); $this->message($headCode, 'Clear user preferences', ' <p> If you press this button all backend users from the tables be_users will have their user preferences cleared (field \'uc\' set to an empty string). <br /> This may come in handy in rare cases where that configuration may be corrupt. <br /> Clearing this will clear all user settings from the \'Setup\' module. </p> ' . $form); } else { $this->message($headCode, 'Required table not in database', ' <p> \'be_users\' must be a table in the database! </p> ', 3); } break; case 'cache': $tableListArr = explode(',', 'cache_pages,cache_pagesection,cache_hash,cache_imagesizes,--div--,sys_log,sys_history,--div--,be_sessions,fe_sessions,fe_session_data' . (\TYPO3\CMS\Core\Extension\ExtensionManager::isLoaded('indexed_search') ? ',--div--,index_words,index_rel,index_phash,index_grlist,index_section,index_fulltext' : '') . (\TYPO3\CMS\Core\Extension\ExtensionManager::isLoaded('tt_products') ? ',--div--,sys_products_orders,sys_products_orders_mm_tt_products' : '') . (\TYPO3\CMS\Core\Extension\ExtensionManager::isLoaded('direct_mail') ? ',--div--,sys_dmail_maillog' : '')); if (is_array($this->INSTALL['database_clearcache'])) { $qList = array(); // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseCache.html'); // Get the subpart for emptied tables $emptiedTablesSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###EMPTIEDTABLES###'); // Get the subpart for table $tableSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($emptiedTablesSubpart, '###TABLE###'); foreach ($tableListArr as $table) { if ($table != '--div--') { $table_c = TYPO3_OS == 'WIN' ? strtolower($table) : $table; if ($this->INSTALL['database_clearcache'][$table] && $whichTables[$table_c]) { $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery($table); // Define the markers content $emptiedTablesMarkers = array('tableName' => $table); // Fill the markers in the subpart $qList[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($tableSubpart, $emptiedTablesMarkers, '###|###', TRUE, FALSE); } } } // Substitute the subpart for table $emptiedTablesSubpart = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($emptiedTablesSubpart, '###TABLE###', implode(LF, $qList)); if (count($qList)) { $this->message($headCode, 'Clearing cache', ' <p> The following tables were emptied: </p> ' . $emptiedTablesSubpart, 1); } } // Count entries and make checkboxes $labelArr = array('cache_pages' => 'Pages', 'cache_pagesection' => 'TS template related information', 'cache_hash' => 'Multipurpose md5-hash cache', 'cache_imagesizes' => 'Cached image sizes', 'sys_log' => 'Backend action logging', 'sys_history' => 'Addendum to the sys_log which tracks ALL changes to content through TCE. May become huge by time. Is used for rollback (undo) and the WorkFlow engine.', 'be_sessions' => 'Backend User sessions', 'fe_sessions' => 'Frontend User sessions', 'fe_session_data' => 'Frontend User sessions data', 'sys_dmail_maillog' => 'Direct Mail log', 'sys_products_orders' => 'tt_product orders', 'sys_products_orders_mm_tt_products' => 'relations between tt_products and sys_products_orders'); $countEntries = array(); reset($tableListArr); // Get the template file $templateFile = @file_get_contents(PATH_site . $this->templateFilePath . 'CheckTheDatabaseCache.html'); // Get the subpart for table list $tableListSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###TABLELIST###'); // Get the subpart for the group separator $groupSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($tableListSubpart, '###GROUP###'); // Get the subpart for a single table $singleTableSubpart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($tableListSubpart, '###SINGLETABLE###'); $checkBoxes = array(); foreach ($tableListArr as $table) { if ($table != '--div--') { $table_c = TYPO3_OS == 'WIN' ? strtolower($table) : $table; if ($whichTables[$table_c]) { $countEntries[$table] = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $table); // Checkboxes: if ($this->INSTALL['database_clearcache'][$table] || $_GET['PRESET']['database_clearcache'][$table]) { $checked = 'checked="checked"'; } else { $checked = ''; } // Define the markers content $singleTableMarkers = array('table' => $table, 'checked' => $checked, 'count' => '(' . $countEntries[$table] . ' rows)', 'label' => $labelArr[$table]); // Fill the markers in the subpart $checkBoxes[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($singleTableSubpart, $singleTableMarkers, '###|###', TRUE, FALSE); } } else { $checkBoxes[] = $groupSubpart; } } // Substitute the subpart for the single tables $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($tableListSubpart, '###SINGLETABLE###', implode(LF, $checkBoxes)); // Substitute the subpart for the group separator $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($content, '###GROUP###', ''); $form = $this->getUpdateDbFormWrap($action_type, $content); $this->message($headCode, 'Clear out selected tables', ' <p> Pressing this button will delete all records from the selected tables. </p> ' . $form); break; } } $this->output($this->outputWrapper($this->printAll())); }
<?php /** * General ext_tables file and also an example for your own extension * * @category Extension * @package Calendarize * @author Tim Lochmüller */ if (!defined('TYPO3_MODE')) { die('Access denied.'); } \HDNET\Autoloader\Loader::extTables('HDNET', 'calendarize', \HDNET\Calendarize\Register::getDefaultAutoloader()); if (!(bool) \HDNET\Calendarize\Utility\ConfigurationUtility::get('disableDefaultEvent')) { \HDNET\Calendarize\Register::extTables(\HDNET\Calendarize\Register::getDefaultCalendarizeConfiguration()); \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->add('calendarize', 'tx_calendarize_domain_model_event'); } \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin('calendarize', 'Calendar', \HDNET\Calendarize\Utility\TranslateUtility::get('pluginName')); if (\TYPO3\CMS\Core\Utility\GeneralUtility::compat_version('7.0.0')) { $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['calendarize_calendar'] .= ',categories'; } // module icon $extensionIcon = \HDNET\Autoloader\Utility\IconUtility::getByExtensionKey('calendarize', true); if (\TYPO3\CMS\Core\Utility\GeneralUtility::compat_version('7.0')) { /** @var \TYPO3\CMS\Core\Imaging\IconRegistry $iconRegistry */ $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Imaging\\IconRegistry'); $iconRegistry->registerIcon('apps-pagetree-folder-contains-calendarize', 'TYPO3\\CMS\\Core\\Imaging\\IconProvider\\BitmapIconProvider', ['source' => $extensionIcon]); } else { $extensionRelPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('calendarize'); \TYPO3\CMS\Backend\Sprite\SpriteManager::addTcaTypeIcon('pages', 'contains-calendar', str_replace('EXT:calendarize/', $extensionRelPath, $extensionIcon)); }
/** * Makes a table categorizable by extending its TCA. * * @param string $extensionKey Extension key to be used * @param string $tableName Name of the table to be categoriezed * @param string $fieldName Name of the field to be used to store categories * @param array $options Additional configuration options * @see addTCAcolumns * @see addToAllTCAtypes */ public static function makeCategorizable($extensionKey, $tableName, $fieldName = 'categories', array $options = array()) { // Load TCA first \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($tableName); // Update the category registry $result = \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->add($extensionKey, $tableName, $fieldName); if ($result === FALSE) { $message = 't3lib_categoryRegistry: no category registered for table "%s". Double check if there is a TCA configured'; \TYPO3\CMS\Core\Utility\GeneralUtility::devLog(sprintf($message, $tableName), 'Core', 2); } // Makes sure to add more TCA to an existing structure if (isset($GLOBALS['TCA'][$tableName]['columns'])) { // Forges a new field, default name is "categories" $fieldConfiguration = array('type' => 'select', 'foreign_table' => 'sys_category', 'foreign_table_where' => ' ORDER BY sys_category.title ASC', 'MM' => 'sys_category_record_mm', 'MM_opposite_field' => 'items', 'MM_match_fields' => array('tablenames' => $tableName), 'size' => 10, 'autoSizeMax' => 50, 'maxitems' => 9999, 'renderMode' => 'tree', 'treeConfig' => array('parentField' => 'parent', 'appearance' => array('expandAll' => TRUE, 'showHeader' => TRUE)), 'wizards' => array('_PADDING' => 1, '_VERTICAL' => 1, 'edit' => array('type' => 'popup', 'title' => 'Edit', 'script' => 'wizard_edit.php', 'icon' => 'edit2.gif', 'popup_onlyOpenIfSelected' => 1, 'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1'), 'add' => array('type' => 'script', 'title' => 'Create new', 'icon' => 'add.gif', 'params' => array('table' => 'sys_category', 'pid' => '###CURRENT_PID###', 'setValue' => 'prepend'), 'script' => 'wizard_add.php'))); if (!empty($options['fieldConfiguration'])) { $fieldConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($fieldConfiguration, $options['fieldConfiguration']); } $columns = array($fieldName => array('exclude' => 0, 'label' => 'LLL:EXT:lang/locallang_tca.xlf:sys_category.categories', 'config' => $fieldConfiguration)); // Adding fields to an existing table definition self::addTCAcolumns($tableName, $columns); $fieldList = '--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category, ' . $fieldName; if (!empty($options['fieldList'])) { $fieldList = $options['fieldList']; } $typesList = ''; if (!empty($options['typesList'])) { $typesList = $options['typesList']; } $position = ''; if (!empty($options['position'])) { $position = $options['position']; } // Makes the new "categories" field to be visible in TSFE. self::addToAllTCAtypes($tableName, $fieldList, $typesList, $position); } }
/** * @test */ public function loadBaseTcaRequiresCacheFileIfExistsAndCachingIsAllowed() { $mockCache = $this->getMock(AbstractFrontend::class, array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', false); /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */ $mockCacheManager = $this->getMock(CacheManager::class, array('getCache')); $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache)); ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager); $mockCache->expects($this->any())->method('has')->will($this->returnValue(true)); $mockCache->expects($this->once())->method('get')->willReturn('<?php ' . serialize(array('tca' => array(), 'categoryRegistry' => CategoryRegistry::getInstance())) . '?>'); ExtensionManagementUtilityAccessibleProxy::loadBaseTca(true); }
/** * @test */ public function loadBaseTcaRequiresCacheFileIfExistsAndCachingIsAllowed() { $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE); $mockCacheManager = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache')); $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache)); ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager); $mockCache->expects($this->any())->method('has')->will($this->returnValue(TRUE)); $mockCache->expects($this->once())->method('get')->willReturn('<?php ' . serialize(array('tca' => array(), 'categoryRegistry' => \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance())) . '?>'); ExtensionManagementUtilityAccessibleProxy::loadBaseTca(TRUE); }
/** * Get the update statement of the database * * @return array */ public static function getSqlUpdateStatements() { $tblFileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl(PATH_typo3 . 'sysext/core/ext_tables.sql'); foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $loadedExtConf) { if (is_array($loadedExtConf) && $loadedExtConf['ext_tables.sql']) { $tblFileContent .= chr(10) . chr(10) . chr(10) . chr(10) . \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($loadedExtConf['ext_tables.sql']); } } if (class_exists('\\TYPO3\\CMS\\Core\\Category\\CategoryRegistry') && version_compare(TYPO3_version, '7.6.0', '>=')) { $tblFileContent .= \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->getDatabaseTableDefinitions(); $tableDefinitions = \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->addCategoryDatabaseSchemaToTablesDefinition(array()); $tblFileContent .= $tableDefinitions['sqlString ']; $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); $cachingFrameworkDatabaseSchemaService = $objectManager->get('TYPO3\\CMS\\Core\\Cache\\DatabaseSchemaService'); $tableDefinitionsCache = $cachingFrameworkDatabaseSchemaService->addCachingFrameworkRequiredDatabaseSchemaForSqlExpectedSchemaService(array()); $tblFileContent .= implode(LF, $tableDefinitionsCache[0]); } else { $tblFileContent .= \TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions(); } $installClass = self::getInstallSqlClass(); $instObj = new $installClass(); $fdDb = self::getDatabaseSchema(); if ($tblFileContent) { $fileContent = implode(chr(10), $instObj->getStatementArray($tblFileContent, 1, '^CREATE TABLE ')); // just support for old version if (method_exists($installClass, 'getFieldDefinitions_fileContent') === true) { $fdFile = $instObj->getFieldDefinitions_fileContent($fileContent); } else { $fdFile = $instObj->getFieldDefinitions_sqlContent($fileContent); } $diff = $instObj->getDatabaseExtra($fdFile, $fdDb); $updateStatements = $instObj->getUpdateSuggestions($diff); $diff = $instObj->getDatabaseExtra($fdDb, $fdFile); $removeStatements = $instObj->getUpdateSuggestions($diff, 'remove'); return array('update' => $updateStatements, 'remove' => $removeStatements); } else { return array('update' => null, 'remove' => null); } }