SchemaToolTask.php 8.55 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\ORM\Tools\Cli\Tasks;

5 6
use Doctrine\Common\Cli\Tasks\AbstractTask,
    Doctrine\Common\Cli\CliException,
7 8
    Doctrine\Common\Cli\Option,
    Doctrine\Common\Cli\OptionGroup,
9
    Doctrine\ORM\Tools\SchemaTool,
10 11 12 13 14 15 16 17 18 19
    Doctrine\Common\Annotations\AnnotationReader,
    Doctrine\ORM\Mapping\Driver\AnnotationDriver,
    Doctrine\ORM\Mapping\Driver\XmlDriver,
    Doctrine\ORM\Mapping\Driver\YamlDriver;

/**
 * Task to create the database schema for a set of classes based on their mappings.
 * 
 * This task has the following arguments:
 * 
20
 * <tt>--class-dir=<path></tt>
21 22 23 24 25
 * Specifies the directory where to start looking for mapped classes.
 * This argument is required when the annotation metadata driver is used,
 * otherwise it has no effect.
 * 
 * <tt>--dump-sql</tt>
26 27
 * Specifies that instead of directly executing the SQL statements,
 * they should be printed to the standard output.
28 29 30 31 32 33 34 35 36 37 38
 * 
 * <tt>--create</tt>
 * Specifies that the schema of the classes should be created.
 * 
 * <tt>--drop</tt>
 * Specifies that the schema of the classes should be dropped.
 * 
 * <tt>--update</tt>
 * Specifies that the schema of the classes should be updated.
 * 
 * 
39 40 41 42 43 44 45
 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link    www.doctrine-project.org
 * @since   2.0
 * @version $Revision: 3938 $
 * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author  Jonathan Wage <jonwage@gmail.com>
 * @author  Roman Borschel <roman@code-factory.org>
46 47 48 49 50 51
 */
class SchemaToolTask extends AbstractTask
{
    /**
     * @inheritdoc
     */
52 53 54 55 56 57 58 59 60
    public function buildDocumentation()
    {
        $schemaOption = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
            new Option(
                'create', null, 
                'Creates the schema in EntityManager (create tables on Database).' . PHP_EOL .
                'If defined, --drop, --update and --re-create can not be requested on same task.'
            ),
            new Option(
61
                'drop', null,
62
                'Drops the schema of EntityManager (drop tables on Database).' . PHP_EOL .
63 64
                'Beware that the complete database is dropped by this command, '.PHP_EOL.
                'even tables that are not relevant to your metadata model.' . PHP_EOL .
65 66 67
                'If defined, --create, --update and --re-create can not be requested on same task.'
            ),
            new Option(
68
                'update', null,
69
                'Updates the schema in EntityManager (update tables on Database).' . PHP_EOL .
70 71 72 73 74 75 76 77
                'This command does a save update, which does not delete any tables, sequences or affected foreign keys.' . PHP_EOL .
                'If defined, --create, --drop and --complete-update --re-create can not be requested on same task.'
            ),
            new Option(
                'complete-update', null,
                'Updates the schema in EntityManager (update tables on Database).' . PHP_EOL .
                'Beware that all assets of the database which are not relevant to the current metadata are dropped by this command.'.PHP_EOL.
                'If defined, --create, --drop and --update --re-create can not be requested on same task.'
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
            ),
            new Option(
                're-create', null, 
                'Runs --drop then --create to re-create the database.' . PHP_EOL .
                'If defined, --create, --update and --drop can not be requested on same task.'
            )
        ));
        
        $optionalOptions = new OptionGroup(OptionGroup::CARDINALITY_0_N, array(
            new Option('dump-sql', null, 'Instead of try to apply generated SQLs into EntityManager, output them.'),
            new Option('class-dir', '<PATH>', 'Optional class directory to fetch for Entities.')
        ));
        
        $doc = $this->getDocumentation();
        $doc->setName('schema-tool')
            ->setDescription('Processes the schema and either apply it directly on EntityManager or generate the SQL output.')
            ->getOptionGroup()
                ->addOption($schemaOption)
                ->addOption($optionalOptions);
    }
    
