Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like DumpCommand often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use DumpCommand, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class DumpCommand extends AbstractDatabaseCommand |
||
18 | { |
||
19 | /** |
||
20 | * @var array |
||
21 | */ |
||
22 | protected $tableDefinitions = null; |
||
23 | |||
24 | /** |
||
25 | * @var array |
||
26 | */ |
||
27 | protected $commandConfig = null; |
||
28 | |||
29 | protected function configure() |
||
120 | |||
121 | /** |
||
122 | * @return array |
||
123 | * |
||
124 | * @deprecated Use database helper |
||
125 | * @throws RuntimeException |
||
126 | */ |
||
127 | public function getTableDefinitions() |
||
128 | { |
||
129 | $this->commandConfig = $this->getCommandConfig(); |
||
130 | |||
131 | if (is_null($this->tableDefinitions)) { |
||
132 | /* @var $dbHelper DatabaseHelper */ |
||
133 | $dbHelper = $this->getHelper('database'); |
||
134 | |||
135 | $this->tableDefinitions = $dbHelper->getTableDefinitions($this->commandConfig); |
||
136 | } |
||
137 | |||
138 | return $this->tableDefinitions; |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Generate help for table definitions |
||
143 | * |
||
144 | * @return string |
||
145 | */ |
||
146 | public function getTableDefinitionHelp() |
||
147 | { |
||
148 | $messages = PHP_EOL; |
||
149 | $this->commandConfig = $this->getCommandConfig(); |
||
150 | $messages .= <<<HELP |
||
151 | <comment>Strip option</comment> |
||
152 | If you like to skip data of some tables you can use the --strip option. |
||
153 | The strip option creates only the structure of the defined tables and |
||
154 | forces `mysqldump` to skip the data. |
||
155 | |||
156 | Separate each table to strip by a space. |
||
157 | You can use wildcards like * and ? in the table names to strip multiple |
||
158 | tables. In addition you can specify pre-defined table groups, that start |
||
159 | with an |
||
160 | |||
161 | Example: "dataflow_batch_export unimportant_module_* @log |
||
162 | |||
163 | $ n98-magerun.phar db:dump --strip="@stripped" |
||
164 | |||
165 | <comment>Available Table Groups</comment> |
||
166 | |||
167 | HELP; |
||
168 | |||
169 | $definitions = $this->getTableDefinitions(); |
||
|
|||
170 | $list = array(); |
||
171 | $maxNameLen = 0; |
||
172 | foreach ($definitions as $id => $definition) { |
||
173 | $name = '@' . $id; |
||
174 | $description = isset($definition['description']) ? $definition['description'] . '.' : ''; |
||
175 | $nameLen = strlen($name); |
||
176 | if ($nameLen > $maxNameLen) { |
||
177 | $maxNameLen = $nameLen; |
||
178 | } |
||
179 | $list[] = array($name, $description); |
||
180 | } |
||
181 | |||
182 | $decrSize = 78 - $maxNameLen - 3; |
||
183 | |||
184 | foreach ($list as $entry) { |
||
185 | list($name, $description) = $entry; |
||
186 | $delta = max(0, $maxNameLen - strlen($name)); |
||
187 | $spacer = $delta ? str_repeat(' ', $delta) : ''; |
||
188 | $buffer = wordwrap($description, $decrSize); |
||
189 | $buffer = strtr($buffer, array("\n" => "\n" . str_repeat(' ', 3 + $maxNameLen))); |
||
190 | $messages .= sprintf(" <info>%s</info>%s %s\n", $name, $spacer, $buffer); |
||
191 | } |
||
192 | |||
193 | return $messages; |
||
194 | } |
||
195 | |||
196 | public function getHelp() |
||
203 | |||
204 | /** |
||
205 | * @param InputInterface $input |
||
206 | * @param OutputInterface $output |
||
207 | * |
||
208 | * @return int|void |
||
209 | */ |
||
210 | protected function execute(InputInterface $input, OutputInterface $output) |
||
211 | { |
||
212 | // communicate early what is required for this command to run (is enabled) |
||
213 | $enabler = new Enabler($this); |
||
214 | $enabler->functionExists('exec'); |
||
215 | $enabler->functionExists('passthru'); |
||
216 | $enabler->operatingSystemIsNotWindows(); |
||
217 | |||
218 | $this->detectDbSettings($output); |
||
219 | |||
220 | if (!$input->getOption('stdout') && !$input->getOption('only-command') |
||
221 | && !$input->getOption('print-only-filename') |
||
222 | ) { |
||
223 | $this->writeSection($output, 'Dump MySQL Database'); |
||
224 | } |
||
225 | |||
226 | $compressor = $this->getCompressor($input->getOption('compression')); |
||
227 | $fileName = $this->getFileName($input, $output, $compressor); |
||
228 | |||
229 | $stripTables = array(); |
||
230 | View Code Duplication | if ($input->getOption('strip')) { |
|
231 | /* @var $database DatabaseHelper */ |
||
232 | $database = $this->getHelper('database'); |
||
233 | $stripTables = $database->resolveTables( |
||
234 | explode(' ', $input->getOption('strip')), |
||
235 | $this->getTableDefinitions() |
||
236 | ); |
||
237 | if (!$input->getOption('stdout') && !$input->getOption('only-command') |
||
238 | && !$input->getOption('print-only-filename') |
||
239 | ) { |
||
240 | $output->writeln( |
||
241 | '<comment>No-data export for: <info>' . implode(' ', $stripTables) . '</info></comment>' |
||
242 | ); |
||
243 | } |
||
244 | } |
||
245 | |||
246 | $excludeTables = array(); |
||
247 | View Code Duplication | if ($input->getOption('exclude')) { |
|
248 | $excludeTables = $this->getHelper('database')->resolveTables( |
||
249 | explode(' ', $input->getOption('exclude')), |
||
250 | $this->getTableDefinitions() |
||
251 | ); |
||
252 | if (!$input->getOption('stdout') && !$input->getOption('only-command') |
||
253 | && !$input->getOption('print-only-filename') |
||
254 | ) { |
||
255 | $output->writeln( |
||
256 | '<comment>Excluded: <info>' . implode(' ', $excludeTables) . '</info></comment>' |
||
257 | ); |
||
258 | } |
||
259 | } |
||
260 | |||
261 | $dumpOptions = ''; |
||
262 | if (!$input->getOption('no-single-transaction')) { |
||
263 | $dumpOptions = '--single-transaction --quick '; |
||
264 | } |
||
265 | |||
266 | if ($input->getOption('human-readable')) { |
||
267 | $dumpOptions .= '--complete-insert --skip-extended-insert '; |
||
268 | } |
||
269 | |||
270 | if ($input->getOption('add-routines')) { |
||
271 | $dumpOptions .= '--routines '; |
||
272 | } |
||
273 | |||
274 | if ($input->getOption('xml')) { |
||
275 | $dumpOptions .= '--xml '; |
||
276 | } |
||
277 | |||
278 | if ($input->getOption('hex-blob')) { |
||
279 | $dumpOptions .= '--hex-blob '; |
||
280 | } |
||
281 | |||
282 | $execs = array(); |
||
283 | |||
284 | $ignore = ''; |
||
285 | foreach (array_merge($excludeTables, $stripTables) as $tableName) { |
||
286 | $ignore .= '--ignore-table=' . $this->dbSettings['dbname'] . '.' . $tableName . ' '; |
||
287 | } |
||
288 | |||
289 | $mysqlClientToolConnectionString = $this->getHelper('database')->getMysqlClientToolConnectionString(); |
||
290 | |||
291 | if (count($stripTables) > 0) { |
||
292 | // dump structure for strip-tables |
||
293 | $exec = 'mysqldump ' . $dumpOptions . '--no-data ' . $mysqlClientToolConnectionString; |
||
294 | $exec .= ' ' . implode(' ', $stripTables); |
||
295 | $exec .= $this->postDumpPipeCommands(); |
||
296 | $exec = $compressor->getCompressingCommand($exec); |
||
297 | if (!$input->getOption('stdout')) { |
||
298 | $exec .= ' > ' . escapeshellarg($fileName); |
||
299 | } |
||
300 | $execs[] = $exec; |
||
301 | } |
||
302 | |||
303 | // dump data for all other tables |
||
304 | $exec = 'mysqldump ' . $dumpOptions . $mysqlClientToolConnectionString . ' ' . $ignore; |
||
305 | $exec .= $this->postDumpPipeCommands(); |
||
306 | $exec = $compressor->getCompressingCommand($exec); |
||
307 | if (!$input->getOption('stdout')) { |
||
308 | $exec .= (count($stripTables) > 0 ? ' >> ' : ' > ') . escapeshellarg($fileName); |
||
309 | } |
||
310 | $execs[] = $exec; |
||
311 | |||
312 | $this->runExecs($execs, $fileName, $input, $output); |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * @param array $execs |
||
317 | * @param string $fileName |
||
318 | * @param InputInterface $input |
||
319 | * @param OutputInterface $output |
||
320 | */ |
||
321 | private function runExecs(array $execs, $fileName, InputInterface $input, OutputInterface $output) |
||
365 | |||
366 | /** |
||
367 | * Commands which filter mysql data. Piped to mysqldump command |
||
368 | * |
||
369 | * @return string |
||
370 | */ |
||
371 | protected function postDumpPipeCommands() |
||
375 | |||
376 | /** |
||
377 | * @param InputInterface $input |
||
378 | * @param OutputInterface $output |
||
379 | * @param Compressor $compressor |
||
380 | * |
||
381 | * @return string |
||
382 | */ |
||
383 | protected function getFileName(InputInterface $input, OutputInterface $output, Compressor $compressor) |
||
439 | } |
||
440 |
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.