TYPO3 CMS  TYPO3_8-7
OptimizeDatabaseTableAdditionalFieldProvider.php
Go to the documentation of this file.
1 <?php
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 
113  public function saveAdditionalFields(array $submittedData, AbstractTask $task)
114  {
115  $task->selectedTables = $submittedData['scheduler_optimizeDatabaseTables_selectedTables'];
116  }
117 
124  protected function getDatabaseTableOptions(array $selectedTables)
125  {
126  $options = [];
127  $availableTables = $this->getOptimizableTables();
128  foreach ($availableTables as $tableName) {
129  $selected = in_array($tableName, $selectedTables, true) ? ' selected="selected"' : '';
130  $options[] = '<option value="' . $tableName . '"' . $selected . '>' . $tableName . '</option>';
131  }
132 
133  return implode('', $options);
134  }
135 
141  protected function getOptimizableTables()
142  {
143  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
144  $defaultConnection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
145 
146  // Retrieve all optimizable tables for the default connection
147  $optimizableTables = $this->getOptimizableTablesForConnection($defaultConnection);
148 
149  // Retrieve additional optimizable tables that have been remapped to a different connection
150  if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'])
151  && is_array($GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'])
152  ) {
153  $tableMap = $GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'];
154  // Remove all remapped tables from the list of optimizable tables
155  // These tables will be rechecked and possibly re-added to the list
156  // of optimizable tables. This ensures that no orphaned table from
157  // the default connection gets mistakenly labeled as optimizable.
158  $optimizableTables = array_diff($optimizableTables, array_keys($tableMap));
159 
160  // Walk each connection and check all tables that have been
161  // remapped to it for optimization support.
162  $connectionNames = array_keys(array_flip($tableMap));
163  foreach ($connectionNames as $connectionName) {
164  $connection = $connectionPool->getConnectionByName($connectionName);
165  $tablesOnConnection = array_keys(array_filter(
166  $tableMap,
167  function ($value) use ($connectionName) {
168  return $value === $connectionName;
169  }
170  ));
171  $tables = $this->getOptimizableTablesForConnection($connection, $tablesOnConnection);
172  $optimizableTables = array_merge($optimizableTables, $tables);
173  }
174  }
175 
176  sort($optimizableTables);
177 
178  return $optimizableTables;
179  }
180 
189  protected function getOptimizableTablesForConnection(Connection $connection, array $tableNames = []): array
190  {
191  // Return empty list if the database platform is not MySQL
192  if (strpos($connection->getServerVersion(), 'MySQL') !== 0) {
193  return [];
194  }
195 
196  // Retrieve all tables from the MySQL informaation schema that have an engine type
197  // that supports the OPTIMIZE TABLE command.
198  $queryBuilder = $connection->createQueryBuilder();
199  $queryBuilder->select('TABLE_NAME AS Table', 'ENGINE AS Engine')
200  ->from('information_schema.TABLES')
201  ->where(
202  $queryBuilder->expr()->eq(
203  'TABLE_TYPE',
204  $queryBuilder->createNamedParameter('BASE TABLE', \PDO::PARAM_STR)
205  ),
206  $queryBuilder->expr()->in(
207  'ENGINE',
208  $queryBuilder->createNamedParameter(['InnoDB', 'MyISAM', 'ARCHIVE'], Connection::PARAM_STR_ARRAY)
209  ),
210  $queryBuilder->expr()->eq(
211  'TABLE_SCHEMA',
212  $queryBuilder->createNamedParameter($connection->getDatabase(), \PDO::PARAM_STR)
213  )
214  );
215 
216  if (!empty($tableNames)) {
217  $queryBuilder->andWhere(
218  $queryBuilder->expr()->in(
219  'TABLE_NAME',
220  $queryBuilder->createNamedParameter($tableNames, \PDO::PARAM_STR)
221  )
222  );
223  }
224 
225  $tables = $queryBuilder->execute()->fetchAll();
226 
227  return array_column($tables, 'Table');
228  }
229 }
getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $parentObject)
static makeInstance($className,... $constructorArguments)
validateAdditionalFields(array &$submittedData, SchedulerModuleController $parentObject)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']