Completed
Pull Request — master (#1390)
by
unknown
02:31
created

AbstractCommand::loadManager()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.3149

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 4
cts 7
cp 0.5714
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.3149
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
        // report the paths
99 32
        $paths = $this->getConfig()->getMigrationPaths();
100
101 32
        $output->writeln('<info>using migration paths</info> ');
102
103 32
        foreach (Util::globAll($paths) as $path) {
104 32
            $output->writeln('<info> - ' . realpath($path) . '</info>');
105 32
        }
106
107
        try {
108 32
            $paths = $this->getConfig()->getSeedPaths();
109
110 6
            $output->writeln('<info>using seed paths</info> ');
111
112 6
            foreach (Util::globAll($paths) as $path) {
113 6
                $output->writeln('<info> - ' . realpath($path) . '</info>');
114 6
            }
115 32
        } catch (\UnexpectedValueException $e) {
116
            // do nothing as seeds are optional
117
        }
118 32
    }
119
120
    /**
121
     * Sets the config.
122
     *
123
     * @param  \Phinx\Config\ConfigInterface $config
124
     * @return \Phinx\Console\Command\AbstractCommand
125
     */
126 32
    public function setConfig(ConfigInterface $config)
127
    {
128 32
        $this->config = $config;
129 32
130
        return $this;
131
    }
132
133
    /**
134
     * Gets the config.
135
     *
136
     * @return \Phinx\Config\ConfigInterface
137 32
     */
138
    public function getConfig()
139 32
    {
140
        return $this->config;
141
    }
142
143
    /**
144
     * Sets the database adapter.
145
     *
146
     * @param \Phinx\Db\Adapter\AdapterInterface $adapter
147
     * @return \Phinx\Console\Command\AbstractCommand
148
     */
149
    public function setAdapter(AdapterInterface $adapter)
