Commit 94c18768 authored by romanb's avatar romanb

[2.0] Work on CLI: Added SchemaToolTask with preliminary support for...

[2.0] Work on CLI: Added SchemaToolTask with preliminary support for dropping/creating the database schema. Prepared the sandbox. Adjusted build to include the sandbox.
parent 733c3c24
...@@ -37,6 +37,19 @@ ...@@ -37,6 +37,19 @@
<fileset id="orm-sources" dir="."> <fileset id="orm-sources" dir=".">
<include name="lib/Doctrine/ORM/**"/> <include name="lib/Doctrine/ORM/**"/>
</fileset> </fileset>
<!--
Fileset for the Doctrine ORM tools + sandbox.
-->
<fileset id="orm-tools" dir=".">
<include name="tools/sandbox/Entities"/>
<include name="tools/sandbox/xml"/>
<include name="tools/sandbox/yaml"/>
<include name="tools/sandbox/cli-config.php"/>
<include name="tools/sandbox/config.php"/>
<include name="tools/sandbox/doctrine"/>
<include name="tools/sandbox/index.php"/>
</fileset>
<target name="clean"> <target name="clean">
<delete dir="${build.dir}" includeemptydirs="true" /> <delete dir="${build.dir}" includeemptydirs="true" />
...@@ -77,6 +90,7 @@ ...@@ -77,6 +90,7 @@
<fileset refid="common-sources"/> <fileset refid="common-sources"/>
<fileset refid="dbal-sources"/> <fileset refid="dbal-sources"/>
<fileset refid="orm-sources"/> <fileset refid="orm-sources"/>
<fileset refid="orm-tools"/>
</copy> </copy>
</target> </target>
......
...@@ -302,11 +302,11 @@ class EntityManager ...@@ -302,11 +302,11 @@ class EntityManager
/** /**
* Gets a reference to the entity identified by the given type and identifier * Gets a reference to the entity identified by the given type and identifier
* without actually loading it. Only the identifier of the returned entity * without actually loading it.
* will be populated. *
* * If partial objects are allowed, this method will return a partial object that only
* NOTE: There is currently no magic proxying in place, that means the full state * has its identifier populated. Otherwise a proxy is returned that automatically
* of the entity will not be loaded upon accessing it. * loads itself on first access.
* *
* @return object The entity reference. * @return object The entity reference.
*/ */
......
...@@ -56,7 +56,7 @@ class CommitOrderCalculator ...@@ -56,7 +56,7 @@ class CommitOrderCalculator
* Uses a depth-first search (DFS) to traverse the graph. * Uses a depth-first search (DFS) to traverse the graph.
* The desired topological sorting is the reverse postorder of these searches. * The desired topological sorting is the reverse postorder of these searches.
* *
* @return array The list of ordered items. These are the items wrapped in the nodes. * @return array The list of ordered classes.
*/ */
public function getCommitOrder() public function getCommitOrder()
{ {
...@@ -65,7 +65,7 @@ class CommitOrderCalculator ...@@ -65,7 +65,7 @@ class CommitOrderCalculator
if ($nodeCount == 0) { if ($nodeCount == 0) {
return array(); return array();
} else if ($nodeCount == 1) { } else if ($nodeCount == 1) {
return $this->_classes; return array(0 => array_pop($this->_classes));
} }
// Init // Init
...@@ -102,7 +102,6 @@ class CommitOrderCalculator ...@@ -102,7 +102,6 @@ class CommitOrderCalculator
} }
$this->_nodeStates[$node->name] = self::VISITED; $this->_nodeStates[$node->name] = self::VISITED;
$this->_sorted[] = $node; $this->_sorted[] = $node;
} }
......
...@@ -363,9 +363,8 @@ class ObjectHydrator extends AbstractHydrator ...@@ -363,9 +363,8 @@ class ObjectHydrator extends AbstractHydrator
if ($this->_rsm->isMixed) { if ($this->_rsm->isMixed) {
$element = array($key => $element); $element = array($key => $element);
$result[] = $element; $result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter; ++$this->_resultCounter;
end($result);
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
} else { } else {
$result[$key] = $element; $result[$key] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key; $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key;
...@@ -373,11 +372,10 @@ class ObjectHydrator extends AbstractHydrator ...@@ -373,11 +372,10 @@ class ObjectHydrator extends AbstractHydrator
} else { } else {
if ($this->_rsm->isMixed) { if ($this->_rsm->isMixed) {
$element = array(0 => $element); $element = array(0 => $element);
++$this->_resultCounter;
} }
$result[] = $element; $result[] = $element;
end($result); $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); ++$this->_resultCounter;
} }
// Update result pointer // Update result pointer
......
...@@ -86,6 +86,11 @@ class ClassMetadataFactory ...@@ -86,6 +86,11 @@ class ClassMetadataFactory
{ {
return $this->_cacheDriver; return $this->_cacheDriver;
} }
public function getLoadedMetadata()
{
return $this->_loadedMetadata;
}
/** /**
* Gets the class metadata descriptor for a class. * Gets the class metadata descriptor for a class.
......
...@@ -91,9 +91,9 @@ abstract class AbstractFileDriver implements Driver ...@@ -91,9 +91,9 @@ abstract class AbstractFileDriver implements Driver
* documents and operates in the specified operating mode. * documents and operates in the specified operating mode.
* *
* @param string|array $paths One or multiple paths where mapping documents can be found. * @param string|array $paths One or multiple paths where mapping documents can be found.
* @param integer $mode The operating mode. Either PRELOAD (default) or FILE_PER_CLASS. * @param integer $mode The operating mode. Either PRELOAD or FILE_PER_CLASS (default).
*/ */
public function __construct($paths, $mode = self::PRELOAD) public function __construct($paths, $mode = self::FILE_PER_CLASS)
{ {
$this->_paths = $paths; $this->_paths = $paths;
$this->_mode = $mode; $this->_mode = $mode;
......
...@@ -120,6 +120,10 @@ class OneToOneMapping extends AssociationMapping ...@@ -120,6 +120,10 @@ class OneToOneMapping extends AssociationMapping
$this->orphanRemoval = isset($mapping['orphanRemoval']) ? $this->orphanRemoval = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false; (bool) $mapping['orphanRemoval'] : false;
/*if ($this->isOptional) {
$this->fetchMode = self::FETCH_EAGER;
}*/
return $mapping; return $mapping;
} }
......
...@@ -82,7 +82,7 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect ...@@ -82,7 +82,7 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
private $_backRefFieldName; private $_backRefFieldName;
/** /**
* The class descriptor of the owning entity. * The class descriptor of the collection's entity type.
*/ */
private $_typeClass; private $_typeClass;
...@@ -124,7 +124,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect ...@@ -124,7 +124,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
/** /**
* INTERNAL: * INTERNAL:
* Sets the collection owner. Used (only?) during hydration. * Sets the collection's owning entity together with the AssociationMapping that
* describes the association between the owner and the elements of the collection.
* *
* @param object $entity * @param object $entity
* @param AssociationMapping $assoc * @param AssociationMapping $assoc
...@@ -168,7 +169,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect ...@@ -168,7 +169,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
/** /**
* INTERNAL: * INTERNAL:
* Adds an element to a collection during hydration. * Adds an element to a collection during hydration. This will automatically
* complete bidirectional associations.
* *
* @param mixed $element The element to add. * @param mixed $element The element to add.
*/ */
...@@ -198,9 +200,23 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect ...@@ -198,9 +200,23 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
* @param mixed $key The key to set. * @param mixed $key The key to set.
* $param mixed $value The element to set. * $param mixed $value The element to set.
*/ */
public function hydrateSet($key, $value) public function hydrateSet($key, $element)
{ {
$this->_coll->set($key, $value); $this->_coll->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->_backRefFieldName) {
// Set back reference to owner
if ($this->_association->isOneToMany()) {
// OneToMany
$this->_typeClass->reflFields[$this->_backRefFieldName]
->setValue($element, $this->_owner);
} else {
// ManyToMany
$this->_typeClass->reflFields[$this->_backRefFieldName]
->getValue($element)->set($key, $this->_owner);
}
}
} }
/** /**
...@@ -307,9 +323,9 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect ...@@ -307,9 +323,9 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
} }
/** /**
* Sets the initialized flag of the collection, forcing it into that state.
* *
* @param $bool * @param boolean $bool
* @return unknown_type
*/ */
public function setInitialized($bool) public function setInitialized($bool)
{ {
......
...@@ -172,6 +172,7 @@ final class Query extends AbstractQuery ...@@ -172,6 +172,7 @@ final class Query extends AbstractQuery
// Calculate hash for dql query. // Calculate hash for dql query.
// TODO: Probably need to include query hints in hash calculation, because query hints // TODO: Probably need to include query hints in hash calculation, because query hints
// can have influence on the SQL. // can have influence on the SQL.
// TODO: Include _maxResults and _firstResult in hash calculation
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT'); $hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
$cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash); $cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash);
......
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
namespace Doctrine\ORM\Tools; namespace Doctrine\ORM\Tools;
use Doctrine\Common\Util\Inflector, use Doctrine\Common\Util\Inflector,
Doctrine\ORM\Tools\Cli\AbstractPrinter, Doctrine\ORM\Tools\Cli\Printers\AbstractPrinter,
Doctrine\ORM\Tools\Cli\AbstractTask, Doctrine\ORM\Tools\Cli\Tasks\AbstractTask,
Doctrine\ORM\Tools\Cli\Printer; Doctrine\ORM\Tools\Cli\Printers\AnsiColorPrinter;
/** /**
* Generic CLI Runner of Tasks * Generic CLI Runner of Tasks
...@@ -83,14 +83,16 @@ class Cli ...@@ -83,14 +83,16 @@ class Cli
public function __construct(AbstractPrinter $printer = null) public function __construct(AbstractPrinter $printer = null)
{ {
//$this->_printer = new Printer\Normal(); //$this->_printer = new Printer\Normal();
$this->_printer = $printer ?: new Printer\AnsiColor(); $this->_printer = $printer ?: new AnsiColorPrinter;
// Include core tasks // Include core tasks
$ns = 'Doctrine\ORM\Tools\Cli\Task'; $ns = 'Doctrine\ORM\Tools\Cli\Tasks';
$this->addTasks(array( $this->addTasks(array(
'help' => $ns . '\Help', 'help' => $ns . '\HelpTask',
'version' => $ns . '\Version', 'version' => $ns . '\VersionTask',
'schema-tool' => $ns . '\SchemaToolTask',
'run-sql' => $ns . '\RunSqlTask'
)); ));
} }
...@@ -146,12 +148,12 @@ class Cli ...@@ -146,12 +148,12 @@ class Cli
// Automatically prepend 'help' task if: // Automatically prepend 'help' task if:
// 1- No arguments were passed // 1- No arguments were passed
// 2- First item is not a valid task name // 2- First item is not a valid task name
if (empty($args) || (isset($args[0]) && strpos($args[0], '-') !== false)) { if (empty($args) || ! isset($this->_tasks[$this->_processTaskName($args[0])])) {
array_unshift($args, 'help'); array_unshift($args, 'help');
} }
// Process all sent arguments // Process all sent arguments
$processedArgs = $this->_processArguments($args); $processedArgs = $this->_processArguments($args);
try { try {
// Handle possible multiple tasks on a single command // Handle possible multiple tasks on a single command
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli; namespace Doctrine\ORM\Tools\Cli\Printers;
use Doctrine\ORM\Tools\Cli\Style;
/** /**
* CLI Output Printer. * CLI Output Printer.
...@@ -137,7 +139,7 @@ abstract class AbstractPrinter ...@@ -137,7 +139,7 @@ abstract class AbstractPrinter
} }
/** /**
* Writes to output stream the message, formatting it by applying the defined style. * Writes to the output stream, formatting it by applying the defined style.
* *
* @param string $message Message to be outputted * @param string $message Message to be outputted
* @param mixed $style Optional style to be applied in message * @param mixed $style Optional style to be applied in message
...@@ -149,6 +151,17 @@ abstract class AbstractPrinter ...@@ -149,6 +151,17 @@ abstract class AbstractPrinter
fwrite($this->_stream, $this->format($message, $style)); fwrite($this->_stream, $this->format($message, $style));
} }
/**
* Writes a line to the output stream, formatting it by applying the defined style.
*
* @param string $message Message to be outputted
* @param mixed $style Optional style to be applied in message
*/
public function writeln($message, $style = 'ERROR')
{
$this->write($message . PHP_EOL, $style);
}
/** /**
* Formats the given message with the defined style. * Formats the given message with the defined style.
* *
......
...@@ -19,10 +19,9 @@ ...@@ -19,10 +19,9 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli\Printer; namespace Doctrine\ORM\Tools\Cli\Printers;
use Doctrine\ORM\Tools\Cli\AbstractPrinter, use Doctrine\ORM\Tools\Cli\Style;
Doctrine\ORM\Tools\Cli\Style;
/** /**
* CLI Output Printer for ANSI Color terminal * CLI Output Printer for ANSI Color terminal
...@@ -35,7 +34,7 @@ use Doctrine\ORM\Tools\Cli\AbstractPrinter, ...@@ -35,7 +34,7 @@ use Doctrine\ORM\Tools\Cli\AbstractPrinter,
* @author Jonathan Wage <jonwage@gmail.com> * @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class AnsiColor extends AbstractPrinter class AnsiColorPrinter extends AbstractPrinter
{ {
/** /**
* @inheritdoc * @inheritdoc
......
...@@ -19,10 +19,9 @@ ...@@ -19,10 +19,9 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli\Printer; namespace Doctrine\ORM\Tools\Cli\Printers;
use Doctrine\ORM\Tools\Cli\AbstractPrinter, use Doctrine\ORM\Tools\Cli\Style;
Doctrine\ORM\Tools\Cli\Style;
/** /**
* CLI Output Printer for Normal terminal * CLI Output Printer for Normal terminal
...@@ -35,7 +34,7 @@ use Doctrine\ORM\Tools\Cli\AbstractPrinter, ...@@ -35,7 +34,7 @@ use Doctrine\ORM\Tools\Cli\AbstractPrinter,
* @author Jonathan Wage <jonwage@gmail.com> * @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class Normal extends AbstractPrinter class NormalPrinter extends AbstractPrinter
{ {
/** /**
* @inheritdoc * @inheritdoc
......
...@@ -19,12 +19,21 @@ ...@@ -19,12 +19,21 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli; namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\Cli\Printers\AbstractPrinter;
/** /**
* CLI Task. * Base class for CLI Tasks.
* Provides basic methods and requires implementation of methods that * Provides basic methods and requires implementation of methods that
* each task should implement in order to correctly work. * each task should implement in order to correctly work.
*
* The following arguments are common to all tasks:
*
* Argument: --config=<path>
* Description: Specifies the path to the configuration file to use. The configuration file
* can bootstrap an EntityManager as well as provide defaults for any cli
* arguments.
* *
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org * @link www.doctrine-project.org
...@@ -51,6 +60,8 @@ abstract class AbstractTask ...@@ -51,6 +60,8 @@ abstract class AbstractTask
*/ */
protected $_availableTasks; protected $_availableTasks;
protected $_em;
/** /**
* Defines a CLI Output Printer * Defines a CLI Output Printer
* *
...@@ -148,13 +159,44 @@ abstract class AbstractTask ...@@ -148,13 +159,44 @@ abstract class AbstractTask
* *
* @return boolean * @return boolean
*/ */
abstract public function validate(); public function validate()
{
if ( ! isset($this->_arguments['config'])) {
if (file_exists('./cli-config.php')) {
require './cli-config.php';
} else {
$this->_printer->writeln('--config option or cli-config.php in the same directory required', 'ERROR');
return false;
}
} else {
require $this->_arguments['config'];
}
// $em and $args come from the config
if (isset($em)) {
$this->_em = $em;
}
if (isset($args)) {
// Merge arguments. Values specified via the CLI take preference.
$this->_arguments = array_merge($args, $this->_arguments);
}
return true;
}
/** /**
* Safely execution of task. * Safely execution of task.
* Each CLI task should implement this as normal flow execution of * Each CLI task should implement this as normal flow execution of
* what is supposed to do. * what is supposed to do.
*
*/ */
abstract public function run(); abstract public function run();
protected function _requireEntityManager()
{
if ( ! isset($this->_em)) {
$this->_printer->writeln('No EntityManager created in configuration but required by task ' . get_class($this), 'ERROR');
return false;
}
return true;
}
} }
\ No newline at end of file
<?php
namespace Doctrine\ORM\Tools\Cli\Tasks;
/**
* Task for creating XML or YAML mappings based on an existing database schema.
*
* @author robo
* @since 2.0
*/
class CreateMappingTask extends AbstractTask
{
}
\ No newline at end of file
...@@ -19,9 +19,7 @@ ...@@ -19,9 +19,7 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli\Task; namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\Cli\AbstractTask;
/** /**
* CLI Task to display available commands help * CLI Task to display available commands help
...@@ -34,7 +32,7 @@ use Doctrine\ORM\Tools\Cli\AbstractTask; ...@@ -34,7 +32,7 @@ use Doctrine\ORM\Tools\Cli\AbstractTask;
* @author Jonathan Wage <jonwage@gmail.com> * @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class Help extends AbstractTask class HelpTask extends AbstractTask
{ {
/** /**
* @inheritdoc * @inheritdoc
......
<?php
namespace Doctrine\ORM\Tools\Cli\Tasks;
/**
* Task for executing arbitrary SQL that can come from a file or directly from
* the command line.
*
* @author robo
* @since 2.0
*/
class RunSqlTask extends AbstractTask
{
/**
* @inheritdoc
*/
public function extendedHelp()
{
$this->getPrinter()->writeln('run-sql extended help.', 'INFO');
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->getPrinter()->writeln('run-sql basic help.', 'INFO');
}
/**
* Executes the task.
*/
public function run()
{
$args = $this->getArguments();
if (isset($args['file'])) {
//TODO
} else if (isset($args['sql'])) {
if (preg_match('/^select/i', $args['sql'])) {
$stmt = $this->_em->getConnection()->execute($args['sql']);
var_dump($stmt->fetchAll(\Doctrine\DBAL\Connection::FETCH_ASSOC));
} else {
var_dump($this->_em->getConnection()->executeUpdate($args['sql']));
}
}
}
}
\ No newline at end of file
<?php
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\SchemaTool,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
Doctrine\ORM\Mapping\Driver\XmlDriver,
Doctrine\ORM\Mapping\Driver\YamlDriver;
/**
* Task to create the database schema for a set of classes based on their mappings.
*
* This task has the following arguments:
*
* <tt>--classdir=<path></tt>
* Specifies the directory where to start looking for mapped classes.
* This argument is required when the annotation metadata driver is used,
* otherwise it has no effect.
*
* <tt>--dump-sql</tt>
* Specifies that instead of directly executing the SQL statements for creating the
* database schema, they should be printed to the standard output.
*
* <tt>--create</tt>
* Specifies that the schema of the classes should be created.
*
* <tt>--drop</tt>
* Specifies that the schema of the classes should be dropped.
*
* <tt>--update</tt>
* Specifies that the schema of the classes should be updated.
*
*
* @author robo
* @since 2.0
*/
class SchemaToolTask extends AbstractTask
{
/**
* @inheritdoc
*/
public function extendedHelp()
{
$this->getPrinter()->writeln('create-schema extended help.', 'INFO');
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->getPrinter()->writeln('create-schema basic help.', 'INFO');
}
/**
* @inheritdoc
*/
public function validate()
{
if ( ! parent::validate()) {
return false;
}
$args = $this->getArguments();
$printer = $this->getPrinter();
if ( ! $this->_requireEntityManager()) {
return false;
}
$isCreate = isset($args['create']);
$isDrop = isset($args['drop']);
$isUpdate = isset($args['update']);
if ( ! ($isCreate ^ $isDrop ^ $isUpdate)) {
$printer->writeln("One of --create, --drop or --update required, and only one.", 'ERROR');
return false;
}
if ($this->_em->getConfiguration()->getMetadataDriverImpl() instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver
&& ! isset($args['classdir'])) {
$printer->writeln("The supplied configuration uses the annotation metadata driver."
. " The 'classdir' argument is required for this driver.", 'ERROR');
return false;
}
return true;
}
/**
* Executes the task.
*/
public function run()
{
$args = $this->getArguments();
$isCreate = isset($args['create']);
$isDrop = isset($args['drop']);
$isUpdate = isset($args['update']);
$cmf = $this->_em->getMetadataFactory();
$driver = $this->_em->getConfiguration()->getMetadataDriverImpl();
$classes = array();
if ($driver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
$iter = new \FilesystemIterator($args['classdir']);
$declared = get_declared_classes();
foreach ($iter as $item) {
$baseName = $item->getBaseName();
if ($baseName[0] == '.') {
continue;
}
require_once $item->getPathName();
}
$declared = array_diff(get_declared_classes(), $declared);
foreach ($declared as $className) {
if ( ! $driver->isTransient($className)) {
$classes[] = $cmf->getMetadataFor($className);
}
}
} else {
$driver->preload();
$classes = $cmf->getLoadedMetadata();
}
$printer = $this->getPrinter();
$tool = new SchemaTool($this->_em);
if ($isCreate) {
if (isset($args['dump-sql'])) {
foreach ($tool->getCreateSchemaSql($classes) as $sql) {
$printer->writeln($sql, 'NONE');
}
} else {
$printer->writeln('Creating database schema...', 'INFO');
$tool->createSchema($classes);
$printer->write('Database schema created successfully.' . PHP_EOL, 'INFO');
}
} else if ($isDrop) {
if (isset($args['dump-sql'])) {
foreach ($tool->getDropSchemaSql($classes) as $sql) {
$printer->writeln($sql, 'NONE');
}
} else {
$printer->writeln('Dropping database schema...', 'INFO');
$tool->dropSchema($classes);
$printer->writeln('Database schema dropped successfully.', 'INFO');
}
} else if ($isUpdate) {
//TODO
$printer->writeln('--update not yet implemented.', 'COMMENT');
}
}
}
\ No newline at end of file
...@@ -19,9 +19,7 @@ ...@@ -19,9 +19,7 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools\Cli\Task; namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\Cli\AbstractTask;
/** /**
* CLI Task to display the doctrine version * CLI Task to display the doctrine version
...@@ -34,7 +32,7 @@ use Doctrine\ORM\Tools\Cli\AbstractTask; ...@@ -34,7 +32,7 @@ use Doctrine\ORM\Tools\Cli\AbstractTask;
* @author Jonathan Wage <jonwage@gmail.com> * @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class Version extends AbstractTask class VersionTask extends AbstractTask
{ {
/** /**
* @inheritdoc * @inheritdoc
......
...@@ -22,17 +22,17 @@ ...@@ -22,17 +22,17 @@
namespace Doctrine\ORM\Tools; namespace Doctrine\ORM\Tools;
use Doctrine\DBAL\Types\Type, use Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager; Doctrine\ORM\EntityManager,
Doctrine\ORM\Internal\CommitOrderCalculator;
/** /**
* The SchemaTool is a tool to create and/or drop database schemas based on * The SchemaTool is a tool to create/drop/update database schemas based on
* <tt>ClassMetadata</tt> class descriptors. * <tt>ClassMetadata</tt> class descriptors.
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision: 4805 $
*/ */
class SchemaTool class SchemaTool
{ {
...@@ -382,8 +382,9 @@ class SchemaTool ...@@ -382,8 +382,9 @@ class SchemaTool
public function getDropSchemaSql(array $classes) public function getDropSchemaSql(array $classes)
{ {
$sql = array(); $sql = array();
$commitOrder = $classes; //FIXME: get real commit order!!
$commitOrder = $this->_getCommitOrder($classes);
// Drop tables in reverse commit order // Drop tables in reverse commit order
for ($i = count($commitOrder) - 1; $i >= 0; --$i) { for ($i = count($commitOrder) - 1; $i >= 0; --$i) {
$class = $commitOrder[$i]; $class = $commitOrder[$i];
...@@ -393,6 +394,8 @@ class SchemaTool ...@@ -393,6 +394,8 @@ class SchemaTool
$sql[] = $this->_platform->getDropTableSql($class->getTableName()); $sql[] = $this->_platform->getDropTableSql($class->getTableName());
} }
//TODO: Drop other schema elements, like sequences etc.
return $sql; return $sql;
} }
...@@ -529,4 +532,26 @@ class SchemaTool ...@@ -529,4 +532,26 @@ class SchemaTool
return $sql; return $sql;
} }
private function _getCommitOrder(array $classes)
{
$calc = new CommitOrderCalculator;
// Calculate dependencies
foreach ($classes as $class) {
$calc->addClass($class);
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide) {
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if ( ! $calc->hasClass($targetClass->name)) {
$calc->addClass($targetClass);
}
// add dependency ($targetClass before $class)
$calc->addDependency($targetClass, $class);
}
}
}
return $calc->getCommitOrder();
}
} }
...@@ -1290,7 +1290,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -1290,7 +1290,7 @@ class UnitOfWork implements PropertyChangedListener
$managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy); $managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy);
$entityVersion = $class->reflFields[$class->versionField]->getValue($entity); $entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
// Throw exception if versions dont match. // Throw exception if versions dont match.
if ($managedCopyVersion != $entity) { if ($managedCopyVersion != $entityVersion) {
throw OptimisticLockException::versionMismatch(); throw OptimisticLockException::versionMismatch();
} }
} }
......
...@@ -41,7 +41,7 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase ...@@ -41,7 +41,7 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testXmlPreloadMode() public function testXmlPreloadMode()
{ {
$className = 'Doctrine\Tests\ORM\Mapping\User'; $className = 'Doctrine\Tests\ORM\Mapping\User';
$xmlDriver = new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml'); $xmlDriver = new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml', XmlDriver::PRELOAD);
$class = new ClassMetadata($className); $class = new ClassMetadata($className);
$classNames = $xmlDriver->preload(); $classNames = $xmlDriver->preload();
...@@ -57,7 +57,7 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase ...@@ -57,7 +57,7 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testYamlPreloadMode() public function testYamlPreloadMode()
{ {
$className = 'Doctrine\Tests\ORM\Mapping\User'; $className = 'Doctrine\Tests\ORM\Mapping\User';
$yamlDriver = new YamlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'yaml'); $yamlDriver = new YamlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'yaml', YamlDriver::PRELOAD);
$class = new ClassMetadata($className); $class = new ClassMetadata($className);
$classNames = $yamlDriver->preload(); $classNames = $yamlDriver->preload();
......
<?php
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
$connectionOptions = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
$args = array(
'classdir' => './Entities'
);
\ No newline at end of file
...@@ -6,9 +6,17 @@ $classLoader = new \Doctrine\Common\ClassLoader(); ...@@ -6,9 +6,17 @@ $classLoader = new \Doctrine\Common\ClassLoader();
$classLoader->setBasePath('Doctrine', realpath(__DIR__ . '/../../lib')); $classLoader->setBasePath('Doctrine', realpath(__DIR__ . '/../../lib'));
$classLoader->setBasePath('Entities', __DIR__); $classLoader->setBasePath('Entities', __DIR__);
$config = new \Doctrine\ORM\Configuration(); $config = new \Doctrine\ORM\Configuration;
$config->setMetadataCacheImpl(new \Doctrine\ORM\Cache\ArrayCache); $cache = new \Doctrine\Common\Cache\ApcCache;
$config->setMetadataDriverImpl(new \Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__ . '/schema')); $config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
# EXAMPLE FOR YAML DRIVER
#$config->setMetadataDriverImpl(new \Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__ . '/yaml'));
# EXAMPLE FOR XML DRIVER
#$config->setMetadataDriverImpl(new \Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__ . '/xml'));
$eventManager = new \Doctrine\Common\EventManager(); $eventManager = new \Doctrine\Common\EventManager();
$connectionOptions = array( $connectionOptions = array(
'driver' => 'pdo_sqlite', 'driver' => 'pdo_sqlite',
......
#!/usr/bin/env php
<?php
require __DIR__ . '/../../lib/Doctrine/Common/ClassLoader.php';
$classLoader = new \Doctrine\Common\ClassLoader();
$classLoader->setBasePath('Doctrine', __DIR__ . '/../../lib');
$cli = new \Doctrine\ORM\Tools\Cli();
$cli->run($_SERVER['argv']);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment