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

namespace Doctrine\ORM\Tools\Cli\Tasks;

5
use Doctrine\Common\DoctrineException,
6 7
    Doctrine\Common\Cli\Option,
    Doctrine\Common\Cli\OptionGroup,
8
    Doctrine\ORM\Tools\SchemaTool,
9 10 11 12 13 14 15 16 17 18
    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:
 * 
19
 * <tt>--class-dir=<path></tt>
20 21 22 23 24
 * 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>
25 26
 * Specifies that instead of directly executing the SQL statements,
 * they should be printed to the standard output.
27 28 29 30 31 32 33 34 35 36 37
 * 
 * <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.
 * 
 * 
38 39 40 41 42 43 44
 * @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>
45 46 47 48 49 50
 */
class SchemaToolTask extends AbstractTask
{
    /**
     * @inheritdoc
     */
51 52 53 54 55 56 57 58 59
    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(
60
                'drop', null,
61
                'Drops the schema of EntityManager (drop tables on Database).' . PHP_EOL .
62 63
                'Beware that the complete database is dropped by this command, '.PHP_EOL.
                'even tables that are not relevant to your metadata model.' . PHP_EOL .
64 65 66
                'If defined, --create, --update and --re-create can not be requested on same task.'
            ),
            new Option(
67
                'update', null,
68
                'Updates the schema in EntityManager (update tables on Database).' . PHP_EOL .
69 70 71 72 73 74 75 76
                '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.'
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
            ),
            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);
    }
    
98 99 100 101 102 103 104 105
    /**
     * @inheritdoc
     */
    public function validate()
    {
        $args = $this->getArguments();
        $printer = $this->getPrinter();
        
106 107 108 109 110
        if (array_key_exists('re-create', $args)) {
            $args['drop'] = true;
            $args['create'] = true;
            $this->setArguments($args);
        }
111 112 113 114
        
        $isCreate = isset($args['create']);
        $isDrop = isset($args['drop']);
        $isUpdate = isset($args['update']);
115
        $isCompleteUpdate = isset($args['complete-update']);
116
        
117 118 119 120 121 122 123
        if ($isUpdate && ($isCreate || $isDrop || $isCompleteUpdate)) {
            $printer->writeln("You can't use --update with --create, --drop or --complete-update", 'ERROR');
            return false;
        }

        if ($isCompleteUpdate && ($isCreate || $isDrop || $isUpdate)) {
            $printer->writeln("You can't use --update with --create, --drop or --update", 'ERROR');
124 125
            return false;
        }
126

127 128
        if ( ! ($isCreate || $isDrop || $isUpdate || $isCompleteUpdate)) {
            $printer->writeln('You must specify at a minimum one of the options (--create, --drop, --update, --re-create, --complete-update).', 'ERROR');
129 130
            return false;
        }
131
        
132 133
        $metadataDriver = $this->getEntityManager()->getConfiguration()->getMetadataDriverImpl();
        
134 135 136 137 138 139 140 141
        if ($metadataDriver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
            if ( ! isset($args['class-dir'])) {
                $printer->writeln("The supplied configuration uses the annotation metadata driver."
                        . " The 'class-dir' argument is required for this driver.", 'ERROR');
                return false;
            } else {
                $metadataDriver->setClassDirectory($args['class-dir']);
            }
142 143 144 145 146 147 148 149 150 151 152
        }
        
        return true;
    }

    /**
     * Executes the task.
     */
    public function run()
    {
        $args = $this->getArguments();
153

154 155 156
        $isCreate = isset($args['create']);
        $isDrop = isset($args['drop']);
        $isUpdate = isset($args['update']);
157
        $isCompleteUpdate = isset($args['complete-update']);
158

159 160
        $em = $this->getEntityManager();
        $cmf = $em->getMetadataFactory();
161

162
        $classes = $cmf->getAllMetadata();
163

164 165
        $printer = $this->getPrinter();
        
166 167 168 169
        if (empty($classes)) {
            $printer->writeln('No classes to process.', 'INFO');
            return;
        }
170

171 172
        $tool = new SchemaTool($em);
        
173
        if ($isDrop) {
174
            if (isset($args['dump-sql'])) {
175
                foreach ($tool->getDropSchemaSql($classes) as $sql) {
176
                    $printer->writeln($sql);
177 178
                }
            } else {
179
                $printer->writeln('Dropping database schema...', 'INFO');
180 181
                
                try {
182
                    $tool->dropSchema($classes);
183
                    $printer->writeln('Database schema dropped successfully.', 'INFO');
184
                } catch (\Exception $ex) {
185
                    throw new DoctrineException($ex);
186
                }
187
            }
188 189 190
        }

        if ($isCreate) {
191
            if (isset($args['dump-sql'])) {
192
                foreach ($tool->getCreateSchemaSql($classes) as $sql) {
193
                    $printer->writeln($sql);
194 195
                }
            } else {
196
                $printer->writeln('Creating database schema...', 'INFO');
197 198
                
                try {
199 200
                    $tool->createSchema($classes);
                    $printer->writeln('Database schema created successfully.', 'INFO');
201
                } catch (\Exception $ex) {
202
                    throw new DoctrineException($ex);
203
                }
204
            }
205 206
        }

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