TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
OptimizeDatabaseTableAdditionalFieldProvider.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Scheduler\Task;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
23 
28 {
32  protected $languageFile = 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf';
33 
42  public function getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $parentObject)
43  {
44  // Initialize selected fields
45  if (empty($taskInfo['scheduler_optimizeDatabaseTables_selectedTables'])) {
46  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = [];
47  if ($parentObject->CMD === 'add') {
48  // In case of new task, select no tables by default
49  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = [];
50  } elseif ($parentObject->CMD === 'edit') {
51  // In case of editing the task, set to currently selected value
52  $taskInfo['scheduler_optimizeDatabaseTables_selectedTables'] = $task->selectedTables;
53  }
54  }
55  $fieldName = 'tx_scheduler[scheduler_optimizeDatabaseTables_selectedTables][]';
56  $fieldId = 'scheduler_optimizeDatabaseTables_selectedTables';
57  $fieldOptions = $this->getDatabaseTableOptions($taskInfo['scheduler_optimizeDatabaseTables_selectedTables']);
58  $fieldHtml = '<select class="form-control" name="' . $fieldName
59  . '" id="' . $fieldId
60  . '" class="from-control" size="10" multiple="multiple">'
61  . $fieldOptions
62  . '</select>';
63  $additionalFields[$fieldId] = [
64  'code' => $fieldHtml,
65  'label' => $this->languageFile . ':label.optimizeDatabaseTables.selectTables',
66  'cshKey' => '_MOD_system_txschedulerM1',
67  'cshLabel' => $fieldId,
68  ];
69 
70  return $additionalFields;
71  }
72 
80  public function validateAdditionalFields(array &$submittedData, SchedulerModuleController $parentObject)
81  {
82  $validData = true;
83  $availableTables = $this->getOptimizableTables();
84  if (is_array($submittedData['scheduler_optimizeDatabaseTables_selectedTables'])) {
85  $invalidTables = array_diff(
86  $submittedData['scheduler_optimizeDatabaseTables_selectedTables'],
87  $availableTables
88  );
89  if (!empty($invalidTables)) {
90  $parentObject->addMessage(
91  $GLOBALS['LANG']->sL($this->languageFile . ':msg.selectionOfNonExistingDatabaseTables'),
93  );
94  $validData = false;
95  }
96  } else {
97  $parentObject->addMessage(
98  $GLOBALS['LANG']->sL($this->languageFile . ':msg.noDatabaseTablesSelected'),
100  );
101  $validData = false;
102  }
103 
104  return $validData;
105  }
106 
114  public function saveAdditionalFields(array $submittedData, AbstractTask $task)
115  {
116  $task->selectedTables = $submittedData['scheduler_optimizeDatabaseTables_selectedTables'];
117  }
118 
125  protected function getDatabaseTableOptions(array $selectedTables)
126  {
127  $options = [];
128  $availableTables = $this->getOptimizableTables();
129  foreach ($availableTables as $tableName) {
130  $selected = in_array($tableName, $selectedTables, true) ? ' selected="selected"' : '';
131  $options[] = '<option value="' . $tableName . '"' . $selected . '>' . $tableName . '</option>';
132  }
133 
134  return implode('', $options);
135  }
136 
142  protected function getOptimizableTables()
143  {
144  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
145  $defaultConnection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
146 
147  // Retrieve all optimizable tables for the default connection
148  $optimizableTables = $this->getOptimizableTablesForConnection($defaultConnection);
149 
150  // Retrieve additional optimizable tables that have been remapped to a different connection
151  if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'])
152  && is_array($GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'])
153  ) {
154  $tableMap = $GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'];
155  // Remove all remapped tables from the list of optimizable tables
156  // These tables will be rechecked and possibly re-added to the list
157  // of optimizable tables. This ensures that no orphaned table from
158  // the default connection gets mistakenly labeled as optimizable.
159  $optimizableTables = array_diff($optimizableTables, array_keys($tableMap));
160 
161  // Walk each connection and check all tables that have been
162  // remapped to it for optimization support.
163  $connectionNames = array_keys(array_flip($tableMap));
164  foreach ($connectionNames as $connectionName) {
165  $connection = $connectionPool->getConnectionByName($connectionName);
166  $tablesOnConnection = array_keys(array_filter(
167  $tableMap,
168  function ($value) use ($connectionName) {
169  return $value === $connectionName;
170  }
171  ));
172  $tables = $this->getOptimizableTablesForConnection($connection, $tablesOnConnection);
173  $optimizableTables = array_merge($optimizableTables, $tables);
174  }
175  }
176 
177  sort($optimizableTables);
178 
179  return $optimizableTables;
180  }
181 
190  protected function getOptimizableTablesForConnection(Connection $connection, array $tableNames = []): array
191  {
192  // Return empty list if the database platform is not MySQL
193  if (strpos($connection->getServerVersion(), 'MySQL') !== 0) {
194  return [];
195  }
196 
197  // Retrieve all tables from the MySQL informaation schema that have an engine type
198  // that supports the OPTIMIZE TABLE command.
199  $queryBuilder = $connection->createQueryBuilder();
200  $queryBuilder->select('TABLE_NAME AS Table', 'ENGINE AS Engine')
201  ->from('information_schema.TABLES')
202  ->where(
203  $queryBuilder->expr()->eq(
204  'TABLE_TYPE',
205  $queryBuilder->createNamedParameter('BASE TABLE', \PDO::PARAM_STR)
206  ),
207  $queryBuilder->expr()->in(
208  'ENGINE',
209  $queryBuilder->createNamedParameter(['InnoDB', 'MyISAM', 'ARCHIVE'], Connection::PARAM_STR_ARRAY)
210  ),
211  $queryBuilder->expr()->eq(
212  'TABLE_SCHEMA',
213  $queryBuilder->createNamedParameter($connection->getDatabase(), \PDO::PARAM_STR)
214  )
215  );
216 
217  if (!empty($tableNames)) {
218  $queryBuilder->andWhere(
219  $queryBuilder->expr()->in(
220  'TABLE_NAME',
221  $queryBuilder->createNamedParameter($tableNames, \PDO::PARAM_STR)
222  )
223  );
224  }
225 
226  $tables = $queryBuilder->execute()->fetchAll();
227 
228  return array_column($tables, 'Table');
229  }
230 }
getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $parentObject)
validateAdditionalFields(array &$submittedData, SchedulerModuleController $parentObject)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)