150
    {
151
        $this->adapter = $adapter;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Gets the database adapter.
158
     *
159
     * @return \Phinx\Db\Adapter\AdapterInterface
160
     */
161
    public function getAdapter()
162
    {
163
        return $this->adapter;
164
    }
165
166
    /**
167
     * Sets the migration manager.
168
     *
169
     * @param \Phinx\Migration\Manager $manager
170 32
     * @return \Phinx\Console\Command\AbstractCommand
171
     */
172 32
    public function setManager(Manager $manager)
173 32
    {
174
        $this->manager = $manager;
175
176
        return $this;
177
    }
178
179
    /**
180
     * Gets the migration manager.
181 32
     *
182
     * @return \Phinx\Migration\Manager|null
183 32
     */
184
    public function getManager()
185
    {
186
        return $this->manager;
187
    }
188
189
    /**
190
     * Returns config file path
191
     *
192 10
     * @param \Symfony\Component\Console\Input\InputInterface $input
193
     * @return string
194 10
     */
195
    protected function locateConfigFile(InputInterface $input)
196 10
    {
197
        $configFile = $input->getOption('configuration');
198 10
199 4
        $useDefault = false;
200 4
201
        if ($configFile === null || $configFile === false) {
202 10
            $useDefault = true;
203
        }
204
205
        $cwd = getcwd();
206 10
207
        // locate the phinx config file (default: phinx.yml)
208 10
        // TODO - In future walk the tree in reverse (max 10 levels)
209
        $locator = new FileLocator([
210 10
            $cwd . DIRECTORY_SEPARATOR
211
        ]);
212 6
213
        if (!$useDefault) {
214
            // Locate() throws an exception if the file does not exist
215 4
            return $locator->locate($configFile, $cwd, $first = true);
216 4
        }
217
218 4
        $possibleConfigFiles = ['phinx.php', 'phinx.json', 'phinx.yml'];
219 3
        foreach ($possibleConfigFiles as $configFile) {
220 3
            try {
221
                return $locator->locate($configFile, $cwd, $first = true);
222 3
            } catch (\InvalidArgumentException $exception) {
223 1
                $lastException = $exception;
224
            }
225
        }
226
        throw $lastException;
227
    }
228
229
    /**
230
     * Parse the config file and load it into the config object
231
     *
232
     * @param \Symfony\Component\Console\Input\InputInterface $input
233
     * @param \Symfony\Component\Console\Output\OutputInterface $output
234
     * @throws \InvalidArgumentException
235
     * @return void
236
     */
237
    protected function loadConfig(InputInterface $input, OutputInterface $output)
238
    {
239
        $configFilePath = $this->locateConfigFile($input);
240
        $output->writeln('<info>using config file</info> .' . str_replace(getcwd(), '', realpath($configFilePath)));
241
242
        $parser = $input->getOption('parser');
243
244
        // If no parser is specified try to determine the correct one from the file extension.  Defaults to YAML
245
        if ($parser === null) {
246
            $extension = pathinfo($configFilePath, PATHINFO_EXTENSION);
247
248
            switch (strtolower($extension)) {
249
                case 'json':
250
                    $parser = 'json';
251
                    break;
252
                case 'php':
253
                    $parser = 'php';
254
                    break;
255
                case 'yml':
256
                default:
257
                    $parser = 'yaml';
258
            }
259
        }
260
261
        switch (strtolower($parser)) {
262
            case 'json':
263
                $config = Config::fromJson($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 239 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...
264
                break;
265
            case 'php':
266
                $config = Config::fromPhp($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 239 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...
267
                break;
268
            case 'yaml':
269
                $config = Config::fromYaml($configFilePath);
0 ignored issues
show
Bug introduced by
It seems like $configFilePath defined by $this->locateConfigFile($input) on line 239 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...
270
                break;
271
            default:
272
                throw new \InvalidArgumentException(sprintf('\'%s\' is not a valid parser.', $parser));
273
        }
274
275
        $output->writeln('<info>using config parser</info> ' . $parser);
276
277
        $this->setConfig($config);
278
    }
279
280
    /**
281
     * Load the migrations manager and inject the config
282
     *
283 32
     * @param \Symfony\Component\Console\Input\InputInterface $input
284
     * @param \Symfony\Component\Console\Output\OutputInterface $output
285 32
     */
286
    protected function loadManager(InputInterface $input, OutputInterface $output)
287
    {
288
        if ($this->getManager() === null) {
289 32
            $manager = new Manager($this->getConfig(), $input, $output);
290 32
            $this->setManager($manager);
291 32
        } else {
292
            $manager = $this->getManager();
293 32
            $manager->setInput($input);
294
            $manager->setOutput($output);
295
        }
296
    }
297
298
    /**
299
     * Verify that the migration directory exists and is writable.
300
     *
301
     * @param string $path
302 13
     * @throws \InvalidArgumentException
303
     * @return void
304 13
     */
305 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...
306
    {
307
        if (!is_dir($path)) {
308
            throw new \InvalidArgumentException(sprintf(
309
                'Migration directory "%s" does not exist',
310
                $path
311 13
            ));
312
        }
313
314
        if (!is_writable($path)) {
315
            throw new \InvalidArgumentException(sprintf(
316
                'Migration directory "%s" is not writable',
317 13
                $path
318
            ));
319
        }
320
    }
321
322
    /**
323
     * Verify that the seed directory exists and is writable.
324
     *
325
     * @param string $path
326 2
     * @throws \InvalidArgumentException
327
     * @return void
328 2
     */
329 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...
330
    {
331
        if (!is_dir($path)) {
332
            throw new \InvalidArgumentException(sprintf(
333
                'Seed directory "%s" does not exist',
334
                $path
335 2
            ));
336
        }
337
338
        if (!is_writable($path)) {
339
            throw new \InvalidArgumentException(sprintf(
340
                'Seed directory "%s" is not writable',
341 2
                $path
342
            ));
343
        }
344
    }
345
346
    /**
347
     * Returns the migration template filename.
348 2
     *
349
     * @return string
350 2
     */
351
    protected function getMigrationTemplateFilename()
352
    {
353
        return __DIR__ . self::DEFAULT_MIGRATION_TEMPLATE;
354
    }
355
356
    /**
357
     * Returns the seed template filename.
358 1
     *
359
     * @return string
360 1
     */
361
    protected function getSeedTemplateFilename()
362
    {
363
        return __DIR__ . self::DEFAULT_SEED_TEMPLATE;
364
    }
365
}
366