99 100 101 102 103
    /**
     * @inheritdoc
     */
    public function validate()
    {
104 105 106 107 108 109 110 111
        $arguments = $this->getArguments();
        $em = $this->getConfiguration()->getAttribute('em');
        
        if ($em === null) {
            throw new CliException(
                "Attribute 'em' of CLI Configuration is not defined or it is not a valid EntityManager."
            );
        }
112
        
113 114 115 116 117 118 119
        if (isset($arguments['re-create'])) {
            $arguments['drop'] = true;
            $arguments['create'] = true;
            
            unset($arguments['re-create']);
            
            $this->setArguments($arguments);
120
        }
121
        
122 123 124 125
        $isCreate = isset($arguments['create']) && $arguments['create'];
        $isDrop = isset($arguments['drop']) && $arguments['drop'];
        $isUpdate = isset($arguments['update']) && $arguments['update'];
        $isCompleteUpdate = isset($arguments['complete-update']) && $arguments['complete-update'];
126
        
127
        if ($isUpdate && ($isCreate || $isDrop || $isCompleteUpdate)) {
128 129 130
            throw new CliException(
                'You cannot use --update with --create, --drop or --complete-update.'
            );
131 132 133
        }

        if ($isCompleteUpdate && ($isCreate || $isDrop || $isUpdate)) {
134
            throw new CliException('You cannot use --complete-update with --create, --drop or --update.');
135
        }
136

137
        if ( ! ($isCreate || $isDrop || $isUpdate || $isCompleteUpdate)) {
138
            throw new CliException(
139 140
                'You must specify at a minimum one of the options: ' .
                '--create, --drop, --update, --re-create or --complete-update.'
141
            );
142
        }
143
        
144
        $metadataDriver = $em->getConfiguration()->getMetadataDriverImpl();
145
        
146
        if ($metadataDriver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
147
            if (isset($arguments['class-dir'])) {
148
                $metadataDriver->addPaths((array) $arguments['class-dir']);
149 150 151 152 153
            } else {
                throw new CliException(
                    'The supplied configuration uses the annotation metadata driver. ' . 
                    "The 'class-dir' argument is required for this driver."
                );
154
            }
155 156 157 158 159 160
        }
        
        return true;
    }

    /**
161
     * @inheritdoc
162 163 164
     */
    public function run()
    {
165 166
        $arguments = $this->getArguments();
        $printer = $this->getPrinter();
167

168 169 170 171 172 173 174
        $isCreate = isset($arguments['create']) && $arguments['create'];
        $isDrop = isset($arguments['drop']) && $arguments['drop'];
        $isUpdate = isset($arguments['update']) && $arguments['update'];
        $isCompleteUpdate = isset($arguments['complete-update']) && $arguments['complete-update'];
        
        $em = $this->getConfiguration()->getAttribute('em');
        
175
        $cmf = $em->getMetadataFactory();
176
        $classes = $cmf->getAllMetadata();
177
        
178 179
        if (empty($classes)) {
            $printer->writeln('No classes to process.', 'INFO');
180
            
181 182
            return;
        }
183

184 185
        $tool = new SchemaTool($em);
        
186
        if ($isDrop) {
187
            if (isset($arguments['dump-sql'])) {
188
                foreach ($tool->getDropSchemaSql($classes) as $sql) {
189
                    $printer->writeln($sql);
190 191
                }
            } else {
192
                $printer->writeln('Dropping database schema...', 'INFO');
193 194
                $tool->dropSchema($classes);
                $printer->writeln('Database schema dropped successfully.', 'INFO');
195
            }
196 197 198
        }

        if ($isCreate) {
199
            if (isset($arguments['dump-sql'])) {
200
                foreach ($tool->getCreateSchemaSql($classes) as $sql) {
201
                    $printer->writeln($sql);
202 203
                }
            } else {
204
                $printer->writeln('Creating database schema...', 'INFO');
205 206
                $tool->createSchema($classes);
                $printer->writeln('Database schema created successfully.', 'INFO');
207
            }
208 209
        }

210
        if ($isUpdate || $isCompleteUpdate) {
211 212 213
            $saveMode = $isUpdate ? true : false;
            
            if (isset($arguments['dump-sql'])) {
214
                foreach ($tool->getUpdateSchemaSql($classes, $saveMode) as $sql) {
215 216 217 218
                    $printer->writeln($sql);
                }
            } else {
                $printer->writeln('Updating database schema...', 'INFO');
219 220
                $tool->updateSchema($classes, $saveMode);
                $printer->writeln('Database schema updated successfully.', 'INFO');
221
            }
222 223 224
        }
    }
}