From 5854bcab11ed8101d0f3c7e798fd669f17abab38 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Thu, 8 Apr 2010 00:47:42 -0300 Subject: [PATCH] [2.0] Added new Console support --- .../Tools/Console/Command/ImportCommand.php | 127 +++++++++++++ .../Tools/Console/Command/RunSqlCommand.php | 87 +++++++++ .../Tools/Console/Helper/ConnectionHelper.php | 74 ++++++++ .../Command/ClearCache/MetadataCommand.php | 81 +++++++++ .../Command/ClearCache/QueryCommand.php | 81 +++++++++ .../Command/ClearCache/ResultCommand.php | 164 +++++++++++++++++ .../Command/ConvertDoctrine1SchemaCommand.php | 154 ++++++++++++++++ .../Console/Command/ConvertMappingCommand.php | 165 +++++++++++++++++ .../EnsureProductionSettingsCommand.php | 76 ++++++++ .../Command/GenerateEntitiesCommand.php | 167 +++++++++++++++++ .../Command/GenerateProxiesCommand.php | 136 ++++++++++++++ .../Command/GenerateRepositoriesCommand.php | 171 ++++++++++++++++++ .../Tools/Console/Command/RunDqlCommand.php | 124 +++++++++++++ .../Command/SchemaTool/CreateCommand.php | 120 ++++++++++++ .../Command/SchemaTool/DropCommand.php | 121 +++++++++++++ .../Command/SchemaTool/UpdateCommand.php | 129 +++++++++++++ .../Console/Helper/EntityManagerHelper.php | 74 ++++++++ .../ORM/Tools/ConvertDoctrine1Schema.php | 2 +- lib/Doctrine/ORM/Tools/SchemaTool.php | 15 +- tools/sandbox/cli-config.php | 9 +- tools/sandbox/doctrine.php | 32 +++- 21 files changed, 2087 insertions(+), 22 deletions(-) create mode 100644 lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php create mode 100644 lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php create mode 100644 lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php new file mode 100644 index 000000000..8c3dd2b76 --- /dev/null +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php @@ -0,0 +1,127 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console; + +/** + * Task for executing arbitrary SQL that can come from a file or directly from + * the command line. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ImportCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('dbal:import') + ->setDescription('Import SQL file(s) directly to Database.') + ->setDefinition(array( + new InputArgument( + 'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.' + ) + )) + ->setHelp(<<getHelper('db')->getConnection(); + + if (($fileNames = $input->getArgument('file')) !== null) { + foreach ((array) $fileNames as $fileName) { + $fileName = realpath($fileName); + + if ( ! file_exists($fileName)) { + throw new \InvalidArgumentException( + sprintf("SQL file '%s' does not exist.", $fileName) + ); + } else if ( ! is_readable($fileName)) { + throw new \InvalidArgumentException( + sprintf("SQL file '%s' does not have read permissions.", $fileName) + ); + } + + $output->write(sprintf("Processing file '%s'... ", $fileName)); + $sql = file_get_contents($fileName); + + if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) { + // PDO Drivers + try { + $lines = 0; + + $stmt = $conn->prepare($sql); + $stmt->execute(); + + do { + // Required due to "MySQL has gone away!" issue + $stmt->fetch(); + $stmt->closeCursor(); + + $lines++; + } while ($stmt->nextRowset()); + + $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); + } catch (\PDOException $e) { + $output->write('error!' . PHP_EOL); + + throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } else { + // Non-PDO Drivers (ie. OCI8 driver) + $stmt = $conn->prepare($sql); + $rs = $stmt->execute(); + + if ($rs) { + $printer->writeln('OK!'); + } else { + $error = $stmt->errorInfo(); + + $output->write('error!' . PHP_EOL); + + throw new \RuntimeException($error[2], $error[0]); + } + + $stmt->closeCursor(); + } + } + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php new file mode 100644 index 000000000..6c5ee824e --- /dev/null +++ b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php @@ -0,0 +1,87 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Task for executing arbitrary SQL that can come from a file or directly from + * the command line. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class RunSqlCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('dbal:run-sql') + ->setDescription('Executes arbitrary SQL directly from the command line.') + ->setDefinition(array( + new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'), + new InputOption('depth', null, InputOption::PARAMETER_REQUIRED, 'Dumping depth of result set.', 7) + )) + ->setHelp(<<getHelper('db')->getConnection(); + + if (($sql = $input->getArgument('sql')) === null) { + throw new \RuntimeException("Argument 'SQL' is required in order to execute this command correctly."); + } + + $depth = $input->getOption('depth'); + + if ( ! is_numeric($depth)) { + throw new \LogicException("Option 'depth' must contains an integer value"); + } + + if (preg_match('/^select/i', $sql)) { + $stmt = $conn->execute($sql); + $resultSet = $stmt->fetchAll(\Doctrine\DBAL\Connection::FETCH_ASSOC); + } else { + $resultSet = $em->getConnection()->executeUpdate($sql); + } + + \Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth); + } +} \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php b/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php new file mode 100644 index 000000000..bcf6f8d97 --- /dev/null +++ b/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php @@ -0,0 +1,74 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Helper; + +use Symfony\Components\Console\Helper\Helper, + Doctrine\DBAL\Connection; + +/** + * Doctrine CLI Connection Helper. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConnectionHelper extends Helper +{ + /** + * Doctrine Database Connection + * @var Connection + */ + protected $_connection; + + /** + * Constructor + * + * @param Connection $connection Doctrine Database Connection + */ + public function __construct(Connection $connection) + { + $this->_connection = $connection; + } + + /** + * Retrieves Doctrine Database Connection + * + * @return Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * @see Helper + */ + public function getName() + { + return 'connection'; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php new file mode 100644 index 000000000..711bffd2d --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to clear the metadata cache of the various cache drivers. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class MetadataCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:metadata') + ->setDescription('Clear all metadata cache of the various cache drivers.') + ->setDefinition(array()) + ->setHelp(<<getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getMetadataCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Metadata cache driver is configured on given EntityManager.'); + } + + $output->write('Clearing ALL Metadata cache entries' . PHP_EOL); + + $cacheIds = $cacheDriver->deleteAll(); + + if ($cacheIds) { + foreach ($cacheIds as $cacheId) { + $output->write(' - ' . $cacheId . PHP_EOL); + } + } else { + $output->write('No entries to be deleted.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php new file mode 100644 index 000000000..b16fec3eb --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to clear the query cache of the various cache drivers. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class QueryCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:query') + ->setDescription('Clear all query cache of the various cache drivers.') + ->setDefinition(array()) + ->setHelp(<<getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getQueryCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Query cache driver is configured on given EntityManager.'); + } + + $output->write('Clearing ALL Query cache entries' . PHP_EOL); + + $cacheIds = $cacheDriver->deleteAll(); + + if ($cacheIds) { + foreach ($cacheIds as $cacheId) { + $output->write(' - ' . $cacheId . PHP_EOL); + } + } else { + $output->write('No entries to be deleted.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php new file mode 100644 index 000000000..947cac9fb --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php @@ -0,0 +1,164 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to clear the result cache of the various cache drivers. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ResultCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:result') + ->setDescription('Clear result cache of the various cache drivers.') + ->setDefinition(array( + new InputOption( + 'id', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'ID(s) of the cache entry to delete (accepts * wildcards).', array() + ), + new InputOption( + 'regex', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Delete cache entries that match the given regular expression(s).', array() + ), + new InputOption( + 'prefix', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Delete cache entries that have the given prefix(es).', array() + ), + new InputOption( + 'suffix', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Delete cache entries that have the given suffix(es).', array() + ), + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getResultCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Result cache driver is configured on given EntityManager.'); + } + + $outputed = false; + + // Removing based on --id + if (($ids = $input->getOption('id')) !== null && $ids) { + foreach ($ids as $id) { + $output->write($outputed ? PHP_EOL : ''); + $output->write(sprintf('Clearing Result cache entries that match the id "%s"', $id) . PHP_EOL); + + $deleted = $cacheDriver->delete($id); + + if (is_array($deleted)) { + $this->_printDeleted($deleted); + } else if (is_bool($deleted) && $deleted) { + $this->_printDeleted(array($id)); + } + + $outputed = true; + } + } + + // Removing based on --regex + if (($regex = $input->getOption('regex')) !== null && $regexps) { + foreach($regexps as $regex) { + $output->write($outputed ? PHP_EOL : ''); + $output->write(sprintf('Clearing Result cache entries that match the regular expression "%s"', $regex) . PHP_EOL); + + $this->_printDeleted($cacheDriver->deleteByRegex('/' . $regex. '/')); + + $outputed = true; + } + } + + // Removing based on --prefix + if (($prefixes = $input->getOption('prefix')) !== null & $prefixes) { + foreach ($prefixes as $prefix) { + $output->write($outputed ? PHP_EOL : ''); + $output->write(sprintf('Clearing Result cache entries that have the prefix "%s"', $prefix) . PHP_EOL); + + $this->_printDeleted($cacheDriver->deleteByPrefix($prefix)); + + $outputed = true; + } + } + + // Removing based on --suffix + if (($suffixes = $input->getOption('suffix')) !== null && $suffixes) { + foreach ($suffixes as $suffix) { + $output->write($outputed ? PHP_EOL : ''); + $output->write(sprintf('Clearing Result cache entries that have the suffix "%s"', $suffix) . PHP_EOL); + + $this->_printDeleted($cacheDriver->deleteBySuffix($suffix)); + + $outputed = true; + } + } + + // Removing ALL entries + if ( ! $ids && ! $regexps && ! $prefixes && ! $suffixes) { + $output->write($outputed ? PHP_EOL : ''); + $output->write('Clearing ALL Result cache entries'); + + $this->_printDeleted($cacheDriver->deleteAll()); + + $outputed = true; + } + } + + private function _printDeleted(Console\Output\OutputInterface $output, array $items) + { + if ($items) { + foreach ($items as $item) { + $output->write(' - ' . $item . PHP_EOL); + } + } else { + $output->write('No entries to be deleted.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php new file mode 100644 index 000000000..48ce45fb0 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php @@ -0,0 +1,154 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to convert a Doctrine 1 schema to a Doctrine 2 mapping file. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertDoctrine1SchemaCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:convert-d1-schema') + ->setDescription('Converts Doctrine 1.X schema into a Doctrine 2.X schema.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of Doctrine 1.X schema information.' + ), + new InputArgument( + 'to-type', InputArgument::REQUIRED, 'The destination Doctrine 2.X mapping type.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, + 'The path to generate your Doctrine 2.X mapping information.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of Doctrine 1.X schema information.', + array() + ), + new InputOption( + 'extend', null, InputOption::PARAMETER_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::PARAMETER_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as &$dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 1.X schema directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 1.X schema directory '%s' does not have read permissions.", $dirName) + ); + } + } + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 2.X mapping destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 2.X mapping destination directory '%s' does not have write permissions.", $destPath) + ); + } + + $toType = $input->getArgument('to-type'); + + $cme = new ClassMetadataExporter(); + $exporter = $cme->getExporter($toType, $destPath); + + if (strtolower($toType) === 'annotation') { + $entityGenerator = new EntityGenerator(); + $exporter->setEntityGenerator($entityGenerator); + + $entityGenerator->setNumSpaces($input->getOption('num-spaces')); + + if (($extend = $input->getOption('extend')) !== null) { + $entityGenerator->setClassToExtend($extend); + } + } + + $converter = new ConvertDoctrine1Schema($fromPaths); + $metadatas = $converter->getMetadatas(); + + if ($metadatas) { + $output->write(PHP_EOL); + + foreach ($metadatas as $metadata) { + $output->write(sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL); + } + + $exporter->setMetadatas($metadatas); + $exporter->export(); + + $output->write(PHP_EOL . sprintf( + 'Converting Doctrine 1.X schema to "%s" mapping type in "%s"', $toType, $destPath + )); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php new file mode 100644 index 000000000..45bc79714 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php @@ -0,0 +1,165 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to convert your mapping information between the various formats. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertMappingCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:convert-mapping') + ->setDescription('Convert mapping information between supported formats.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputArgument( + 'to-type', InputArgument::REQUIRED, 'The mapping type to be converted.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, + 'The path to generate your entities classes.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ), + new InputOption( + 'extend', null, InputOption::PARAMETER_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::PARAMETER_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + $cme = new ClassMetadataExporter(); + + // Process source directories + $fromPath = $input->getArgument('from-path'); + + if (strtolower($fromPath) !== 'database') { + $fromPaths = array_merge(array($fromPath), $input->getOption('from')); + + foreach ($fromPaths as &$dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $cme->addMappingSource($dirName); + } + } else { + $em->getConfiguration()->setMetadataDriverImpl( + new \Doctrine\ORM\Mapping\Driver\DatabaseDriver( + $em->getConnection()->getSchemaManager() + ) + ); + + $cme->addMappingSource($fromPath); + } + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Mapping destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Mapping destination directory '%s' does not have write permissions.", $destPath) + ); + } + + $toType = strtolower($input->getArgument('to-type')); + + $exporter = $cme->getExporter($toType, $destPath); + + if ($toType == 'annotation') { + $entityGenerator = new EntityGenerator(); + $exporter->setEntityGenerator($entityGenerator); + + $entityGenerator->setNumSpaces($input->getOption('num-spaces')); + + if (($extend = $input->getOption('extend')) !== null) { + $entityGenerator->setClassToExtend($extend); + } + } + + $metadatas = $cme->getMetadatas(); + + if ($metadatas) { + foreach ($metadatas as $metadata) { + $output->write(sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL); + } + + $exporter->setMetadatas($metadatas); + $exporter->export(); + + $output->write(PHP_EOL . sprintf( + 'Exporting "%s" mapping information to "%s"', $toType, $destPath + )); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php new file mode 100644 index 000000000..44cdd5688 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php @@ -0,0 +1,76 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to ensure that Doctrine is properly configured for a production environment. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EnsureProductionSettingsCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:ensure-production-settings') + ->setDescription('Verify that Doctrine is properly configured for a production environment.') + ->setDefinition(array( + new InputOption( + 'complete', null, InputOption::PARAMETER_NONE, + 'Flag to also inspect database connection existance.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + $em->getConfiguration()->ensureProductionSettings(); + + if ($input->getOption('complete') !== null) { + $em->getConnection()->connect(); + } + + $output->write('Environment is correctly configured for production.'); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php new file mode 100644 index 000000000..0cf0230dd --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php @@ -0,0 +1,167 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to generate entity classes and method stubs from your mapping information. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateEntitiesCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-entities') + ->setDescription('Generate entity classes and method stubs from your mapping information.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, 'The path to generate your entity classes.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ), + new InputOption( + 'generate-annotations', null, InputOption::PARAMETER_OPTIONAL, + 'Flag to define if generator should generate annotation metadata on entities.', false + ), + new InputOption( + 'generate-methods', null, InputOption::PARAMETER_OPTIONAL, + 'Flag to define if generator should generate stub methods on entities.', true + ), + new InputOption( + 'regenerate-entities', null, InputOption::PARAMETER_OPTIONAL, + 'Flag to define if generator should regenerate entity if it exists.', false + ), + new InputOption( + 'update-entities', null, InputOption::PARAMETER_OPTIONAL, + 'Flag to define if generator should only update entity if it exists.', true + ), + new InputOption( + 'extend', null, InputOption::PARAMETER_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::PARAMETER_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not have write permissions.", $destPath) + ); + } + + // Create EntityGenerator + $entityGenerator = new EntityGenerator(); + + $entityGenerator->setGenerateAnnotations($input->getOption('generate-annotations')); + $entityGenerator->setGenerateStubMethods($input->getOption('generate-methods')); + $entityGenerator->setRegenerateEntityIfExists($input->getOption('regenerate-entities')); + $entityGenerator->setUpdateEntityIfExists($input->getOption('update-entities')); + $entityGenerator->setNumSpaces($input->getOption('num-spaces')); + + if (($extend = $input->getOption('extend')) !== null) { + $entityGenerator->setClassToExtend($extend); + } + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + foreach ($metadatas as $metadata) { + $output->write( + sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL + ); + } + + // Generating Entities + $entityGenerator->generate($metadatas, $destPath); + + // Outputting information message + $output->write(PHP_EOL . sprintf('Entity classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php new file mode 100644 index 000000000..4b6333b6f --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php @@ -0,0 +1,136 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to (re)generate the proxy classes used by doctrine. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateProxiesCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-proxies') + ->setDescription('Generates proxy classes for entity classes.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputArgument( + 'dest-path', InputArgument::OPTIONAL, + 'The path to generate your proxy classes. If none is provided, it will attempt to grab from configuration.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Process destination directory + if (($destPath = $input->getArgument('dest-path')) === null) { + $destPath = $em->getConfiguration()->getProxyDir(); + } + + $destPath = realpath($destPath); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '%s' does not have write permissions.", $destPath) + ); + } + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + foreach ($metadatas as $metadata) { + $output->write( + sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL + ); + } + + // Generating Proxies + $em->getProxyFactory()->generateProxyClasses($metadatas, $destPath); + + // Outputting information message + $output->write(PHP_EOL . sprintf('Proxy classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php new file mode 100644 index 000000000..1d24fccb3 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php @@ -0,0 +1,171 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to generate repository classes for mapping information. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateRepositoriesCommand extends Console\Command\Command +{ + private static $_template = +'; + +use \Doctrine\ORM\EntityRepository; + +/** + * + * + * This class was generated by the Doctrine ORM. Add your own custom + * repository methods below. + */ +class extends EntityRepository +{ +}'; + + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-repositories') + ->setDescription('Generate repository classes from your mapping information.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, 'The path to generate your repository classes.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not have write permissions.", $destPath) + ); + } + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + $numRepositories = 0; + + foreach ($metadatas as $metadata) { + if ($metadata->customRepositoryClassName) { + $output->write( + sprintf('Processing repository "%s"', $metadata->customRepositoryClassName) . PHP_EOL + ); + + $this->_generateRepositoryClass($metadata, $destPath); + + $numRepositories++; + } + } + + if ($numRepositories) { + // Outputting information message + $output->write(PHP_EOL . sprintf('Repository classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Repository classes were found to be processed.' . PHP_EOL); + } + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } + + private function _generateRepositoryClass($metadata, $destPath) + { + $code = $this->_generateRepositoryClass($metadata->customRepositoryClassName); + + $path = $destPath . DIRECTORY_SEPARATOR + . str_replace('\\', \DIRECTORY_SEPARATOR, $metadata->customRepositoryClassName) . '.php'; + $dir = dirname($path); + + if ( ! is_dir($dir)) { + mkdir($dir, 0777, true); + } + + file_put_contents($path, $code); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php new file mode 100644 index 000000000..c995fba7b --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php @@ -0,0 +1,124 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to execute DQL queries in a given EntityManager. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class RunDqlCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:run-dql') + ->setDescription('Executes arbitrary DQL directly from the command line.') + ->setDefinition(array( + new InputArgument('dql', InputArgument::REQUIRED, 'The DQL to execute.'), + new InputOption( + 'hydrate', null, InputOption::PARAMETER_REQUIRED, + 'Hydration mode of result set. Should be either: object, array, scalar or single-scalar.', + 'object' + ), + new InputOption( + 'first-result', null, InputOption::PARAMETER_REQUIRED, + 'The first result in the result set.' + ), + new InputOption( + 'max-result', null, InputOption::PARAMETER_REQUIRED, + 'The maximum number of results in the result set.' + ), + new InputOption( + 'depth', null, InputOption::PARAMETER_REQUIRED, + 'Dumping depth of Entity graph.', 7 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + if (($dql = $input->getArgument('dql')) === null) { + throw new \RuntimeException("Argument 'DQL' is required in order to execute this command correctly."); + } + + $depth = $input->getOption('depth'); + + if ( ! is_numeric($depth)) { + throw new \LogicException("Option 'depth' must contains an integer value"); + } + + $hydrationModeName = $input->getOption('hydrate'); + $hydrationMode = 'Doctrine\ORM\Query::HYDRATE_' . strtoupper(str_replace('-', '_', $hydrationModeName)); + + if ( ! defined($hydrationMode)) { + throw new \RuntimeException( + "Hydration mode '$hydrationModeName' does not exist. It should be either: object. array, scalar or single-scalar." + ); + } + + $query = $em->createQuery($dql); + + if (($firstResult = $input->getOption('first-result')) !== null) { + if ( ! is_numeric($firstResult)) { + throw new \LogicException("Option 'first-result' must contains an integer value"); + } + + $query->setFirstResult((int) $firstResult); + } + + if (($maxResult = $input->getOption('max-result')) !== null) { + if ( ! is_numeric($maxResult)) { + throw new \LogicException("Option 'max-result' must contains an integer value"); + } + + $query->setMaxResult((int) $maxResult); + } + + $resultSet = $query->execute(array(), $hydrationMode); + + \Doctrine\Common\Util\Debug::dump($resultSet, $input->getOption('depth')); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php new file mode 100644 index 000000000..4ca0b3090 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php @@ -0,0 +1,120 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to create the database schema for a set of classes based on their mappings. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class CreateCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:schema-tool:create') + ->setDescription( + 'Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output.' + ) + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ), + new InputOption( + 'dump-sql', null, InputOption::PARAMETER_NONE, + 'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + // Create SchemaTool + $tool = new \Doctrine\ORM\Tools\SchemaTool($em); + + if ($input->getOption('dump-sql') === null) { + $sqls = $tool->getCreateSchemaSql($metadatas); + $output->write(implode(';' . PHP_EOL, $sqls)); + } else { + $output->write('Creating database schema...' . PHP_EOL); + $tool->createSchema($metadatas); + $output->write('Database schema created successfully!' . PHP_EOL); + } + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php new file mode 100644 index 000000000..b41c616a8 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to drop the database schema for a set of classes based on their mappings. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DropCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:schema-tool:drop') + ->setDescription( + 'Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.' + ) + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ), + new InputOption( + 'dump-sql', null, InputOption::PARAMETER_NONE, + 'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + // Create SchemaTool + $tool = new \Doctrine\ORM\Tools\SchemaTool($em); + + if ($input->getOption('dump-sql') === null) { + $sqls = $tool->getDropSchemaSql($metadatas); + $output->write(implode(';' . PHP_EOL, $sqls)); + } else { + $output->write('Dropping database schema...' . PHP_EOL); + $tool->dropSchema($metadatas); + $output->write('Database schema dropped successfully!' . PHP_EOL); + } + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php new file mode 100644 index 000000000..9aba1e9cd --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -0,0 +1,129 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Components\Console\Input\InputArgument, + Symfony\Components\Console\Input\InputOption, + Symfony\Components\Console; + +/** + * Command to update the database schema for a set of classes based on their mappings. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class UpdateCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:schema-tool:update') + ->setDescription( + 'Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output.' + ) + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of mapping information.' + ), + new InputOption( + 'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY, + 'Optional paths of mapping information.', + array() + ), + new InputOption( + 'complete', null, InputOption::PARAMETER_NONE, + 'If defined, all assets of the database which are not relevant to the current metadata will be dropped.' + ), + new InputOption( + 'dump-sql', null, InputOption::PARAMETER_NONE, + 'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $reader = new ClassMetadataReader(); + $reader->setEntityManager($em); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + foreach ($fromPaths as $dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Mapping directory '%s' does not have read permissions.", $dirName) + ); + } + + $reader->addMappingSource($dirName); + } + + // Defining if update is complete or not (--complete not defined means $saveMode = true) + $saveMode = ($input->getOption('complete') === null); + + // Retrieving ClassMetadatas + $metadatas = $reader->getMetadatas(); + + if ( ! empty($metadatas)) { + // Create SchemaTool + $tool = new \Doctrine\ORM\Tools\SchemaTool($em); + + if ($input->getOption('dump-sql') === null) { + $sqls = $tool->getUpdateSchemaSql($metadatas, $saveMode); + $output->write(implode(';' . PHP_EOL, $sqls)); + } else { + $output->write('Updating database schema...' . PHP_EOL); + $tool->updateSchema($metadatas, $saveMode); + $output->write('Database schema updated successfully!' . PHP_EOL); + } + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php b/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php new file mode 100644 index 000000000..2636006e3 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php @@ -0,0 +1,74 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Helper; + +use Symfony\Components\Console\Helper\Helper, + Doctrine\ORM\EntityManager; + +/** + * Doctrine CLI Connection Helper. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityManagerHelper extends Helper +{ + /** + * Doctrine ORM EntityManager + * @var EntityManager + */ + protected $_em; + + /** + * Constructor + * + * @param Connection $connection Doctrine Database Connection + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + } + + /** + * Retrieves Doctrine ORM EntityManager + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * @see Helper + */ + public function getName() + { + return 'entityManager'; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php b/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php index 89744c0f1..b559913a4 100644 --- a/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php +++ b/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php @@ -48,7 +48,7 @@ class ConvertDoctrine1Schema * Constructor passes the directory or array of directories * to convert the Doctrine 1 schema files from * - * @param string $from + * @param array $from * @author Jonathan Wage */ public function __construct($from) diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 129c9aa02..5897e0a72 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -43,15 +43,6 @@ use Doctrine\ORM\ORMException, */ class SchemaTool { - /** - * @var string - */ - const DROP_METADATA = "metadata"; - /** - * @var string - */ - const DROP_DATABASE = "database"; - /** * @var \Doctrine\ORM\EntityManager */ @@ -473,12 +464,11 @@ class SchemaTool * issued for all classes of the schema and some probably just don't exist. * * @param array $classes - * @param string $mode * @return void */ - public function dropSchema(array $classes, $mode=self::DROP_METADATA) + public function dropSchema(array $classes) { - $dropSchemaSql = $this->getDropSchemaSql($classes, $mode); + $dropSchemaSql = $this->getDropSchemaSql($classes); $conn = $this->_em->getConnection(); foreach ($dropSchemaSql as $sql) { @@ -490,7 +480,6 @@ class SchemaTool * Gets the SQL needed to drop the database schema for the given classes. * * @param array $classes - * @param string $mode * @return array */ public function getDropSchemaSql(array $classes) diff --git a/tools/sandbox/cli-config.php b/tools/sandbox/cli-config.php index 06cb51f07..887780dd9 100644 --- a/tools/sandbox/cli-config.php +++ b/tools/sandbox/cli-config.php @@ -22,9 +22,6 @@ $classLoader->register(); $classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__); $classLoader->register(); -$classLoader = new \Doctrine\Common\ClassLoader('Symfony', __DIR__ . '/../../lib/vendor'); -$classLoader->register(); - $config = new \Doctrine\ORM\Configuration(); $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); $config->setProxyDir(__DIR__ . '/Proxies'); @@ -37,5 +34,7 @@ $connectionOptions = array( $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config); -$configuration = new \Doctrine\Common\CLI\Configuration(); -$configuration->setAttribute('em', $em); \ No newline at end of file +$helperSet = new \Symfony\Components\Console\Helper\HelperSet(array( + 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()), + 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em) +)); \ No newline at end of file diff --git a/tools/sandbox/doctrine.php b/tools/sandbox/doctrine.php index 9b29b5e49..152a9932e 100644 --- a/tools/sandbox/doctrine.php +++ b/tools/sandbox/doctrine.php @@ -5,8 +5,34 @@ require __DIR__ . '/../../lib/Doctrine/Common/ClassLoader.php'; $classLoader = new \Doctrine\Common\ClassLoader('Doctrine', __DIR__ . '/../../lib'); $classLoader->register(); -// Variable $configuration is defined inside cli-config.php +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', __DIR__ . '/../../lib/vendor'); +$classLoader->register(); + +// Variable $helperSet is defined inside cli-config.php require __DIR__ . '/cli-config.php'; -$cli = new \Doctrine\Common\CLI\CLIController($configuration); -$cli->run($_SERVER['argv']); \ No newline at end of file +$cli = new \Symfony\Components\Console\Application('Doctrine Command Line Interface', Doctrine\Common\Version::VERSION); +$cli->setCatchExceptions(true); +$cli->setHelperSet($helperSet); +$cli->addCommands(array( + // DBAL Commands + new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), + + // ORM Commands + new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(), + new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(), + new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(), + +)); +$cli->run(); \ No newline at end of file