0

Final Class Yiisoft\Db\Migration\Command\CreateCommand

InheritanceYiisoft\Db\Migration\Command\CreateCommand » Yiisoft\Db\Migration\Command\DatabaseCommand » Symfony\Component\Console\Command\Command

Creates a new migration.

This command creates a new migration using the available migration template.

To use it, configure migrations paths (newMigrationPath and sourcePaths) in params.php file, in your application.

'yiisoft/db-migration' => [
    'newMigrationNamespace' => '',
    'newMigrationPath' => '',
    'sourceNamespaces' => [],
    'sourcePaths' => [],
],

After using this command, developers should modify the created migration skeleton by filling up the actual migration logic.

./yii migrate:create table --command=table

To generate a namespaced migration, you should specify a namespace before the migration's name.

Note that backslash (\) is usually considered a special character in the shell, so you need to escape it properly to avoid shell errors or incorrect behavior.

For example:

./yii migrate:create post --command=table --namespace=Yiisoft\\Db\\Migration\\Migration
./yii migrate:create post --command=table --path=@root/migrations/blog

In case {@see \Yiisoft\Db\Migration\Service\MigrationService::$newMigrationPath} is not set, and no namespace is provided, {@see \Yiisoft\Db\Migration\Service\MigrationService::$newMigrationNamespace} will be used.

Constants

Hide inherited constants

Constant Value Description Defined By
AVAILABLE_COMMANDS [ 'create', 'table', 'dropTable', 'addColumn', 'dropColumn', 'junction', ] Yiisoft\Db\Migration\Command\CreateCommand

Method Details

Hide inherited methods

__construct() public method

public mixed __construct ( Yiisoft\Db\Migration\Service\Generate\CreateService $createService, Yiisoft\Db\Migration\Service\MigrationService $migrationService, Yiisoft\Db\Migration\Migrator $migrator, ?\Yiisoft\Db\Migration\DatabaseRegistry $additionalDatabases = null )
$createService Yiisoft\Db\Migration\Service\Generate\CreateService
$migrationService Yiisoft\Db\Migration\Service\MigrationService
$migrator Yiisoft\Db\Migration\Migrator
$additionalDatabases ?\Yiisoft\Db\Migration\DatabaseRegistry

                public function __construct(
    private readonly CreateService $createService,
    private readonly MigrationService $migrationService,
    private readonly Migrator $migrator,
    ?DatabaseRegistry $additionalDatabases = null,
) {
    parent::__construct($additionalDatabases);
}

            
configure() protected method

protected void configure ( )

                protected function configure(): void
{
    $this
        ->addArgument('name', InputArgument::REQUIRED, 'Table name to generate migration for.')
        ->addOption('command', 'c', InputOption::VALUE_REQUIRED, 'Command to execute.', 'create')
        ->addOption('fields', 'f', InputOption::VALUE_REQUIRED, 'Table fields to generate.')
        ->addOption('table-comment', null, InputOption::VALUE_REQUIRED, 'Table comment.')
        ->addOption('and', null, InputOption::VALUE_REQUIRED, 'And junction.')
        ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Path to migration directory.')
        ->addOption('namespace', 'ns', InputOption::VALUE_REQUIRED, 'Migration file namespace.')
        ->addOption(
            'transactional',
            null,
            InputOption::VALUE_NEGATABLE,
            'Generate a transactional migration. If omitted, use the configured mode or template default.',
        )
        ->setHelp('This command generates new migration file.');
}

            
createContext() protected method

protected Yiisoft\Db\Migration\Command\Context\CreateContext createContext ( Yiisoft\Db\Migration\DatabaseSetup $setup )
$setup Yiisoft\Db\Migration\DatabaseSetup

                protected function createContext(DatabaseSetup $setup): CreateContext
{
    return new CreateContext(
        $setup->migrator,
        $setup->migrationService,
        new CreateService(
            $setup->config->db,
            $setup->config->useTablePrefix,
            $setup->config->newMigrationTransactional,
        ),
    );
}

            
createDefaultContext() protected method

