Completed
Pull Request — master (#1455)
by
unknown
01:43
created

AbstractCommand   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 324
Duplicated Lines 9.88 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 53.72%

Importance

Changes 0
Metric Value
wmc 37
lcom 1
cbo 8
dl 32
loc 324
ccs 65
cts 121
cp 0.5372
rs 9.44
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 5 1
B bootstrap() 0 34 6
A setConfig() 0 6 1
A getConfig() 0 4 1
A setAdapter() 0 6 1
A getAdapter() 0 4 1
A setManager() 0 6 1
A getManager() 0 4 1
B locateConfigFile() 0 33 6
B loadConfig() 0 42 8
A loadManager() 0 11 2
A verifyMigrationDirectory() 16 16 3
A verifySeedDirectory() 16 16 3
A getMigrationTemplateFilename() 0 4 1
A getSeedTemplateFilename() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

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:

1
<?php
2
/**
3
 * Phinx
4
 *
5
 * (The MIT license)
6
 * Copyright (c) 2015 Rob Morgan
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated * documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
25
 *
26
 * @package    Phinx
27
 * @subpackage Phinx\Console
28
 */
29
namespace Phinx\Console\Command;
30
31
use Phinx\Config\Config;
32
use Phinx\Config\ConfigInterface;
33
use Phinx\Db\Adapter\AdapterInterface;
34
use Phinx\Migration\Manager;
35
use Phinx\Util\Util;
36
use Symfony\Component\Config\FileLocator;
37
use Symfony\Component\Console\Command\Command;
38
use Symfony\Component\Console\Input\InputInterface;
39
use Symfony\Component\Console\Input\InputOption;
40
use Symfony\Component\Console\Output\OutputInterface;
41
42
/**
43
 * Abstract command, contains bootstrapping info
44
 *
45
 * @author Rob Morgan <[email protected]>
46
 */
47
abstract class AbstractCommand extends Command
48
{
49
    /**
50
     * The location of the default migration template.
51
     */
52
    const DEFAULT_MIGRATION_TEMPLATE = '/../../Migration/Migration.template.php.dist';
53
54
    /**
55
     * The location of the default seed template.
56
     */
57
    const DEFAULT_SEED_TEMPLATE = '/../../Seed/Seed.template.php.dist';
58
59
    /**
60
     * @var \Phinx\Config\ConfigInterface
61
     */
62
    protected $config;
63
64
    /**
65
     * @var \Phinx\Db\Adapter\AdapterInterface
66
     */
67
    protected $adapter;
68
69
    /**
70
     * @var \Phinx\Migration\Manager
71
     */
72
    protected $manager;
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 54
    protected function configure()
78
    {
79 54
        $this->addOption('--configuration', '-c', InputOption::VALUE_REQUIRED, 'The configuration file to load');
80 54
        $this->addOption('--parser', '-p', InputOption::VALUE_REQUIRED, 'Parser used to read the config file. Defaults to YAML');
81 54
    }
82
83
    /**
84
     * Bootstrap Phinx.
85
     *
86
     * @param \Symfony\Component\Console\Input\InputInterface $input
87
     * @param \Symfony\Component\Console\Output\OutputInterface $output
88
     * @return void
89
     */
90 32
    public function bootstrap(InputInterface $input, OutputInterface $output)
91
    {
92 32
        if (!$this->getConfig()) {
93
            $this->loadConfig($input, $output);
94
        }
95
96 32
        $this->loadManager($input, $output);
97
98
        if ($bootstrap = $this->getConfig()->getBootstrapFile()) {
99 32
            $output->writeln('<info>using bootstrap</info> .' . str_replace(getcwd(), '', realpath($bootstrap)) . ' ');
100
            Util::loadPhpFile($bootstrap);
101 32
        }
102
103 32
        // report the paths
104 32
        $paths = $this->getConfig()->getMigrationPaths();
105 32
106
        $output->writeln('<info>using migration paths</info> ');
107
108 32
        foreach (Util::globAll($paths) as $path) {
109
            $output->writeln('<info> - ' . realpath($path) . '</info>');
110 6
        }
111
112 6
        try {
113 6
            $paths = $this->getConfig()->getSeedPaths();
114 6
115 32
            $output->writeln('<info>using seed paths</info> ');
116
117
            foreach (Util::globAll($paths) as $path) {
118 32
                $output->writeln('<info> - ' . realpath($path) . '</info>');
119
            }
120
        } catch (\UnexpectedValueException $e) {
121
            // do nothing as seeds are optional
122
        }
123
    }
124
125
    /**
126 32
     * Sets the config.
127
     *
128 32
     * @param  \Phinx\Config\ConfigInterface $config
129 32
     * @return \Phinx\Console\Command\AbstractCommand
130
     */
131
    public function setConfig(ConfigInterface $config)
132
    {
133
        $this->config = $config;
134
135
        return $this;
136
    }
137 32
138
    /**
139 32
     * Gets the config.
140
     *
141
     * @return \Phinx\Config\ConfigInterface
142
     */
143
    public function getConfig()
144
    {
145
        return $this->config;
146
    }
147
148
    /**
149
     * Sets the database adapter.
150
     *
151
     * @param \Phinx\Db\Adapter\AdapterInterface $adapter
152
     * @return \Phinx\Console\Command\AbstractCommand
153
     */
154
    public function setAdapter(AdapterInterface $adapter)
155
    {
156
        $this->adapter = $adapter;
157
158
        return $this;
159
    }
160
161
    /**
162
     * Gets the database adapter.
163
     *
164
     * @return \Phinx\Db\Adapter\AdapterInterface
165
     */
166
    public function getAdapter()
167
    {
168
        return $this->adapter;
169
    }
170 32
171
    /**
172 32
     * Sets the migration manager.
173 32
     *
174
     * @param \Phinx\Migration\Manager $manager
175
     * @return \Phinx\Console\Command\AbstractCommand
176
     */
177
    public function setManager(Manager $manager)
178
    {
179
        $this->manager = $manager;
180
181 32
        return $this;
182
    }
183 32
184
    /**
185
     * Gets the migration manager.
186
     *
187
     * @return \Phinx\Migration\Manager|null
188
     */
189
    public function getManager()
190
    {
191
        return $this->manager;
192 10
    }
193
194 10
    /**
195
     * Returns config file path
196 10
     *
197
     * @param \Symfony\Component\Console\Input\InputInterface $input
198 10
     * @return string
199 4
     */
200 4
    protected function locateConfigFile(InputInterface $input)
201
    {
202 10
        $configFile = $input->getOption('configuration');
203
204
        $useDefault = false;
205
206 10
        if ($configFile === null || $configFile === false) {
207
            $useDefault = true;
208 10
        }
209
210 10
        $cwd = getcwd();
211
212 6
        // locate the phinx config file (default: phinx.yml)
213
        // TODO - In future walk the tree in reverse (max 10 levels)
214
        $locator = new FileLocator([
215 4
            $cwd . DIRECTORY_SEPARATOR
216 4
        ]);
217
218 4
        if (!$useDefault) {
219 3
            // Locate() throws an exception if the file does not exist
220 3
            return $locator->locate($configFile, $cwd, $first = true);
221
        }
222 3
223 1
        $possibleConfigFiles = ['phinx.php', 'phinx.json', 'phinx.yml'];
224
        foreach ($possibleConfigFiles as $configFile) {
225
            try {
226
                return $locator->locate($configFile, $cwd, $first = true);
227
            } catch (\InvalidArgumentException $exception) {
228
                $lastException = $exception;
229
            }
230
        }
231
        throw $lastException;
232
    }
233
234
    /**
235
     * Parse the config file and load it into the config object
236
     *
237
     * @param \Symfony\Component\Console\Input\InputInterface $input
238
     * @param \Symfony\Component\Console\Output\OutputInterface $output
239
     * @throws \InvalidArgumentException
240
     * @return void
241
     */
242
    protected function loadConfig(InputInterface $input, OutputInterface $output)
243
    {
244
        $configFilePath = $this->locateConfigFile($input);
245
        $output->writeln('<info>using config file</info> .' . str_replace(getcwd(), '', realpath($configFilePath)));
246
247
        $parser = $input->getOption('parser');
248
249
        // If no parser is specified try to determine the correct one from the file extension.  Defaults to YAML
250
        if ($parser === null) {
251
            $extension = pathinfo($configFilePath, PATHINFO_EXTENSION);
252
253
            switch (strtolower($extension)) {
254
                case 'json':
255
                    $parser = 'json';
256
                    break;
257
                case 'php':
258
                    $parser = 'php';
259
                    break;
260
                case 'yml':
261
                default:
262
                    $parser = 'yaml';
263
            }
264
        }
265
266
        switch (strtolower($parser)) {
267
            case 'json':
268
                $config = Config::fromJson($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 244 can also be of type array; however, Phinx\Config\Config::fromJson() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
269
                break;
270
            case 'php':
271
                $config = Config::fromPhp($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 244 can also be of type array; however, Phinx\Config\Config::fromPhp() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
272
                break;
273
            case 'yaml':
274
                $config = Config::fromYaml($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 244 can also be of type array; however, Phinx\Config\Config::fromYaml() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
275
                break;
276
            default:
277
                throw new \InvalidArgumentException(sprintf('\'%s\' is not a valid parser.', $parser));
278
        }
279
280
        $output->writeln('<info>using config parser</info> ' . $parser);
281
282
        $this->setConfig($config);
283 32
    }
284
285 32
    /**
286
     * Load the migrations manager and inject the config
287
     *
288
     * @param \Symfony\Component\Console\Input\InputInterface $input
289 32
     * @param \Symfony\Component\Console\Output\OutputInterface $output
290 32
     */
291 32
    protected function loadManager(InputInterface $input, OutputInterface $output)
292
    {
293 32
        if ($this->getManager() === null) {
294
            $manager = new Manager($this->getConfig(), $input, $output);
295
            $this->setManager($manager);
296
        } else {
297
            $manager = $this->getManager();
298
            $manager->setInput($input);
299
            $manager->setOutput($output);
300
        }
301
    }
302 13
303
    /**
304 13
     * Verify that the migration directory exists and is writable.
305
     *
306
     * @param string $path
307
     * @throws \InvalidArgumentException
308
     * @return void
309
     */
310 View Code Duplication
    protected function verifyMigrationDirectory($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311 13
    {
312
        if (!is_dir($path)) {
313
            throw new \InvalidArgumentException(sprintf(
314
                'Migration directory "%s" does not exist',
315
                $path
316
            ));
317 13
        }
318
319
        if (!is_writable($path)) {
320
            throw new \InvalidArgumentException(sprintf(
321
                'Migration directory "%s" is not writable',
322
                $path
323
            ));
324
        }
325
    }
326 2
327
    /**
328 2
     * Verify that the seed directory exists and is writable.
329
     *
330
     * @param string $path
331
     * @throws \InvalidArgumentException
332
     * @return void
333
     */
334 View Code Duplication
    protected function verifySeedDirectory($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
335 2
    {
336
        if (!is_dir($path)) {
337
            throw new \InvalidArgumentException(sprintf(
338
                'Seed directory "%s" does not exist',
339
                $path
340
            ));
341 2
        }
342
343
        if (!is_writable($path)) {
344
            throw new \InvalidArgumentException(sprintf(
345
                'Seed directory "%s" is not writable',
346
                $path
347
            ));
348 2
        }
349
    }
350 2
351
    /**
352
     * Returns the migration template filename.
353
     *
354
     * @return string
355
     */
356
    protected function getMigrationTemplateFilename()
357
    {
358 1
        return __DIR__ . self::DEFAULT_MIGRATION_TEMPLATE;
359
    }
360 1
361
    /**
362
     * Returns the seed template filename.
363
     *
364
     * @return string
365
     */
366
    protected function getSeedTemplateFilename()
367
    {
368
        return __DIR__ . self::DEFAULT_SEED_TEMPLATE;
369
    }
370
}
371