Create.php
7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<?php
// +----------------------------------------------------------------------
// | TopThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015 http://www.topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\migration\command\migrate;
use Phinx\Migration\CreationInterface;
use Phinx\Util;
use think\console\input\Argument as InputArgument;
use think\console\Input;
use think\console\input\Option as InputOption;
use think\console\Output;
use think\migration\command\AbstractCommand;
class Create extends AbstractCommand
{
/**
* The name of the interface that any external template creation class is required to implement.
*/
const CREATION_INTERFACE = 'Phinx\Migration\CreationInterface';
/**
* {@inheritdoc}
*/
protected function configure()
{
parent::configure();
$this->setName('migrate:create')
->setDescription('Create a new migration')
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the migration?')
->setHelp(sprintf(
'%sCreates a new database migration%s',
PHP_EOL,
PHP_EOL
));
// An alternative template.
$this->addOption('template', 't', InputOption::VALUE_REQUIRED, 'Use an alternative template');
// A classname to be used to gain access to the template content as well as the ability to
// have a callback once the migration file has been created.
$this->addOption('class', 'l', InputOption::VALUE_REQUIRED, 'Use a class implementing "' . self::CREATION_INTERFACE . '" to generate the template');
}
/**
* Create the new migration.
*
* @param Input $input
* @param Output $output
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return void
*/
protected function execute(Input $input, Output $output)
{
$this->bootstrap($input, $output);
// get the migration path from the config
$path = $this->getConfig()->getMigrationPath();
if (!file_exists($path)) {
if ($output->confirm($input, 'Create migrations directory?')) {
mkdir($path, 0755, true);
}
}
$this->verifyMigrationDirectory($path);
$path = realpath($path);
$className = $input->getArgument('name');
if (!Util::isValidPhinxClassName($className)) {
throw new \InvalidArgumentException(sprintf(
'The migration class name "%s" is invalid. Please use CamelCase format.',
$className
));
}
if (!Util::isUniqueMigrationClassName($className, $path)) {
throw new \InvalidArgumentException(sprintf(
'The migration class name "%s" already exists',
$className
));
}
// Compute the file path
$fileName = Util::mapClassNameToFileName($className);
$filePath = $path . DIRECTORY_SEPARATOR . $fileName;
if (is_file($filePath)) {
throw new \InvalidArgumentException(sprintf(
'The file "%s" already exists',
$filePath
));
}
// Get the alternative template and static class options, but only allow one of them.
$altTemplate = $input->getOption('template');
if (!$altTemplate) {
$altTemplate = $this->getConfig()->getMigrationTemplateFile();
}
$creationClassName = $input->getOption('class');
if (!$creationClassName) {
$creationClassName = $this->getConfig()->getMigrationTemplateClass();
}
if ($altTemplate && $creationClassName) {
throw new \InvalidArgumentException('Cannot use --template and --class at the same time');
}
// Verify the alternative template file's existence.
if ($altTemplate && !is_file($altTemplate)) {
throw new \InvalidArgumentException(sprintf(
'The alternative template file "%s" does not exist',
$altTemplate
));
}
// Verify that the template creation class (or the aliased class) exists and that it implements the required interface.
$aliasedClassName = null;
if ($creationClassName) {
// Supplied class does not exist, is it aliased?
if (!class_exists($creationClassName)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" does not exist',
$creationClassName
));
}
// Does the class implement the required interface?
if (!is_subclass_of($creationClassName, self::CREATION_INTERFACE)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" does not implement the required interface "%s"',
$creationClassName,
self::CREATION_INTERFACE
));
}
}
// Determine the appropriate mechanism to get the template
if ($creationClassName) {
// Get the template from the creation class
/** @var CreationInterface $creationClass */
$creationClass = new $creationClassName();
$contents = $creationClass->getMigrationTemplate();
} else {
// Load the alternative template if it is defined.
$contents = file_get_contents($altTemplate ?: $this->getMigrationTemplateFilename());
}
// inject the class names appropriate to this migration
$classes = [
'$useClassName' => $this->getConfig()->getMigrationBaseClassName(false),
'$className' => $className,
'$version' => Util::getVersionFromFileName($fileName),
'$baseClassName' => $this->getConfig()->getMigrationBaseClassName(true),
];
$contents = strtr($contents, $classes);
if (false === file_put_contents($filePath, $contents)) {
throw new \RuntimeException(sprintf(
'The file "%s" could not be written to',
$path
));
}
// Do we need to do the post creation call to the creation class?
if ($creationClassName) {
/** @var CreationInterface $creationClass */
$creationClass->postMigrationCreation($filePath, $className, $this->getConfig()->getMigrationBaseClassName());
}
$output->writeln('<info>using migration base class</info> ' . $classes['$useClassName']);
if (!empty($altTemplate)) {
$output->writeln('<info>using alternative template</info> ' . $altTemplate);
} elseif (!empty($creationClassName)) {
$output->writeln('<info>using template creation class</info> ' . $creationClassName);
} else {
$output->writeln('<info>using default template</info>');
}
$output->writeln('<info>created</info> .' . str_replace(getcwd(), '', $filePath));
}
}