‪TYPO3CMS  ‪main
OptimizeDatabaseTableAdditionalFieldProvider.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Doctrine\DBAL\Platforms\MariaDBPlatform as DoctrineMariaDBPlatform;
19 use Doctrine\DBAL\Platforms\MySQLPlatform as DoctrineMySQLPlatform;
28 
34 {
38  protected ‪$languageFile = 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf';
39 
48  public function ‪getAdditionalFields(array &$taskInfo, $task, ‪SchedulerModuleController $schedulerModule)
49  {
50  $currentSchedulerModuleAction = $schedulerModule->‪getCurrentAction();
51 
52  // Initialize selected fields
53  if (empty($taskInfo['scheduler_optimizeDatabaseTables_selectedTables'])) {
54  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = [];
55  if ($currentSchedulerModuleAction === SchedulerManagementAction::ADD) {
56  // In case of new task, select no tables by default
57  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = [];
58  } elseif ($currentSchedulerModuleAction === SchedulerManagementAction::EDIT) {
59  // In case of editing the task, set to currently selected value
60  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = $task->selectedTables;
61  }
62  }
63  $fieldName = 'tx_scheduler[scheduler_optimizeDatabaseTables_selectedTables][]';
64  $fieldId = 'scheduler_optimizeDatabaseTables_selectedTables';
65  $fieldOptions = $this->‪getDatabaseTableOptions($taskInfo['scheduler_optimizeDatabaseTables_selectedTables']);
66  $fieldHtml = '<select class="form-select" name="' . $fieldName . '" id="' . $fieldId . '" size="10"'
67  . ' multiple="multiple">' . $fieldOptions . '</select>';
68  $additionalFields = [];
69  $additionalFields[$fieldId] = [
70  'code' => $fieldHtml,
71  'label' => $this->languageFile . ':label.optimizeDatabaseTables.selectTables',
72  'cshKey' => '_MOD_system_txschedulerM1',
73  'cshLabel' => $fieldId,
74  'type' => 'select',
75  ];
76 
77  return $additionalFields;
78  }
79 
87  public function ‪validateAdditionalFields(array &$submittedData, ‪SchedulerModuleController $schedulerModule)
88  {
89  $validData = true;
90  $availableTables = $this->‪getOptimizableTables();
91  if (is_array($submittedData['scheduler_optimizeDatabaseTables_selectedTables'] ?? false)) {
92  $invalidTables = array_diff(
93  $submittedData['scheduler_optimizeDatabaseTables_selectedTables'],
94  $availableTables
95  );
96  if (!empty($invalidTables)) {
97  $this->‪addMessage(
98  $this->‪getLanguageService()->sL($this->languageFile . ':msg.selectionOfNonExistingDatabaseTables'),
99  ContextualFeedbackSeverity::ERROR
100  );
101  $validData = false;
102  }
103  } else {
104  $this->‪addMessage(
105  $this->‪getLanguageService()->sL($this->languageFile . ':msg.noDatabaseTablesSelected'),
106  ContextualFeedbackSeverity::ERROR
107  );
108  $validData = false;
109  }
110 
111  return $validData;
112  }
113 
120  public function ‪saveAdditionalFields(array $submittedData, ‪AbstractTask $task)
121  {
122  $task->selectedTables = $submittedData['scheduler_optimizeDatabaseTables_selectedTables'];
123  }
124 
131  protected function ‪getDatabaseTableOptions(array $selectedTables)
132  {
133  $options = [];
134  $availableTables = $this->‪getOptimizableTables();
135  foreach ($availableTables as $tableName) {
136  $selected = in_array($tableName, $selectedTables, true) ? ' selected="selected"' : '';
137  $options[] = '<option value="' . $tableName . '"' . $selected . '>' . $tableName . '</option>';
138  }
139 
140  return implode('', $options);
141  }
142 
148  protected function ‪getOptimizableTables()
149  {
150  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
151  $defaultConnection = $connectionPool->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
152 
153  // Retrieve all optimizable tables for the default connection
154  $optimizableTables = $this->‪getOptimizableTablesForConnection($defaultConnection);
155 
156  // Retrieve additional optimizable tables that have been remapped to a different connection
157  $tableMap = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'] ?? [];
158  if ($tableMap) {
159  // Remove all remapped tables from the list of optimizable tables
160  // These tables will be rechecked and possibly re-added to the list
161  // of optimizable tables. This ensures that no orphaned table from
162  // the default connection gets mistakenly labeled as optimizable.
163  $optimizableTables = array_diff($optimizableTables, array_keys($tableMap));
164 
165  // Walk each connection and check all tables that have been
166  // remapped to it for optimization support.
167  $connectionNames = array_keys(array_flip($tableMap));
168  foreach ($connectionNames as $connectionName) {
169  $connection = $connectionPool->getConnectionByName($connectionName);
170  $tablesOnConnection = array_keys(array_filter(
171  $tableMap,
172  static function ($value) use ($connectionName) {
173  return $value === $connectionName;
174  }
175  ));
176  $tables = $this->‪getOptimizableTablesForConnection($connection, $tablesOnConnection);
177  $optimizableTables = array_merge($optimizableTables, $tables);
178  }
179  }
180 
181  sort($optimizableTables);
182 
183  return $optimizableTables;
184  }
185 
190  protected function ‪getOptimizableTablesForConnection(‪Connection $connection, array $tableNames = []): array
191  {
192  // Return empty list if the database platform is not MySQL/MariaDB
193  $platform = $connection->getDatabasePlatform();
194  if (!($platform instanceof DoctrineMariaDBPlatform || $platform instanceof DoctrineMySQLPlatform)) {
195  return [];
196  }
197 
198  // Retrieve all tables from the MySQL information schema that have an engine type
199  // that supports the OPTIMIZE TABLE command.
200  $queryBuilder = $connection->‪createQueryBuilder();
201  $queryBuilder->select('TABLE_NAME AS Table', 'ENGINE AS Engine')
202  ->from('information_schema.TABLES')
203  ->where(
204  $queryBuilder->expr()->eq(
205  'TABLE_TYPE',
206  $queryBuilder->createNamedParameter('BASE TABLE')
207  ),
208  $queryBuilder->expr()->in(
209  'ENGINE',
210  $queryBuilder->createNamedParameter(['InnoDB', 'MyISAM', 'ARCHIVE'], ‪Connection::PARAM_STR_ARRAY)
211  ),
212  $queryBuilder->expr()->eq(
213  'TABLE_SCHEMA',
214  $queryBuilder->createNamedParameter($connection->getDatabase())
215  )
216  );
217 
218  if (!empty($tableNames)) {
219  $queryBuilder->andWhere(
220  $queryBuilder->expr()->in(
221  'TABLE_NAME',
222  $queryBuilder->createNamedParameter($tableNames, ‪Connection::PARAM_STR_ARRAY)
223  )
224  );
225  }
226 
227  $tables = $queryBuilder->executeQuery()->fetchAllAssociative();
228 
229  return array_column($tables, 'Table');
230  }
231 
232  protected function ‪getLanguageService(): ?‪LanguageService
233  {
234  return ‪$GLOBALS['LANG'] ?? null;
235  }
236 }
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\$languageFile
‪string $languageFile
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:37
‪TYPO3\CMS\Scheduler\SchedulerManagementAction
‪SchedulerManagementAction
Definition: SchedulerManagementAction.php:25
‪TYPO3\CMS\Scheduler\Task
Definition: AbstractTask.php:16
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\getAdditionalFields
‪array getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $schedulerModule)
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:47
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\getOptimizableTablesForConnection
‪getOptimizableTablesForConnection(Connection $connection, array $tableNames=[])
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:189
‪TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider
Definition: AbstractAdditionalFieldProvider.php:29
‪TYPO3\CMS\Core\Database\ConnectionPool\DEFAULT_CONNECTION_NAME
‪const DEFAULT_CONNECTION_NAME
Definition: ConnectionPool.php:50
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\saveAdditionalFields
‪saveAdditionalFields(array $submittedData, AbstractTask $task)
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:119
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\validateAdditionalFields
‪bool validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule)
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:86
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getCurrentAction
‪getCurrentAction()
Definition: SchedulerModuleController.php:197
‪TYPO3\CMS\Scheduler\Task\AbstractTask
Definition: AbstractTask.php:33
‪TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider\addMessage
‪addMessage(string $message, ContextualFeedbackSeverity $severity=ContextualFeedbackSeverity::OK)
Definition: AbstractAdditionalFieldProvider.php:36
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\getDatabaseTableOptions
‪string getDatabaseTableOptions(array $selectedTables)
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:130
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController
Definition: SchedulerModuleController.php:61
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\getLanguageService
‪getLanguageService()
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:231
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR_ARRAY
‪const PARAM_STR_ARRAY
Definition: Connection.php:77
‪TYPO3\CMS\Core\Database\Connection\createQueryBuilder
‪createQueryBuilder()
Definition: Connection.php:114
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider\getOptimizableTables
‪array getOptimizableTables()
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:147
‪TYPO3\CMS\Scheduler\Task\OptimizeDatabaseTableAdditionalFieldProvider
Definition: OptimizeDatabaseTableAdditionalFieldProvider.php:34
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52