[DoctrineBundle] Enhancing the Doctrine 2 integration further to better handle multiple connections/entity managers
This commit is contained in:
parent
b3d8aa414e
commit
1a45bb6d63
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Framework\DoctrineBundle\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument;
|
||||
use Symfony\Components\Console\Input\InputOption;
|
||||
use Symfony\Components\Console\Input\InputInterface;
|
||||
use Symfony\Components\Console\Output\OutputInterface;
|
||||
use Symfony\Components\Console\Output\Output;
|
||||
use Symfony\Framework\WebBundle\Util\Filesystem;
|
||||
use Doctrine\Common\Cli\Configuration;
|
||||
use Doctrine\Common\Cli\CliController as DoctrineCliController;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build command allows you to easily build and re-build your Doctrine development environment
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Kris Wallsmith <kris.wallsmith@symfony-project.org>
|
||||
*/
|
||||
class BuildDoctrineCommand extends DoctrineCommand
|
||||
{
|
||||
const
|
||||
BUILD_ENTITIES = 1,
|
||||
BUILD_DB = 16,
|
||||
|
||||
OPTION_ENTITIES = 1,
|
||||
OPTION_DB = 16,
|
||||
OPTION_ALL = 31;
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('doctrine:build')
|
||||
->setDescription('Build task for easily re-building your Doctrine development environment.')
|
||||
->addOption('all', null, null, 'Build everything and reset the database')
|
||||
->addOption('entities', null, null, 'Build model classes')
|
||||
->addOption('db', null, null, 'Drop database, create database and create schema.')
|
||||
->addOption('and-load', null, InputOption::PARAMETER_OPTIONAL | InputOption::PARAMETER_IS_ARRAY, 'Load data fixtures')
|
||||
->addOption('and-append', null, InputOption::PARAMETER_OPTIONAL | InputOption::PARAMETER_IS_ARRAY, 'Load data fixtures and append to existing data')
|
||||
->addOption('and-update-schema', null, null, 'Update schema after rebuilding all classes')
|
||||
->addOption('connection', null, null, 'The connection to use.')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (!$mode = $this->calculateMode($input))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf("You must include one or more of the following build options:\n--%s\n\nSee this task's help page for more information:\n\n php console help doctrine:build", join(', --', array_keys($this->getBuildOptions()))));
|
||||
}
|
||||
|
||||
if (self::BUILD_ENTITIES == (self::BUILD_ENTITIES & $mode))
|
||||
{
|
||||
$this->runCommand('doctrine:build-entities');
|
||||
}
|
||||
|
||||
if (self::BUILD_DB == (self::BUILD_DB & $mode))
|
||||
{
|
||||
$this->runCommand('doctrine:schema-tool', array('--re-create' => true, '--connection' => $input->getOption('connection')));
|
||||
}
|
||||
|
||||
if ($input->getOption('and-update-schema'))
|
||||
{
|
||||
$this->runCommand('doctrine:schema-tool', array('--update' => true, '--connection' => $input->getOption('connection')));
|
||||
$this->runCommand('doctrine:schema-tool', array('--complete-update' => true, '--connection' => $input->getOption('connection')));
|
||||
}
|
||||
|
||||
if ($input->hasOption('and-load'))
|
||||
{
|
||||
$dirOrFile = $input->getOption('and-load');
|
||||
$this->runCommand('doctrine:load-data-fixtures',
|
||||
array('--dir_or_file' => $dirOrFile, '--append' => false)
|
||||
);
|
||||
}
|
||||
else if ($input->hasOption('and-append'))
|
||||
{
|
||||
$dirOrFile = $input->getOption('and-append');
|
||||
$this->runCommand('doctrine:load-data-fixtures', array('--dir_or_file' => $dirOrFile, '--append' => true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a bit mode based on the supplied options.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @return integer
|
||||
*/
|
||||
protected function calculateMode(InputInterface $input)
|
||||
{
|
||||
$mode = 0;
|
||||
foreach ($this->getBuildOptions() as $name => $value)
|
||||
{
|
||||
if ($input->getOption($name) === true)
|
||||
{
|
||||
$mode = $mode | $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of valid build options.
|
||||
*
|
||||
* @return array An array of option names and their mode
|
||||
*/
|
||||
protected function getBuildOptions()
|
||||
{
|
||||
$options = array();
|
||||
foreach ($this->getDefinition()->getOptions() as $option)
|
||||
{
|
||||
if (defined($constant = __CLASS__.'::OPTION_'.str_replace('-', '_', strtoupper($option->getName()))))
|
||||
{
|
||||
$options[$option->getName()] = constant($constant);
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Framework\DoctrineBundle\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument;
|
||||
use Symfony\Components\Console\Input\InputOption;
|
||||
use Symfony\Components\Console\Input\InputInterface;
|
||||
use Symfony\Components\Console\Output\OutputInterface;
|
||||
use Symfony\Components\Console\Output\Output;
|
||||
use Symfony\Framework\WebBundle\Util\Filesystem;
|
||||
use Doctrine\Common\Cli\Configuration;
|
||||
use Doctrine\Common\Cli\CliController as DoctrineCliController;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build all Bundle entity classes from mapping information.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
*/
|
||||
class BuildEntitiesDoctrineCommand extends DoctrineCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('doctrine:build-entities')
|
||||
->setDescription('Build all Bundle entity classes from mapping information.')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
foreach ($this->container->getParameter('kernel.bundle_dirs') as $bundle => $path)
|
||||
{
|
||||
$bundles = glob($path.'/*Bundle');
|
||||
foreach ($bundles as $p)
|
||||
{
|
||||
if (!is_dir($metadataPath = $p.'/Resources/config/doctrine/metadata'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$opts = array();
|
||||
$opts['--from'] = $metadataPath;
|
||||
$opts['--to'] = 'annotation';
|
||||
$opts['--dest'] = realpath($path.'/..');
|
||||
$this->runCommand('doctrine:convert-mapping', $opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Framework\DoctrineBundle\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument;
|
||||
use Symfony\Components\Console\Input\InputOption;
|
||||
use Symfony\Components\Console\Input\InputInterface;
|
||||
use Symfony\Components\Console\Output\OutputInterface;
|
||||
use Symfony\Components\Console\Output\Output;
|
||||
use Symfony\Framework\WebBundle\Util\Filesystem;
|
||||
use Doctrine\Common\Cli\Configuration;
|
||||
use Doctrine\Common\Cli\CliController as DoctrineCliController;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Database tool allows you to easily drop and create your configured databases.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
*/
|
||||
class DatabaseToolDoctrineCommand extends DoctrineCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('doctrine:database-tool')
|
||||
->setDescription('Create and drop the configured databases.')
|
||||
->addOption('re-create', null, null, 'Drop and re-create your databases.')
|
||||
->addOption('drop', null, null, 'Drop your databases.')
|
||||
->addOption('create', null, null, 'Create your databases.')
|
||||
->addOption('connection', null, null, 'The connection name to work on.')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('re-create'))
|
||||
{
|
||||
$input->setOption('drop', true);
|
||||
$input->setOption('create', true);
|
||||
}
|
||||
if (!$input->getOption('drop') && !$input->getOption('create'))
|
||||
{
|
||||
throw new \InvalidArgumentException('You must specify one of the --drop and --create options or both.');
|
||||
}
|
||||
$found = false;
|
||||
$connections = $this->getDoctrineConnections();
|
||||
foreach ($connections as $name => $connection)
|
||||
{
|
||||
if ($input->getOption('connection') && $name != $input->getOption('connection'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($input->getOption('drop'))
|
||||
{
|
||||
$this->dropDatabaseForConnection($connection, $output);
|
||||
}
|
||||
if ($input->getOption('create'))
|
||||
{
|
||||
$this->createDatabaseForConnection($connection, $output);
|
||||
}
|
||||
$found = true;
|
||||
}
|
||||
if ($found === false)
|
||||
{
|
||||
if ($input->getOption('connection'))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('<error>Could not find a connection named <comment>%s</comment></error>', $input->getOption('connection')));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('<error>Could not find any configured connections</error>', $input->getOption('connection')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function dropDatabaseForConnection(Connection $connection, OutputInterface $output)
|
||||
{
|
||||
$params = $connection->getParams();
|
||||
$name = isset($params['path']) ? $params['path']:$params['dbname'];
|
||||
|
||||
try {
|
||||
$connection->getSchemaManager()->dropDatabase($name);
|
||||
$output->writeln(sprintf('<info>Dropped database for connection named <comment>%s</comment></info>', $name));
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln(sprintf('<error>Could not drop database for connection named <comment>%s</comment></error>', $name));
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
protected function createDatabaseForConnection(Connection $connection, OutputInterface $output)
|
||||
{
|
||||
$params = $connection->getParams();
|
||||
$name = isset($params['path']) ? $params['path']:$params['dbname'];
|
||||
|
||||
unset($params['dbname']);
|
||||
|
||||
$tmpConnection = \Doctrine\DBAL\DriverManager::getConnection($params);
|
||||
|
||||
try {
|
||||
$tmpConnection->getSchemaManager()->createDatabase($name);
|
||||
$output->writeln(sprintf('<info>Created database for connection named <comment>%s</comment></info>', $name));
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln(sprintf('<error>Could not create database for connection named <comment>%s</comment></error>', $name));
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
}
|
||||
|
||||
$tmpConnection->close();
|
||||
}
|
||||
}
|
@ -3,11 +3,13 @@
|
||||
namespace Symfony\Framework\DoctrineBundle\Command;
|
||||
|
||||
use Symfony\Framework\WebBundle\Command\Command;
|
||||
use Symfony\Components\Console\Input\ArrayInput;
|
||||
use Symfony\Components\Console\Input\InputArgument;
|
||||
use Symfony\Components\Console\Input\InputOption;
|
||||
use Symfony\Components\Console\Input\InputInterface;
|
||||
use Symfony\Components\Console\Output\OutputInterface;
|
||||
use Symfony\Components\Console\Output\Output;
|
||||
use Symfony\Framework\WebBundle\Console\Application;
|
||||
use Symfony\Framework\WebBundle\Util\Filesystem;
|
||||
use Doctrine\Common\Cli\Configuration;
|
||||
use Doctrine\Common\Cli\CliController as DoctrineCliController;
|
||||
@ -30,16 +32,19 @@ use Doctrine\Common\Cli\CliController as DoctrineCliController;
|
||||
*/
|
||||
abstract class DoctrineCommand extends Command
|
||||
{
|
||||
protected $cli;
|
||||
protected
|
||||
$cli,
|
||||
$em;
|
||||
|
||||
protected function getDoctrineCli()
|
||||
{
|
||||
if ($this->cli === null)
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$configuration->setAttribute('em', $this->container->getDoctrine_Orm_EntityManagerService());
|
||||
$this->cli = new DoctrineCliController($configuration);
|
||||
}
|
||||
$em = $this->em ? $this->em : $this->container->getDoctrine_Orm_EntityManagerService();
|
||||
$this->cli->getConfiguration()->setAttribute('em', $em);
|
||||
return $this->cli;
|
||||
}
|
||||
|
||||
@ -60,7 +65,7 @@ abstract class DoctrineCommand extends Command
|
||||
return $this->getDoctrineCli()->run(array_merge(array('doctrine', $name), $builtOptions));
|
||||
}
|
||||
|
||||
public function buildDoctrineCliTaskOptions(InputInterface $input, array $options)
|
||||
protected function buildDoctrineCliTaskOptions(InputInterface $input, array $options)
|
||||
{
|
||||
$taskOptions = array();
|
||||
foreach ($options as $option)
|
||||
@ -72,4 +77,49 @@ abstract class DoctrineCommand extends Command
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
protected function runCommand($name, array $input = array())
|
||||
{
|
||||
$arguments = array();
|
||||
$arguments = array_merge(array($name), $input);
|
||||
$input = new ArrayInput($arguments);
|
||||
$application = new Application($this->container->getKernelService());
|
||||
$application->setAutoExit(false);
|
||||
$application->run($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Better way to do these functions?
|
||||
*/
|
||||
protected function getDoctrineConnections()
|
||||
{
|
||||
$connections = array();
|
||||
$ids = $this->container->getServiceIds();
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
preg_match('/doctrine.dbal.(.*)_connection/', $id, $matches);
|
||||
if ($matches)
|
||||
{
|
||||
$name = $matches[1];
|
||||
$connections[$name] = $this->container->getService($id);
|
||||
}
|
||||
}
|
||||
return $connections;
|
||||
}
|
||||
|
||||
protected function getDoctrineEntityManagers()
|
||||
{
|
||||
$entityManagers = array();
|
||||
$ids = $this->container->getServiceIds();
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
preg_match('/doctrine.orm.(.*)_entity_manager/', $id, $matches);
|
||||
if ($matches)
|
||||
{
|
||||
$name = $matches[1];
|
||||
$entityManagers[$name] = $this->container->getService($id);
|
||||
}
|
||||
}
|
||||
return $entityManagers;
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ class LoadDataFixturesDoctrineCommand extends DoctrineCommand
|
||||
$this
|
||||
->setName('doctrine:load-data-fixtures')
|
||||
->setDescription('Load data fixtures to your database.')
|
||||
->addOption('dir_or_file', null, null, 'The directory or file to load data fixtures from.')
|
||||
->addOption('dir_or_file', null, InputOption::PARAMETER_OPTIONAL | InputOption::PARAMETER_IS_ARRAY, 'The directory or file to load data fixtures from.')
|
||||
->addOption('append', null, InputOption::PARAMETER_OPTIONAL, 'Whether or not to append the data fixtures.', false)
|
||||
;
|
||||
}
|
||||
@ -51,37 +51,11 @@ class LoadDataFixturesDoctrineCommand extends DoctrineCommand
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$em = $this->container->getDoctrine_ORM_EntityManagerService();
|
||||
if (!$input->getOption('append'))
|
||||
{
|
||||
$classes = array();
|
||||
$metadatas = $em->getMetadataFactory()->getAllMetadata();
|
||||
|
||||
foreach ($metadatas as $metadata)
|
||||
{
|
||||
if (!$metadata->isMappedSuperclass)
|
||||
{
|
||||
$classes[] = $metadata;
|
||||
}
|
||||
}
|
||||
$cmf = $em->getMetadataFactory();
|
||||
$classes = $this->getCommitOrder($em, $classes);
|
||||
for ($i = count($classes) - 1; $i >= 0; --$i)
|
||||
{
|
||||
$class = $classes[$i];
|
||||
if ($cmf->hasMetadataFor($class->name))
|
||||
{
|
||||
try {
|
||||
$em->createQuery('DELETE FROM '.$class->name.' a')->execute();
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$defaultEm = $this->container->getDoctrine_ORM_EntityManagerService();
|
||||
$dirOrFile = $input->getOption('dir_or_file');
|
||||
if ($dirOrFile)
|
||||
{
|
||||
$paths = $dirOrFile;
|
||||
$paths = is_array($dirOrFile) ? $dirOrFile : array($dirOrFile);
|
||||
} else {
|
||||
$paths = array();
|
||||
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
|
||||
@ -112,20 +86,83 @@ class LoadDataFixturesDoctrineCommand extends DoctrineCommand
|
||||
$files = array_merge($files, $found);
|
||||
}
|
||||
|
||||
$ems = array();
|
||||
$emEntities = array();
|
||||
$files = array_unique($files);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$em = $defaultEm;
|
||||
$output->writeln(sprintf('<info>Loading data fixtures from <comment>"%s"</comment></info>', $file));
|
||||
|
||||
$before = array_keys(get_defined_vars());
|
||||
include($file);
|
||||
$after = array_keys(get_defined_vars());
|
||||
$new = array_diff($after, $before);
|
||||
$entities = array_values($new);
|
||||
unset($entities[array_search('before', $entities)]);
|
||||
foreach ($entities as $entity) {
|
||||
$em->persist($$entity);
|
||||
$params = $em->getConnection()->getParams();
|
||||
$emName = isset($params['path']) ? $params['path']:$params['dbname'];
|
||||
|
||||
$ems[$emName] = $em;
|
||||
$emEntities[$emName] = array();
|
||||
$variables = array_values($new);
|
||||
|
||||
foreach ($variables as $variable)
|
||||
{
|
||||
$value = $$variable;
|
||||
if (!is_object($value) || $value instanceof \Doctrine\ORM\EntityManager)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$emEntities[$emName][] = $value;
|
||||
}
|
||||
foreach ($ems as $emName => $em)
|
||||
{
|
||||
if (!$input->getOption('append'))
|
||||
{
|
||||
$output->writeln(sprintf('<info>Purging data from entity manager named <comment>"%s"</comment></info>', $emName));
|
||||
$this->purgeEntityManager($em);
|
||||
}
|
||||
|
||||
$entities = $emEntities[$emName];
|
||||
$numEntities = count($entities);
|
||||
$output->writeln(sprintf('<info>Persisting "%s" '.($numEntities > 1 ? 'entities' : 'entity').'</info>', count($entities)));
|
||||
|
||||
foreach ($entities as $entity)
|
||||
{
|
||||
$output->writeln(sprintf('<info>Persisting "%s" entity:</info>', get_class($entity)));
|
||||
$output->writeln('');
|
||||
$output->writeln(var_dump($entity));
|
||||
|
||||
$em->persist($entity);
|
||||
}
|
||||
$output->writeln('<info>Flushing entity manager</info>');
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function purgeEntityManager(EntityManager $em)
|
||||
{
|
||||
$classes = array();
|
||||
$metadatas = $em->getMetadataFactory()->getAllMetadata();
|
||||
|
||||
foreach ($metadatas as $metadata)
|
||||
{
|
||||
if (!$metadata->isMappedSuperclass)
|
||||
{
|
||||
$classes[] = $metadata;
|
||||
}
|
||||
}
|
||||
$cmf = $em->getMetadataFactory();
|
||||
$classes = $this->getCommitOrder($em, $classes);
|
||||
for ($i = count($classes) - 1; $i >= 0; --$i)
|
||||
{
|
||||
$class = $classes[$i];
|
||||
if ($cmf->hasMetadataFor($class->name))
|
||||
{
|
||||
try {
|
||||
$em->createQuery('DELETE FROM '.$class->name.' a')->execute();
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ class RunDqlDoctrineCommand extends DoctrineCommand
|
||||
->setDescription('Executes arbitrary DQL directly from the command line.')
|
||||
->addOption('dql', null, null, 'The DQL query to run.')
|
||||
->addOption('depth', null, null, 'The depth to output the data to.')
|
||||
->addOption('connection', null, null, 'The connection to use.')
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ class RunSqlDoctrineCommand extends DoctrineCommand
|
||||
->addOption('sql', null, null, 'The SQL query to run.')
|
||||
->addOption('file', null, null, 'Path to a SQL file to run.')
|
||||
->addOption('depth', null, null, 'The depth to output the data to.')
|
||||
->addOption('connection', null, null, 'The connection to use.')
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ class SchemaToolDoctrineCommand extends DoctrineCommand
|
||||
->addOption('complete-update', null, null, 'Complete update and drop anything that is not in your schema.')
|
||||
->addOption('re-create', null, null, 'Drop and re-create your database schema.')
|
||||
->addOption('dump-sql', null, null, 'Dump the SQL instead of executing it.')
|
||||
->addOption('connection', null, null, 'The connection to use.')
|
||||
;
|
||||
}
|
||||
|
||||
@ -55,8 +56,33 @@ class SchemaToolDoctrineCommand extends DoctrineCommand
|
||||
$options = $this->buildDoctrineCliTaskOptions($input, array(
|
||||
'create', 'drop', 'update', 'complete-update', 're-create', 'dump-sql'
|
||||
));
|
||||
|
||||
$entityDirs = $this->container->getParameter('doctrine.orm.entity_dirs');
|
||||
$options['class-dir'] = implode(', ', $entityDirs);
|
||||
$this->runDoctrineCliTask('orm:schema-tool', $options);
|
||||
|
||||
$found = false;
|
||||
$ems = $this->getDoctrineEntityManagers();
|
||||
foreach ($ems as $name => $em)
|
||||
{
|
||||
if ($input->getOption('connection') && $name !== $input->getOption('connection'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->em = $em;
|
||||
$this->runDoctrineCliTask('orm:schema-tool', $options);
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if ($found === false)
|
||||
{
|
||||
if ($input->getOption('connection'))
|
||||
{
|
||||
$output->writeln(sprintf('<error>Could not find a connection named <comment>%s</comment></error>', $input->getOption('connection')));
|
||||
}
|
||||
else
|
||||
{
|
||||
$output->writeln(sprintf('<error>Could not find any configured connections</error>', $input->getOption('connection')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
191
src/Symfony/Framework/DoctrineBundle/README
Normal file
191
src/Symfony/Framework/DoctrineBundle/README
Normal file
@ -0,0 +1,191 @@
|
||||
DoctrineBundle
|
||||
--------------
|
||||
|
||||
This document describes some of the functionality provided by the
|
||||
**DoctrineBundle**. Doctrine 2 is a first class citizen in Symfony 2 and is
|
||||
tightly integrated. Continue reading to learn how to use Doctrine 2 with the
|
||||
latest Symfony 2!
|
||||
|
||||
## Configuration
|
||||
|
||||
This section will help you with configuring your Symfony 2 project to enable
|
||||
the Doctrine DBAL and ORM services.
|
||||
|
||||
### Database Abstraction Layer
|
||||
|
||||
You can configure your database abstraction layer simply configuration a few
|
||||
pieces of information about your database. If you only have one database you can
|
||||
do the following:
|
||||
|
||||
[yml]
|
||||
doctrine.dbal:
|
||||
dbname: symfony_guestbook
|
||||
user: root
|
||||
password: ~
|
||||
|
||||
Or if you have multiple connections and want to customize the configuration of the
|
||||
connection further you can use the following:
|
||||
|
||||
[yml]
|
||||
doctrine.dbal:
|
||||
default_connection: default
|
||||
connections:
|
||||
default:
|
||||
driver: PDOSqlite # PDOSqlite, PDOMySql, PDOMsSql, PDOOracle, PDOPgSql, OCI8
|
||||
dbname: symfony
|
||||
user: root
|
||||
password: null
|
||||
host: localhost
|
||||
port: ~
|
||||
path: %kernel.data_dir%/symfony.sqlite
|
||||
event_manager_class: Doctrine\Common\EventManager
|
||||
configuration_class: Doctrine\DBAL\Configuration
|
||||
wrapper_class: ~
|
||||
options: []
|
||||
|
||||
### Object Relational Mapper
|
||||
|
||||
If you want to enable the Doctrine 2 ORM you can do so with the following:
|
||||
|
||||
doctrine.orm:
|
||||
default_entity_manager: default
|
||||
metadata_driver: xml # xml, yml, annotation
|
||||
cache_driver: apc # array, apc, memcache, xcache
|
||||
entity_managers:
|
||||
default:
|
||||
connection: default
|
||||
|
||||
It's pretty simple, you can specify which entity managers you want to instantiate
|
||||
for which connections and also configure some other information about the ORM
|
||||
like what type of mapping files to use or what cache driver to use.
|
||||
|
||||
## Creating a Bundle
|
||||
|
||||
To get started we need to create a new bundle:
|
||||
|
||||
$ php console init:bundle "Bundle\\GuestbookBundle"
|
||||
Initializing bundle "GuestbookBundle" in "/path/to/symfony-sandbox/src/Bundle"
|
||||
|
||||
Now basically the most important thing to know about using Doctrine 2 with Symfony
|
||||
is where to put your mapping information files, where your entity classes are and
|
||||
a few commands to help move things faster!
|
||||
|
||||
## Mapping Information
|
||||
|
||||
You can place all your mapping information inside a bundle. Below is an example
|
||||
path for the **GuestbookBundle** we created above:
|
||||
|
||||
/path/to/symfony-sandbox/src/Bundle/GuestbookBundle/Resources/config/doctrine/metadata
|
||||
|
||||
Any files found in here that have a suffix of **.dcm.xml** (or whatever
|
||||
mapping_driver you picked) are used as your entities mapping information.
|
||||
|
||||
In the **GuestbookBundle** we have a file named **Bundle.GuestbookBundle.Entities.Entry.dcm.xml**
|
||||
which contains the following XML:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bundle\GuestbookBundle\Entities\Entry" table="guestbook_entry">
|
||||
|
||||
<id name="id" type="integer" column="id">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
|
||||
<field name="createdAt" column="created_at" type="datetime" />
|
||||
<field name="name" column="name" type="string" length="255" />
|
||||
<field name="emailAddress" column="email_address" type="string" length="255" />
|
||||
<field name="body" column="body" type="text" />
|
||||
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
||||
|
||||
## Building Entities
|
||||
|
||||
Doctrine can help you a little bit by generating the entity classes for your
|
||||
mapping information with the command:
|
||||
|
||||
$ php console doctrine:build-entities
|
||||
|
||||
Now if you have a look in the bundles **Entities** directory you will see a new
|
||||
file named **Entry.php** with some code like the following:
|
||||
|
||||
[php]
|
||||
// Bundle/GuestbookBundle/Entities/Entry.php
|
||||
|
||||
namespace Bundle\GuestbookBundle\Entities;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="guestbook_entry")
|
||||
*/
|
||||
class Entry
|
||||
{
|
||||
/**
|
||||
* @Column(name="created_at", type="datetime")
|
||||
*/
|
||||
private $createdAt;
|
||||
|
||||
/**
|
||||
* @Column(name="name", type="string", length=255)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
// ...
|
||||
|
||||
> **NOTE**
|
||||
> If you modify your mapping information and re-run the build entities command
|
||||
> it will modify the classes and update them based on the mapping information.
|
||||
|
||||
## Commands
|
||||
|
||||
The Doctrine 2 CLI is integrated with the Symfony 2 CLI so we have all the common
|
||||
commands we need to make working with Doctrine 2 just as easy and fast as before!
|
||||
|
||||
$ php console list doctrine
|
||||
|
||||
Available commands for the "doctrine" namespace:
|
||||
:build Build task for easily re-building your Doctrine development environment.
|
||||
:build-entities Build all Bundle entity classes from mapping information.
|
||||
:clear-cache Clear cache from configured query, result and metadata drivers. (doctrine:cc)
|
||||
:convert-mapping Convert mapping information between supported formats.
|
||||
:database-tool Create and drop the configured databases.
|
||||
:ensure-production-settings Verify that Doctrine is properly configured for a production environment.
|
||||
:generate-proxies Generates proxy classes for entity classes.
|
||||
:load-data-fixtures Load data fixtures to your database.
|
||||
:run-dql Executes arbitrary DQL directly from the command line.
|
||||
:run-sql Executes arbitrary SQL from a file or directly from the command line.
|
||||
:schema-tool Processes the schema and either apply it directly on EntityManager or generate the SQL output.
|
||||
:version Displays the current installed Doctrine version.
|
||||
|
||||
The development workflow is very similar to how it is in Symfony 1.4. You can modify
|
||||
your mapping information and use **doctrine:build --all** to re-build your
|
||||
environment:
|
||||
|
||||
php console doctrine:build --all
|
||||
|
||||
The recommend way to work is to re-build your entities and update your database
|
||||
schema:
|
||||
|
||||
php console doctrine:build --entities --and-update-schema
|
||||
|
||||
Now any changes you made in your mapping information will be reflected in the
|
||||
according databases! Here are all the available options for the **build** task:
|
||||
|
||||
$ php console help doctrine:build
|
||||
Usage:
|
||||
Symfony doctrine:build [--all] [--all-classes] [--entities] [--db] [--and-load[="..."]] [--and-append[="..."]] [--and-update-schema] [--dump-sql] [--connection]
|
||||
|
||||
Options:
|
||||
--all Build everything and reset the database
|
||||
--entities Build model classes
|
||||
--db Drop database, create database and create schema.
|
||||
--and-load Load data fixtures (multiple values allowed)
|
||||
--and-append Load data fixtures and append to existing data (multiple values allowed)
|
||||
--and-update-schema Update schema after rebuilding all classes
|
||||
--connection The connection to use.
|
Reference in New Issue
Block a user