From f0eb20605166b5550b6d0aa1dfd3e3409d6841c8 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Mon, 23 Mar 2020 11:22:06 +0100 Subject: [PATCH] [TASK] Remove unused code related to internal_type=file The internal_type=file was removed in TYPO3 v10, but the Backend Module "DB Check" (lowlevel) still contained lots of parts that are not relevant anymore. This patch cleans up the corresponding parts and simplifies various other places due to the lack of checks of internal_type=file. Resolves: #90816 Releases: master Change-Id: I742fc1ea197837c477415368a674ad8831e10f31 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63872 Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Susanne Moog <look@susi.dev> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Susanne Moog <look@susi.dev> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> --- .../DatabaseIntegrityController.php | 23 +- .../Integrity/DatabaseIntegrityCheck.php | 296 ++++++------------ .../Resources/Private/Language/locallang.xlf | 18 -- .../Private/Templates/Backend/Relations.html | 40 --- 4 files changed, 106 insertions(+), 271 deletions(-) diff --git a/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php b/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php index 458a30409e82..c4a4ba8d5e6b 100644 --- a/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php +++ b/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php @@ -16,6 +16,7 @@ namespace TYPO3\CMS\Lowlevel\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Template\Components\ButtonBar; use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Utility\BackendUtility; @@ -74,16 +75,6 @@ class DatabaseIntegrityController */ protected $moduleTemplate; - /** - * Loaded with the global array $MCONF which holds some module configuration from the conf.php file of backend modules. - * - * @see init() - * @var array - */ - protected $MCONF = [ - 'name' => 'system_dbint', - ]; - /** * The module menu items array. Each key represents a key for which values can range between the items in the array of that key. * @@ -254,8 +245,7 @@ class DatabaseIntegrityController { $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu(); $menu->setIdentifier('DatabaseJumpMenu'); - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); foreach ($this->MOD_MENU['function'] as $controller => $title) { $item = $menu ->makeMenuItem() @@ -286,8 +276,7 @@ class DatabaseIntegrityController { $modules = []; $availableModFuncs = ['records', 'relations', 'search', 'refindex']; - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); foreach ($availableModFuncs as $modFunc) { $modules[$modFunc] = (string)$uriBuilder->buildUriFromRoute('system_dbint') . '&SET[function]=' . $modFunc; } @@ -439,8 +428,7 @@ class DatabaseIntegrityController $theNumberOfRe = ''; } $lr = ''; - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); if (is_array($admin->getLRecords()[$t])) { foreach ($admin->getLRecords()[$t] as $data) { if (!GeneralUtility::inList($admin->getLostPagesList(), $data['pid'])) { @@ -472,8 +460,7 @@ class DatabaseIntegrityController protected function func_relations() { $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class); - $fkey_arrays = $admin->getGroupFields(''); - $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays); + $admin->selectNonEmptyRecordsWithFkeys(); $this->view->assignMultiple([ 'select_db' => $admin->testDBRefs($admin->getCheckSelectDBRefs()), diff --git a/typo3/sysext/lowlevel/Classes/Integrity/DatabaseIntegrityCheck.php b/typo3/sysext/lowlevel/Classes/Integrity/DatabaseIntegrityCheck.php index c42d6c60fca7..f1d6fea62548 100644 --- a/typo3/sysext/lowlevel/Classes/Integrity/DatabaseIntegrityCheck.php +++ b/typo3/sysext/lowlevel/Classes/Integrity/DatabaseIntegrityCheck.php @@ -68,11 +68,6 @@ class DatabaseIntegrityCheck */ protected $recIdArray = []; - /** - * @var array - */ - protected $checkFileRefs = []; - /** * @var array From the select-fields */ @@ -115,10 +110,9 @@ class DatabaseIntegrityCheck * This list should ideally include all records in the pages-table. * * @param int $theID a pid (page-record id) from which to start making the tree - * @param string $depthData HTML-code (image-tags) used when this function calls itself recursively. * @param bool $versions Internal variable, don't set from outside! */ - public function genTree($theID, $depthData = '', $versions = false) + public function genTree($theID, $versions = false) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions()->removeAll(); @@ -166,7 +160,7 @@ class DatabaseIntegrityCheck if ($this->genTreeIncludeRecords) { foreach ($GLOBALS['TCA'] as $tableName => $cfg) { if ($tableName !== 'pages') { - $this->genTree_records($newID, '', $tableName); + $this->genTree_records($newID, $tableName); } } } @@ -174,18 +168,17 @@ class DatabaseIntegrityCheck $this->genTree($newID); // If versions are included in the tree, add those now: if ($this->genTreeIncludeVersions) { - $this->genTree($newID, '', true); + $this->genTree($newID, true); } } } /** * @param int $theID a pid (page-record id) from which to start making the tree - * @param string $_ Unused parameter * @param string $table Table to get the records from * @param bool $versions Internal variable, don't set from outside! */ - public function genTree_records($theID, $_ = '', $table = '', $versions = false): void + public function genTree_records($theID, $table, $versions = false): void { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions()->removeAll(); @@ -221,7 +214,7 @@ class DatabaseIntegrityCheck } // Select all versions of this record: if ($this->genTreeIncludeVersions && BackendUtility::isTableWorkspaceEnabled($table)) { - $this->genTree_records($newID, '', $table, true); + $this->genTree_records($newID, $table, true); } } } @@ -359,165 +352,127 @@ class DatabaseIntegrityCheck } /** - * Finding relations in database based on type 'group' (files or database-uid's in a list) + * Finding relations in database based on type 'group' (database-uid's in a list) * - * @param string $mode $mode = file, $mode = db, $mode = '' (all...) - * @return array An array with all fields listed that somehow are references to other records (foreign-keys) or files + * @return array An array with all fields listed that somehow are references to other records (foreign-keys) */ - public function getGroupFields($mode): array + public function getGroupFields(): array { $result = []; foreach ($GLOBALS['TCA'] as $table => $tableConf) { $cols = $GLOBALS['TCA'][$table]['columns']; foreach ($cols as $field => $config) { - if ($config['config']['type'] === 'group') { - if ((!$mode || $mode === 'db') && $config['config']['internal_type'] === 'db') { - $result[$table][] = $field; - } + if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'db') { + $result[$table][] = $field; } - if ((!$mode || $mode === 'db') && $config['config']['type'] === 'select' && $config['config']['foreign_table']) { + if ($config['config']['type'] === 'select' && $config['config']['foreign_table']) { $result[$table][] = $field; } } - if ($result[$table]) { - $result[$table] = implode(',', $result[$table]); - } } return $result; } /** - * Returns an array with arrays of table/field pairs which are allowed to hold references to the input table name - according to $GLOBALS['TCA'] + * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields() * - * @param string $theSearchTable Table name - * @return array + * @see getGroupFields() */ - public function getDBFields($theSearchTable): array + public function selectNonEmptyRecordsWithFkeys(): void { - $result = []; - foreach ($GLOBALS['TCA'] as $table => $tableConf) { - $cols = $GLOBALS['TCA'][$table]['columns']; - foreach ($cols as $field => $config) { - if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'db') { - if (trim($config['config']['allowed']) === '*' || strpos($config['config']['allowed'], $theSearchTable) !== false) { - $result[] = [$table, $field]; - } - } elseif ($config['config']['type'] === 'select' && $config['config']['foreign_table'] == $theSearchTable) { - $result[] = [$table, $field]; + $fkey_arrays = $this->getGroupFields(); + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + foreach ($fkey_arrays as $table => $fields) { + $connection = $connectionPool->getConnectionForTable($table); + $schemaManager = $connection->getSchemaManager(); + $tableColumns = $schemaManager->listTableColumns($table); + + $queryBuilder = $connectionPool->getQueryBuilderForTable($table); + $queryBuilder->getRestrictions()->removeAll(); + + $queryBuilder->select('uid') + ->from($table); + $whereClause = []; + + foreach ($fields as $fieldName) { + // The array index of $tableColumns is the lowercased column name! + // It is quoted for keywords + $column = $tableColumns[strtolower($fieldName)] + ?? $tableColumns[$connection->quoteIdentifier(strtolower($fieldName))]; + if (!$column) { + // Throw meaningful exception if field does not exist in DB - 'none' is not filtered here since the + // method is only called with type=group fields + throw new \RuntimeException( + 'Field ' . $fieldName . ' for table ' . $table . ' has been defined in TCA, but does not exist in DB', + 1536248937 + ); + } + $fieldType = $column->getType()->getName(); + if (in_array( + $fieldType, + [Types::BIGINT, Types::INTEGER, Types::SMALLINT, Types::DECIMAL, Types::FLOAT], + true + )) { + $whereClause[] = $queryBuilder->expr()->andX( + $queryBuilder->expr()->isNotNull($fieldName), + $queryBuilder->expr()->neq( + $fieldName, + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ); + } elseif (in_array($fieldType, [Types::STRING, Types::TEXT], true)) { + $whereClause[] = $queryBuilder->expr()->andX( + $queryBuilder->expr()->isNotNull($fieldName), + $queryBuilder->expr()->neq( + $fieldName, + $queryBuilder->createNamedParameter('', \PDO::PARAM_STR) + ) + ); + } elseif ($fieldType === Types::BLOB) { + $whereClause[] = $queryBuilder->expr()->andX( + $queryBuilder->expr()->isNotNull($fieldName), + $queryBuilder->expr() + ->comparison( + $queryBuilder->expr()->length($fieldName), + ExpressionBuilder::GT, + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ); } } - } - return $result; - } + $queryResult = $queryBuilder->orWhere(...$whereClause)->execute(); - /** - * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields() - * - * @param array $fkey_arrays Array with tables/fields generated by getGroupFields() - * @see getGroupFields() - */ - public function selectNonEmptyRecordsWithFkeys($fkey_arrays): void - { - if (is_array($fkey_arrays)) { - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - foreach ($fkey_arrays as $table => $field_list) { - if ($GLOBALS['TCA'][$table] && trim($field_list)) { - $connection = $connectionPool->getConnectionForTable($table); - $schemaManager = $connection->getSchemaManager(); - $tableColumns = $schemaManager->listTableColumns($table); - - $queryBuilder = $connectionPool->getQueryBuilderForTable($table); - $queryBuilder->getRestrictions()->removeAll(); - - $fields = GeneralUtility::trimExplode(',', $field_list, true); - - $queryBuilder->select('uid') - ->from($table); - $whereClause = []; - - foreach ($fields as $fieldName) { - // The array index of $tableColumns is the lowercased column name! - // It is quoted for keywords - $column = $tableColumns[strtolower($fieldName)] - ?? $tableColumns[$connection->quoteIdentifier(strtolower($fieldName))]; - if (!$column) { - // Throw meaningful exception if field does not exist in DB - 'none' is not filtered here since the - // method is only called with type=group fields - throw new \RuntimeException( - 'Field ' . $fieldName . ' for table ' . $table . ' has been defined in TCA, but does not exist in DB', - 1536248937 + while ($row = $queryResult->fetch()) { + foreach ($fields as $field) { + if (trim($row[$field])) { + $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; + if ($fieldConf['type'] === 'group' && $fieldConf['internal_type'] === 'db') { + $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class); + $dbAnalysis->start( + $row[$field], + $fieldConf['allowed'], + $fieldConf['MM'], + $row['uid'], + $table, + $fieldConf ); + foreach ($dbAnalysis->itemArray as $tempArr) { + $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1; + } } - $fieldType = $column->getType()->getName(); - if (in_array( - $fieldType, - [Types::BIGINT, Types::INTEGER, Types::SMALLINT, Types::DECIMAL, Types::FLOAT], - true - )) { - $whereClause[] = $queryBuilder->expr()->andX( - $queryBuilder->expr()->isNotNull($fieldName), - $queryBuilder->expr()->neq( - $fieldName, - $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) - ) - ); - } elseif (in_array($fieldType, [Types::STRING, Types::TEXT], true)) { - $whereClause[] = $queryBuilder->expr()->andX( - $queryBuilder->expr()->isNotNull($fieldName), - $queryBuilder->expr()->neq( - $fieldName, - $queryBuilder->createNamedParameter('', \PDO::PARAM_STR) - ) + if ($fieldConf['type'] === 'select' && $fieldConf['foreign_table']) { + $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class); + $dbAnalysis->start( + $row[$field], + $fieldConf['foreign_table'], + $fieldConf['MM'], + $row['uid'], + $table, + $fieldConf ); - } elseif ($fieldType === Types::BLOB) { - $whereClause[] = $queryBuilder->expr()->andX( - $queryBuilder->expr()->isNotNull($fieldName), - $queryBuilder->expr() - ->comparison( - $queryBuilder->expr()->length($fieldName), - ExpressionBuilder::GT, - $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) - ) - ); - } - } - $queryResult = $queryBuilder->orWhere(...$whereClause)->execute(); - - while ($row = $queryResult->fetch()) { - foreach ($fields as $field) { - if (trim($row[$field])) { - $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; - if ($fieldConf['type'] === 'group') { - if ($fieldConf['internal_type'] === 'db') { - $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class); - $dbAnalysis->start( - $row[$field], - $fieldConf['allowed'], - $fieldConf['MM'], - $row['uid'], - $table, - $fieldConf - ); - foreach ($dbAnalysis->itemArray as $tempArr) { - $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1; - } - } - } - if ($fieldConf['type'] === 'select' && $fieldConf['foreign_table']) { - $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class); - $dbAnalysis->start( - $row[$field], - $fieldConf['foreign_table'], - $fieldConf['MM'], - $row['uid'], - $table, - $fieldConf - ); - foreach ($dbAnalysis->itemArray as $tempArr) { - if ($tempArr['id'] > 0) { - $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1; - } - } + foreach ($dbAnalysis->itemArray as $tempArr) { + if ($tempArr['id'] > 0) { + $this->checkSelectDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1; } } } @@ -573,55 +528,6 @@ class DatabaseIntegrityCheck return $result; } - /** - * Finding all references to record based on table/uid - * - * @param string $searchTable Table name - * @param int $id Uid of database record - * @return array Array with other arrays containing information about where references was found - */ - public function whereIsRecordReferenced($searchTable, $id): array - { - // Gets tables / Fields that reference to files - $fileFields = $this->getDBFields($searchTable); - $theRecordList = []; - foreach ($fileFields as $info) { - [$table, $field] = $info; - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); - $queryBuilder->getRestrictions()->removeAll(); - $queryResult = $queryBuilder - ->select('uid', 'pid', $GLOBALS['TCA'][$table]['ctrl']['label'], $field) - ->from($table) - ->where( - $queryBuilder->expr()->like( - $field, - $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($id) . '%') - ) - ) - ->execute(); - - while ($row = $queryResult->fetch()) { - // Now this is the field, where the reference COULD come from. - // But we're not guaranteed, so we must carefully examine the data. - $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; - $allowedTables = $fieldConf['type'] === 'group' ? $fieldConf['allowed'] : $fieldConf['foreign_table']; - $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class); - $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf); - foreach ($dbAnalysis->itemArray as $tempArr) { - if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) { - $theRecordList[] = [ - 'table' => $table, - 'uid' => $row['uid'], - 'field' => $field, - 'pid' => $row['pid'] - ]; - } - } - } - } - return $theRecordList; - } - /** * @return array */ diff --git a/typo3/sysext/lowlevel/Resources/Private/Language/locallang.xlf b/typo3/sysext/lowlevel/Resources/Private/Language/locallang.xlf index 95161e63218d..5eeaf247519d 100644 --- a/typo3/sysext/lowlevel/Resources/Private/Language/locallang.xlf +++ b/typo3/sysext/lowlevel/Resources/Private/Language/locallang.xlf @@ -267,18 +267,6 @@ <trans-unit id="relations_description" resname="relations_description"> <source>This will analyze the content of the tables and check if there are 'empty' relations between records or if files are missing from their expected position.</source> </trans-unit> - <trans-unit id="files_many_ref" resname="files_many_ref"> - <source>Files referenced from more than one record</source> - </trans-unit> - <trans-unit id="no_files_found" resname="no_files_found"> - <source>No files found.</source> - </trans-unit> - <trans-unit id="files_no_ref" resname="files_no_ref"> - <source>Files with no references at all (delete them!)</source> - </trans-unit> - <trans-unit id="files_no_file" resname="files_no_file"> - <source>Missing files</source> - </trans-unit> <trans-unit id="select_db" resname="select_db"> <source>Select fields</source> </trans-unit> @@ -303,12 +291,6 @@ <trans-unit id="search_description" resname="search_description"> <source>This searches through all database tables and records for a text string.</source> </trans-unit> - <trans-unit id="filesearch" resname="filesearch"> - <source>Search all filenames for pattern</source> - </trans-unit> - <trans-unit id="filesearch_description" resname="filesearch_description"> - <source>Will search recursively for filenames inside sub directories of the public web folder (PublicPath) matching a certain regex pattern.</source> - </trans-unit> <trans-unit id="refindex" resname="refindex"> <source>Check and update global reference index</source> </trans-unit> diff --git a/typo3/sysext/lowlevel/Resources/Private/Templates/Backend/Relations.html b/typo3/sysext/lowlevel/Resources/Private/Templates/Backend/Relations.html index 619da61ae868..425601aa237a 100644 --- a/typo3/sysext/lowlevel/Resources/Private/Templates/Backend/Relations.html +++ b/typo3/sysext/lowlevel/Resources/Private/Templates/Backend/Relations.html @@ -1,45 +1,5 @@ <h1>{f:translate(key:'relations')}</h1> -<h2>{f:translate(key:'files_no_ref')}</h2> -<f:if condition="{files.noReferences}"> - <f:then> - <f:for each="{files.noReferences}" as="item"> - <span class="text-nowrap">{item.0}/<strong>{item.1}</strong></span> - <br> - </f:for> - </f:then> - <f:else> - <p>{f:translate(key:'no_files_found')}</p> - </f:else> -</f:if> - -<h2>{f:translate(key:'files_many_ref')}</h2> -<f:if condition="{files.moreReferences}"> - <f:then> - <f:for each="{files.moreReferences}" as="item"> - <span class="text-nowrap">{item.0}/<strong>{item.1}</strong>: {item.2} {f:translate(key:'references')}</span> - <br>{item.3}<br><br> - </f:for> - </f:then> - <f:else> - <p>{f:translate(key:'no_files_found')}</p> - </f:else> -</f:if> - -<h2>{f:translate(key:'files_no_file')}</h2> -<f:if condition="{files.noFile}"> - <f:then> - <f:for each="{files.noFile}" as="item"> - <span class="text-nowrap">{item.0}/<strong>{item.1}</strong> {f:translate(key:'isMissing')}</span> - <br>{f:translate(key:'referencedFrom')} {item.2}<br><br> - </f:for> - </f:then> - <f:else> - <p>{f:translate(key:'no_files_found')}</p> - </f:else> -</f:if> - - <h2>{f:translate(key:'select_db')}</h2> <f:format.raw>{select_db}</f:format.raw> -- GitLab