netz98 /
n98-magerun2
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace N98\Magento\Command\Database\Maintain; |
||
| 4 | |||
| 5 | use N98\Magento\Command\AbstractMagentoCommand; |
||
| 6 | use Symfony\Component\Console\Input\InputInterface; |
||
| 7 | use Symfony\Component\Console\Input\InputOption; |
||
| 8 | use Symfony\Component\Console\Output\OutputInterface; |
||
| 9 | use N98\Util\Console\Helper\Table\Renderer\RendererFactory; |
||
| 10 | |||
| 11 | class CheckTablesCommand extends AbstractMagentoCommand |
||
| 12 | { |
||
| 13 | const MESSAGE_CHECK_NOT_SUPPORTED = 'The storage engine for the table doesn\'t support check'; |
||
| 14 | const MESSAGE_REPAIR_NOT_SUPPORTED = 'The storage engine for the table doesn\'t support repair'; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * @var \Symfony\Component\Console\Input\InputInterface |
||
| 18 | */ |
||
| 19 | protected $input = null; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * @var \Symfony\Component\Console\Output\OutputInterface |
||
| 23 | */ |
||
| 24 | protected $output = null; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @var \N98\Util\Console\Helper\DatabaseHelper |
||
| 28 | */ |
||
| 29 | protected $dbHelper = null; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @var bool |
||
| 33 | */ |
||
| 34 | protected $showProgress = false; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * @var array |
||
| 38 | */ |
||
| 39 | protected $allowedTypes = array( |
||
| 40 | 'QUICK', |
||
| 41 | 'FAST', |
||
| 42 | 'CHANGED', |
||
| 43 | 'MEDIUM', |
||
| 44 | 'EXTENDED', |
||
| 45 | ); |
||
| 46 | |||
| 47 | protected function configure() |
||
| 48 | { |
||
| 49 | $help = <<<'HELP' |
||
| 50 | <comment>TYPE OPTIONS</comment> |
||
| 51 | |||
| 52 | <info>QUICK</info> |
||
| 53 | Do not scan the rows to check for incorrect links. |
||
| 54 | Applies to InnoDB and MyISAM tables and views. |
||
| 55 | <info>FAST</info> |
||
| 56 | Check only tables that have not been closed properly. |
||
| 57 | Applies only to MyISAM tables and views; ignored for InnoDB. |
||
| 58 | <info>CHANGED</info> |
||
| 59 | Check only tables that have been changed since the last check or that |
||
| 60 | have not been closed properly. Applies only to MyISAM tables and views; |
||
| 61 | ignored for InnoDB. |
||
| 62 | <info>MEDIUM</info> |
||
| 63 | Scan rows to verify that deleted links are valid. |
||
| 64 | This also calculates a key checksum for the rows and verifies this with a |
||
| 65 | calculated checksum for the keys. Applies only to MyISAM tables and views; |
||
| 66 | ignored for InnoDB. |
||
| 67 | <info>EXTENDED</info> |
||
| 68 | Do a full key lookup for all keys for each row. This ensures that the table |
||
| 69 | is 100% consistent, but takes a long time. |
||
| 70 | Applies only to MyISAM tables and views; ignored for InnoDB. |
||
| 71 | |||
| 72 | <comment>InnoDB</comment> |
||
| 73 | InnoDB tables will be optimized with the ALTER TABLE ... ENGINE=InnoDB statement. |
||
| 74 | The options above do not apply to them. |
||
| 75 | HELP; |
||
| 76 | |||
| 77 | $this |
||
| 78 | ->setName('db:maintain:check-tables') |
||
| 79 | ->setDescription('Check database tables') |
||
| 80 | ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'Check type (one of QUICK, FAST, MEDIUM, EXTENDED, CHANGED)', 'MEDIUM') |
||
|
0 ignored issues
–
show
|
|||
| 81 | ->addOption('repair', null, InputOption::VALUE_NONE, 'Repair tables (only MyISAM)') |
||
| 82 | ->addOption('table', null, InputOption::VALUE_OPTIONAL, 'Process only given table (wildcards are supported)') |
||
|
0 ignored issues
–
show
|
|||
| 83 | ->addOption( |
||
| 84 | 'format', |
||
| 85 | null, |
||
| 86 | InputOption::VALUE_OPTIONAL, |
||
| 87 | 'Output Format. One of [' . implode(',', RendererFactory::getFormats()) . ']' |
||
| 88 | ) |
||
| 89 | ->setHelp($help);; |
||
| 90 | } |
||
| 91 | |||
| 92 | /** |
||
| 93 | * @throws \InvalidArgumentException |
||
| 94 | * |
||
| 95 | */ |
||
| 96 | protected function isTypeAllowed() |
||
| 97 | { |
||
| 98 | $type = $this->input->getOption('type'); |
||
| 99 | $type = strtoupper($type); |
||
| 100 | if ($type && !in_array($type, $this->allowedTypes)) { |
||
| 101 | throw new \InvalidArgumentException('Invalid type was given'); |
||
| 102 | } |
||
| 103 | } |
||
| 104 | |||
| 105 | protected function progressAdvance() |
||
| 106 | { |
||
| 107 | if ($this->showProgress) { |
||
| 108 | $this->getHelper('progress')->advance(); |
||
| 109 | } |
||
| 110 | } |
||
| 111 | |||
| 112 | /** |
||
| 113 | * @param \Symfony\Component\Console\Input\InputInterface $input |
||
| 114 | * @param \Symfony\Component\Console\Output\OutputInterface $output |
||
| 115 | * |
||
| 116 | * @throws \InvalidArgumentException |
||
| 117 | * @return int|void |
||
| 118 | */ |
||
| 119 | protected function execute(InputInterface $input, OutputInterface $output) |
||
| 120 | { |
||
| 121 | $this->input = $input; |
||
| 122 | $this->output = $output; |
||
| 123 | $this->isTypeAllowed(); |
||
| 124 | $this->detectMagento($output); |
||
| 125 | $this->dbHelper = $this->getHelper('database'); |
||
| 126 | $this->showProgress = $input->getOption('format') == null; |
||
| 127 | |||
| 128 | if ($input->getOption('table')) { |
||
| 129 | $resolvedTables = array( |
||
| 130 | $this->dbHelper->resolveTables( |
||
| 131 | array('@check'), |
||
| 132 | array( |
||
| 133 | 'check' => array( |
||
| 134 | 'tables' => $input->getOption('table') |
||
| 135 | ) |
||
| 136 | ) |
||
| 137 | ) |
||
| 138 | ); |
||
| 139 | $tables = $resolvedTables[0]; |
||
| 140 | } else { |
||
| 141 | $tables = $this->dbHelper->getTables(); |
||
| 142 | } |
||
| 143 | |||
| 144 | $allTableStatus = $this->dbHelper->getTablesStatus(); |
||
| 145 | |||
| 146 | $tableOutput = array(); |
||
| 147 | /** @var \Symfony\Component\Console\Helper\ProgressHelper $progress */ |
||
| 148 | $progress = $this->getHelper('progress'); |
||
| 149 | if ($this->showProgress) { |
||
| 150 | $progress->start($output, count($tables)); |
||
| 151 | } |
||
| 152 | |||
| 153 | $methods = array( |
||
| 154 | 'InnoDB' => 1, |
||
| 155 | 'MEMORY' => 1, |
||
| 156 | 'MyISAM' => 1, |
||
| 157 | ); |
||
| 158 | |||
| 159 | foreach ($tables as $tableName) { |
||
| 160 | |||
| 161 | if (isset($allTableStatus[$tableName]) && isset($methods[$allTableStatus[$tableName]['Engine']])) { |
||
| 162 | $m = '_check' . $allTableStatus[$tableName]['Engine']; |
||
| 163 | $tableOutput = array_merge($tableOutput, $this->$m($tableName)); |
||
| 164 | } else { |
||
| 165 | $tableOutput[] = array( |
||
| 166 | 'table' => $tableName, |
||
| 167 | 'operation' => 'not supported', |
||
| 168 | 'type' => '', |
||
| 169 | 'status' => '', |
||
| 170 | ); |
||
| 171 | } |
||
| 172 | $this->progressAdvance(); |
||
| 173 | } |
||
| 174 | |||
| 175 | if ($this->showProgress) { |
||
| 176 | $progress->finish(); |
||
| 177 | } |
||
| 178 | |||
| 179 | $this->getHelper('table') |
||
| 180 | ->setHeaders(array('Table', 'Operation', 'Type', 'Status')) |
||
| 181 | ->renderByFormat($this->output, $tableOutput, $this->input->getOption('format')); |
||
| 182 | } |
||
| 183 | |||
| 184 | /** |
||
| 185 | * @param string $tableName |
||
| 186 | * @param string $engine |
||
| 187 | * |
||
| 188 | * @return array |
||
| 189 | */ |
||
| 190 | protected function _queryAlterTable($tableName, $engine) |
||
| 191 | { |
||
| 192 | /** @var \PDO $connection */ |
||
| 193 | $connection = $this->dbHelper->getConnection($this->output); |
||
| 194 | $start = microtime(true); |
||
| 195 | $affectedRows = $connection->exec(sprintf('ALTER TABLE %s ENGINE=%s', $tableName, $engine)); |
||
| 196 | |||
| 197 | return array(array( |
||
| 198 | 'table' => $tableName, |
||
| 199 | 'operation' => 'ENGINE ' . $engine, |
||
| 200 | 'type' => sprintf('%15s rows', (string)$affectedRows), |
||
| 201 | 'status' => sprintf('%.3f secs', microtime(true) - $start), |
||
| 202 | ) |
||
| 203 | ); |
||
| 204 | } |
||
| 205 | |||
| 206 | /** |
||
| 207 | * @param string $tableName |
||
| 208 | * |
||
| 209 | * @return array |
||
| 210 | */ |
||
| 211 | protected function _checkInnoDB($tableName) |
||
| 212 | { |
||
| 213 | return $this->_queryAlterTable($tableName, 'InnoDB'); |
||
| 214 | } |
||
| 215 | |||
| 216 | /** |
||
| 217 | * @param string $tableName |
||
| 218 | * |
||
| 219 | * @return array |
||
| 220 | */ |
||
| 221 | protected function _checkMEMORY($tableName) |
||
| 222 | { |
||
| 223 | return $this->_queryAlterTable($tableName, 'MEMORY'); |
||
| 224 | } |
||
| 225 | |||
| 226 | /** |
||
| 227 | * @param string $tableName |
||
| 228 | * |
||
| 229 | * @return array |
||
| 230 | */ |
||
| 231 | protected function _checkMyISAM($tableName) |
||
| 232 | { |
||
| 233 | $table = array(); |
||
| 234 | $type = $this->input->getOption('type'); |
||
| 235 | $result = $this->_query(sprintf('CHECK TABLE %s %s', $tableName, $type)); |
||
| 236 | if ($result['Msg_text'] == self::MESSAGE_CHECK_NOT_SUPPORTED) { |
||
| 237 | return array(); |
||
| 238 | } |
||
| 239 | |||
| 240 | $table[] = array( |
||
| 241 | 'table' => $tableName, |
||
| 242 | 'operation' => $result['Op'], |
||
| 243 | 'type' => $type, |
||
| 244 | 'status' => $result['Msg_text'], |
||
| 245 | ); |
||
| 246 | |||
| 247 | if ($result['Msg_text'] != 'OK' |
||
| 248 | && $this->input->getOption('repair') |
||
| 249 | ) { |
||
| 250 | $result = $this->_query(sprintf('REPAIR TABLE %s %s', $tableName, $type)); |
||
| 251 | if ($result['Msg_text'] != self::MESSAGE_REPAIR_NOT_SUPPORTED) { |
||
| 252 | $table[] = array( |
||
| 253 | 'table' => $tableName, |
||
| 254 | 'operation' => $result['Op'], |
||
| 255 | 'type' => $type, |
||
| 256 | 'status' => $result['Msg_text'], |
||
| 257 | ); |
||
| 258 | } |
||
| 259 | } |
||
| 260 | return $table; |
||
| 261 | } |
||
| 262 | |||
| 263 | /** |
||
| 264 | * @param string $sql |
||
| 265 | * |
||
| 266 | * @return array|bool |
||
| 267 | */ |
||
| 268 | protected function _query($sql) |
||
| 269 | { |
||
| 270 | /** @var \PDO $connection */ |
||
| 271 | $connection = $this->dbHelper->getConnection($this->output); |
||
| 272 | $query = $connection->prepare($sql); |
||
| 273 | $query->execute(); |
||
| 274 | $result = $query->fetch(\PDO::FETCH_ASSOC); |
||
| 275 | return $result; |
||
| 276 | } |
||
| 277 | } |
||
| 278 |
Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.