Completed
Push — master ( ba3223...b47a39 )
by Luís
17s
created

Tools/Console/Command/ConvertMappingCommand.php (1 issue)

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Tools\Console\Command;
21
22
use Symfony\Component\Console\Input\InputArgument;
23
use Symfony\Component\Console\Input\InputOption;
24
use Doctrine\ORM\Tools\Console\MetadataFilter;
25
use Doctrine\ORM\Tools\Export\ClassMetadataExporter;
26
use Doctrine\ORM\Tools\EntityGenerator;
27
use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
28
use Doctrine\ORM\Mapping\Driver\DatabaseDriver;
29
use Symfony\Component\Console\Output\OutputInterface;
30
use Symfony\Component\Console\Input\InputInterface;
31
use Symfony\Component\Console\Command\Command;
32
33
/**
34
 * Command to convert your mapping information between the various formats.
35
 *
36
 * @link    www.doctrine-project.org
37
 * @since   2.0
38
 * @author  Benjamin Eberlei <[email protected]>
39
 * @author  Guilherme Blanco <[email protected]>
40
 * @author  Jonathan Wage <[email protected]>
41
 * @author  Roman Borschel <[email protected]>
42
 */
43
class ConvertMappingCommand extends Command
44
{
45
    /**
46
     * {@inheritdoc}
47
     */
48
    protected function configure()
49
    {
50
        $this
51
        ->setName('orm:convert-mapping')
52
        ->setAliases(['orm:convert:mapping'])
53
        ->setDescription('Convert mapping information between supported formats.')
54
        ->setDefinition(
55
            [
56
                new InputOption(
57
                    'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
58
                    'A string pattern used to match entities that should be processed.'
59
                ),
60
                new InputArgument(
61
                    'to-type', InputArgument::REQUIRED, 'The mapping type to be converted.'
62
                ),
63
                new InputArgument(
64
                    'dest-path', InputArgument::REQUIRED,
65
                    'The path to generate your entities classes.'
66
                ),
67
                new InputOption(
68
                    'force', 'f', InputOption::VALUE_NONE,
69
                    'Force to overwrite existing mapping files.'
70
                ),
71
                new InputOption(
72
                    'from-database', null, null, 'Whether or not to convert mapping information from existing database.'
73
                ),
74
                new InputOption(
75
                    'extend', null, InputOption::VALUE_OPTIONAL,
76
                    'Defines a base class to be extended by generated entity classes.'
77
                ),
78
                new InputOption(
79
                    'num-spaces', null, InputOption::VALUE_OPTIONAL,
80
                    'Defines the number of indentation spaces', 4
81
                ),
82
                new InputOption(
83
                    'namespace', null, InputOption::VALUE_OPTIONAL,
84
                    'Defines a namespace for the generated entity classes, if converted from database.'
85
                ),
86
            ]
87
        )
88
        ->setHelp(<<<EOT
89
Convert mapping information between supported formats.
90
91
This is an execute <info>one-time</info> command. It should not be necessary for
92
you to call this method multiple times, especially when using the <comment>--from-database</comment>
93
flag.
94
95
Converting an existing database schema into mapping files only solves about 70-80%
96
of the necessary mapping information. Additionally the detection from an existing
97
database cannot detect inverse associations, inheritance types,
98
entities with foreign keys as primary keys and many of the
99
semantical operations on associations such as cascade.
100
101
<comment>Hint:</comment> There is no need to convert YAML or XML mapping files to annotations
102
every time you make changes. All mapping drivers are first class citizens
103
in Doctrine 2 and can be used as runtime mapping for the ORM.
104
105
<comment>Hint:</comment> If you have a database with tables that should not be managed
106
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
107
on a global level:
108
109
    \$config->setFilterSchemaAssetsExpression(\$regexp);
110
EOT
111
        );
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117
    protected function execute(InputInterface $input, OutputInterface $output)
118
    {
119
        $em = $this->getHelper('em')->getEntityManager();
120
121
        if ($input->getOption('from-database') === true) {
122
            $databaseDriver = new DatabaseDriver(
123
                $em->getConnection()->getSchemaManager()
124
            );
125
126
            $em->getConfiguration()->setMetadataDriverImpl(
127
                $databaseDriver
128
            );
129
130
            if (($namespace = $input->getOption('namespace')) !== null) {
131
                $databaseDriver->setNamespace($namespace);
132
            }
133
        }
134
135
        $cmf = new DisconnectedClassMetadataFactory();
136
        $cmf->setEntityManager($em);
137
        $metadata = $cmf->getAllMetadata();
138
        $metadata = MetadataFilter::filter($metadata, $input->getOption('filter'));
139
140
        // Process destination directory
141
        if ( ! is_dir($destPath = $input->getArgument('dest-path'))) {
142
            mkdir($destPath, 0775, true);
143
        }
144
        $destPath = realpath($destPath);
145
146
        if ( ! file_exists($destPath)) {
147
            throw new \InvalidArgumentException(
148
                sprintf("Mapping destination directory '<info>%s</info>' does not exist.", $input->getArgument('dest-path'))
149
            );
150
        }
151
152
        if ( ! is_writable($destPath)) {
153
            throw new \InvalidArgumentException(
154
                sprintf("Mapping destination directory '<info>%s</info>' does not have write permissions.", $destPath)
155
            );
156
        }
157
158
        $toType = strtolower($input->getArgument('to-type'));
159
160
        $exporter = $this->getExporter($toType, $destPath);
161
        $exporter->setOverwriteExistingFiles($input->getOption('force'));
162
163
        if ($toType == 'annotation') {
164
            $entityGenerator = new EntityGenerator();
165
            $exporter->setEntityGenerator($entityGenerator);
166
167
            $entityGenerator->setNumSpaces($input->getOption('num-spaces'));
168
169
            if (($extend = $input->getOption('extend')) !== null) {
170
                $entityGenerator->setClassToExtend($extend);
171
            }
172
        }
173
174 View Code Duplication
        if (count($metadata)) {
0 ignored issues
show
This code seems to be duplicated across 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...
175
            foreach ($metadata as $class) {
176
                $output->writeln(sprintf('Processing entity "<info>%s</info>"', $class->name));
177
            }
178
179
            $exporter->setMetadata($metadata);
180
            $exporter->export();
181
182
            $output->writeln(PHP_EOL . sprintf(
183
                'Exporting "<info>%s</info>" mapping information to "<info>%s</info>"', $toType, $destPath
184
            ));
185
        } else {
186
            $output->writeln('No Metadata Classes to process.');
187
        }
188
    }
189
190
    /**
191
     * @param string $toType
192
     * @param string $destPath
193
     *
194
     * @return \Doctrine\ORM\Tools\Export\Driver\AbstractExporter
195
     */
196
    protected function getExporter($toType, $destPath)
197
    {
198
        $cme = new ClassMetadataExporter();
199
200
        return $cme->getExporter($toType, $destPath);
201
    }
202
}
203