protected Yiisoft\Db\Migration\Command\Context\CreateContext createDefaultContext ( )

                protected function createDefaultContext(): CreateContext
{
    return new CreateContext($this->migrator, $this->migrationService, $this->createService);
}

            
execute() protected method
protected integer execute ( \Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output )
$input \Symfony\Component\Console\Input\InputInterface
$output \Symfony\Component\Console\Output\OutputInterface

                final protected function execute(InputInterface $input, OutputInterface $output): int
{
    $io = new SymfonyStyle($input, $output);
    $names = $this->resolveDatabaseNames($input);
    if (is_string($names)) {
        $io->error($names);
        return Command::INVALID;
    }
    $multipleDatabases = $this->isMultipleDatabases();
    $hasResults = false;
    foreach ($names as $name) {
        if (!$multipleDatabases || $name === DatabaseRegistry::DEFAULT_DATABASE) {
            $context = $this->createDefaultContext();
        } else {
            /** @psalm-var DatabaseRegistry $this->additionalDatabases */
            $context = $this->createContext($this->additionalDatabases->createSetup($name));
        }
        if ($multipleDatabases) {
            $io->section('Database: ' . OutputFormatter::escape($name));
        }
        $status = $this->executeForDatabase($input, $output, $context);
        if ($status === null) {
            continue;
        }
        if ($status !== Command::SUCCESS) {
            return $status;
        }
        $hasResults = true;
    }
    return $hasResults ? Command::SUCCESS : Command::FAILURE;
}

            
executeForDatabase() protected method

protected integer executeForDatabase ( \Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output, object $context )
$input \Symfony\Component\Console\Input\InputInterface
$output \Symfony\Component\Console\Output\OutputInterface
$context object

                protected function executeForDatabase(
    InputInterface $input,
    OutputInterface $output,
    object $context,
): int {
    $io = new SymfonyStyle($input, $output);
    $context->migrator->setIo($io);
    $context->migrationService->setIo($io);
    $context->createService->setIo($io);
    $context->migrationService->databaseConnection();
    /** @var string|null $path */
    $path = $input->getOption('path');
    /** @var string|null $namespace */
    $namespace = $input->getOption('namespace');
    if ($path !== null || $namespace !== null) {
        $context->migrationService->setNewMigrationPath((string) $path);
        $context->migrationService->setNewMigrationNamespace((string) $namespace);
    } else {
        $namespace = $context->migrationService->getNewMigrationNamespace();
    }
    if ($context->migrationService->before($this->getName() ?? '') === Command::INVALID) {
        return Command::INVALID;
    }
    /** @var string $table */
    $table = $input->getArgument('name');
    if (!preg_match('/^[\w\\\\]+$/', $table)) {
        $io->error(
            'The migration name should contain letters, digits, underscore and/or backslash characters only.',
        );
        return Command::INVALID;
    }
    /** @var string $command */
    $command = $input->getOption('command');
    if (!in_array($command, self::AVAILABLE_COMMANDS, true)) {
        $io->error(
            "Command not found \"$command\". Available commands: " . implode(', ', self::AVAILABLE_COMMANDS) . '.',
        );
        return Command::INVALID;
    }
    /** @var string|null $and */
    $and = $input->getOption('and');
    $name = $this->generateName($command, $table, $and);
    $className = $context->migrationService->generateClassName($name);
    $nameLimit = $context->migrator->getMigrationNameLimit();
    if ($nameLimit !== 0 && strlen($className) > $nameLimit) {
        $io->error('The migration name is too long.');
        return Command::INVALID;
    }
    try {
        $migrationPath = $context->migrationService->findMigrationPath();
    } catch (LogicException $e) {
        $io->error($e->getMessage());
        return Command::INVALID;
    }
    if (!is_dir($migrationPath)) {
        $io->error("Invalid path directory \"$migrationPath\"");
        return Command::INVALID;
    }
    /** @var string|null $fields */
    $fields = $input->getOption('fields');
    /** @var string|null $tableComment */
    $tableComment = $input->getOption('table-comment');
    /** @var bool|null $transactional */
    $transactional = $input->getOption('transactional');
    $content = $context->createService->run(
        $command,
        $table,
        $className,
        $namespace,
        $fields,
        $and,
        $tableComment,
        $transactional,
    );
    $file = $migrationPath . DIRECTORY_SEPARATOR . $className . '.php';
    file_put_contents($file, $content, LOCK_EX);
    $output->writeln("\n\t<info>$className</info>");
    $output->writeln("\n");
    $io->success('New migration created successfully.');
    return Command::SUCCESS;
}

            
getAvailableDatabaseNames() protected method
protected string[] getAvailableDatabaseNames ( )

                protected function getAvailableDatabaseNames(): array
{
    return [DatabaseRegistry::DEFAULT_DATABASE, ...($this->additionalDatabases?->getNames() ?? [])];
}

            
isMultipleDatabases() protected method
protected boolean isMultipleDatabases ( )

                protected function isMultipleDatabases(): bool
{
    return $this->additionalDatabases !== null && $this->additionalDatabases->getNames() !== [];
}

            
resolveDatabaseNamesWithMissingOption() protected method

protected array resolveDatabaseNamesWithMissingOption ( \Symfony\Component\Console\Input\InputInterface $input )
$input \Symfony\Component\Console\Input\InputInterface

                protected function resolveDatabaseNamesWithMissingOption(InputInterface $input): array
{
    return [DatabaseRegistry::DEFAULT_DATABASE];
}