From 320d21e2bee8c4d4c9c03e8a997f3778daf3d8bf Mon Sep 17 00:00:00 2001 From: romanb Date: Fri, 11 Sep 2009 19:50:48 +0000 Subject: [PATCH] [2.0] Refactored classloader architecture. Renamed ClassLoader => GlobalClassLoader. Introduced IsolatedClassLoader that is suitable for participating in autoload stacks. Added 2 example entity classes to the sandbox with 2 xml mappings and 2 yaml mappings. Simplified sandbox setup. --- lib/Doctrine/Common/ClassLoader.php | 184 ------------------ lib/Doctrine/Common/GlobalClassLoader.php | 136 +++++++++++++ lib/Doctrine/Common/IsolatedClassLoader.php | 117 +++++++++++ .../ORM/Mapping/ClassMetadataFactory.php | 5 +- .../ORM/Mapping/Driver/YamlDriver.php | 7 +- lib/Doctrine/ORM/Query/Parser.php | 8 +- lib/Doctrine/ORM/Query/SqlWalker.php | 27 ++- .../ORM/Tools/Cli/Tasks/SchemaToolTask.php | 5 + .../Doctrine/Tests/Common/ClassLoaderTest.php | 43 ++-- .../ORM/Query/SelectSqlGenerationTest.php | 8 + tests/Doctrine/Tests/TestInit.php | 8 +- tools/sandbox/Entities/Address.php | 40 ++++ tools/sandbox/Entities/User.php | 42 ++++ tools/sandbox/cli-config.php | 21 +- tools/sandbox/config.php | 28 --- tools/sandbox/doctrine.php | 7 +- tools/sandbox/index.php | 34 +++- tools/sandbox/xml/Entities.Address.dcm.xml | 15 ++ tools/sandbox/xml/Entities.User.dcm.xml | 17 ++ tools/sandbox/yaml/Entities.Address.dcm.yml | 16 ++ tools/sandbox/yaml/Entities.User.dcm.yml | 18 ++ 21 files changed, 522 insertions(+), 264 deletions(-) delete mode 100644 lib/Doctrine/Common/ClassLoader.php create mode 100644 lib/Doctrine/Common/GlobalClassLoader.php create mode 100644 lib/Doctrine/Common/IsolatedClassLoader.php create mode 100644 tools/sandbox/Entities/Address.php create mode 100644 tools/sandbox/Entities/User.php delete mode 100644 tools/sandbox/config.php create mode 100644 tools/sandbox/xml/Entities.Address.dcm.xml create mode 100644 tools/sandbox/xml/Entities.User.dcm.xml create mode 100644 tools/sandbox/yaml/Entities.Address.dcm.yml create mode 100644 tools/sandbox/yaml/Entities.User.dcm.yml diff --git a/lib/Doctrine/Common/ClassLoader.php b/lib/Doctrine/Common/ClassLoader.php deleted file mode 100644 index e22b57b51..000000000 --- a/lib/Doctrine/Common/ClassLoader.php +++ /dev/null @@ -1,184 +0,0 @@ -. - */ - -namespace Doctrine\Common; - -/** - * A class loader used to load class files on demand. - * - * IMPORTANT: - * - * This class loader is NOT meant to be put into a "chain" of autoloaders. - * It is not meant to load only Doctrine class file. It is a one-classloader-for-all-classes - * solution. It may not be useable with frameworks that do not follow basic pear/zend - * conventions where the namespace+class name reflects the physical location of the source - * file. This is not a bug. This class loader is, however, compatible with the - * old namespace separator '_' (underscore), so any classes using that convention - * instead of the 5.3 builtin namespaces can be loaded as well. - * - * The only way to put this classloader into an autoloader chain is to use - * setCheckFileExists(true) which is not recommended. - * - * Here is the recommended usage: - * 1) Use only 1 class loader instance. - * 2) Reduce the include_path to only the path to the PEAR packages. - * 2) Set the base paths to any non-pear class libraries through - * $classLoader->setBasePath($prefix, $basePath); - * 3) DO NOT setCheckFileExists(true). Doing so is expensive in terms of performance. - * 4) Use an opcode-cache (i.e. APC) (STRONGLY RECOMMENDED). - * - * The "prefix" is the part of a class name before the very first namespace separator - * character. If the class is named "Foo_Bar_Baz" then the prefix is "Foo". - * - * If no base path is configured for a certain class prefix, the classloader relies on - * the include_path. That's why classes of any pear packages can be loaded without - * registering their base paths. However, since a long include_path has a negative effect - * on performance it is recommended to have only the path to the pear packages in the - * include_path. - * - * For any other class libraries you always have the choice between registering the base - * path on the classloader or putting the base path into the include_path. The former - * should be preferred but the latter is fine also. - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 2.0 - * @version $Revision: 3938 $ - * @author Guilherme Blanco - * @author Jonathan Wage - * @author Roman Borschel - */ -class ClassLoader -{ - /** - * @var string Namespace separator - */ - private $_namespaceSeparator = '\\'; - - /** - * @var string File extension used for classes - */ - private $_fileExtension = '.php'; - - /** - * @var boolean Flag to inspect if file exists in codebase before include it - */ - private $_checkFileExists = false; - - /** - * @var array Hashmap of base paths that Autoloader will look into - */ - private $_basePaths = array(); - - /** - * Constructor registers the autoloader automatically - * - */ - public function __construct() - { - spl_autoload_register(array($this, 'loadClass')); - } - - /** - * Set check file exists - * - * @param boolean $bool - * @return void - */ - public function setCheckFileExists($bool) - { - $this->_checkFileExists = $bool; - } - - /** - * Set class file extension - * - * @param string $extension - * @return void - */ - public function setClassFileExtension($extension) - { - $this->_fileExtension = $extension; - } - - /** - * Sets the namespace separator to use. - * - * @param string $separator - * @return void - */ - public function setNamespaceSeparator($separator) - { - $this->_namespaceSeparator = $separator; - } - - /** - * Sets a static base path for classes with a certain prefix that is prepended - * to the path derived from the class itself. - * - * @param string $classPrefix - * @param string $basePath - */ - public function setBasePath($classPrefix, $basePath) - { - $this->_basePaths[$classPrefix] = $basePath; - } - - /** - * Loads the given class or interface. - * - * @param string $classname The name of the class to load. - * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise. - */ - public function loadClass($className) - { - if (class_exists($className, false) || interface_exists($className, false)) { - return false; - } - - $prefix = ''; - $separator = $this->_namespaceSeparator; - if (($pos = strpos($className, $this->_namespaceSeparator)) !== false) { - $prefix = substr($className, 0, strpos($className, $this->_namespaceSeparator)); - } else if (($pos = strpos($className, '_')) !== false) { - // Support for '_' namespace separator for compatibility with Zend/PEAR/... - $prefix = substr($className, 0, strpos($className, '_')); - $separator = '_'; - } - - // If we have a custom path for namespace, use it - $class = ((isset($this->_basePaths[$prefix])) ? $this->_basePaths[$prefix] . DIRECTORY_SEPARATOR : '') - . str_replace($separator, DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; - - // Assure file exists in codebase before require if flag is active - if ($this->_checkFileExists) { - if (($fh = @fopen($class, 'r', true)) === false) { - return false; - } - - @fclose($fh); - } - - require $class; - - return true; - } -} \ No newline at end of file diff --git a/lib/Doctrine/Common/GlobalClassLoader.php b/lib/Doctrine/Common/GlobalClassLoader.php new file mode 100644 index 000000000..efa4e7522 --- /dev/null +++ b/lib/Doctrine/Common/GlobalClassLoader.php @@ -0,0 +1,136 @@ +. + */ + +namespace Doctrine\Common; + +/** + * A GlobalClassLoader is an autoloader for class files that can be + * installed on the SPL autoload stack. A GlobalClassLoader must be the only + * autoloader on the stack and be used for all classes. + * + * The GlobalClassLoader assumes the PHP 5.3 namespace separator but + * is also compatible with the underscore "_" namespace separator. + * + * A recommended class loading setup for optimal performance looks as follows: + * + * 1) Use a GlobalClassLoader. + * 2) Reduce the include_path to only the path to the PEAR packages. + * 2) Register the namespaces of any other (non-pear) class library with their + * absolute base paths, like this: $gcl->registerNamespace('Zend', '/path/to/zf-lib'); + * + * If no base path is configured for a certain namespace, the GlobalClassLoader relies on + * the include_path. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GlobalClassLoader +{ + /** + * @var string File extension used for classes + */ + private $_defaultFileExtension = '.php'; + + /** + * @var array The custom file extensions of class libraries. + */ + private $_fileExtensions = array(); + + /** + * @var array Hashmap of base paths to class libraries. + */ + private $_basePaths = array(); + + /** + * Installs this class loader on the SPL autoload stack as the only class loader. + * + * @throws DoctrineException If the SPL autoload stack already contains other autoloaders. + */ + public function register() + { + if (spl_autoload_functions() !== false) { + throw new DoctrineException("Autoload stack is not empty. GlobalClassLoader does not work " + . "in an autoload stack."); + } + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Sets the default file extension of class files. + * + * @param string $extension + * @return void + */ + public function setDefaultFileExtension($extension) + { + $this->_fileExtension = $extension; + } + + /** + * Sets a static base path for classes with a certain prefix that is prepended + * to the path derived from the class itself. + * + * @param string $classPrefix The prefix (root namespace) of the class library. + * @param string $basePath The base path to the class library. + * @param string $fileExtension The custom file extension used by the class files in the namespace. + */ + public function registerNamespace($namespace, $basePath, $fileExtension = null) + { + $this->_basePaths[$namespace] = $basePath; + if ($fileExtension !== null) { + $this->_fileExtensions[$namespace] = $fileExtension; + } + } + + /** + * Loads the given class or interface. + * + * @param string $classname The name of the class to load. + * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise. + */ + public function loadClass($className) + { + $prefix = ''; + $separator = '\\'; + + if (($pos = strpos($className, $separator)) !== false) { + $prefix = substr($className, 0, strpos($className, $separator)); + } else if (($pos = strpos($className, '_')) !== false) { + // Support for '_' namespace separator for compatibility with Zend/PEAR/... + $prefix = substr($className, 0, strpos($className, '_')); + $separator = '_'; + } + + // Build the class file name + $class = ((isset($this->_basePaths[$prefix])) ? + $this->_basePaths[$prefix] . DIRECTORY_SEPARATOR : '') + . str_replace($separator, DIRECTORY_SEPARATOR, $className) + . (isset($this->_fileExtensions[$prefix]) ? + $this->_fileExtensions[$prefix] : $this->_defaultFileExtension); + + require $class; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Common/IsolatedClassLoader.php b/lib/Doctrine/Common/IsolatedClassLoader.php new file mode 100644 index 000000000..969be465e --- /dev/null +++ b/lib/Doctrine/Common/IsolatedClassLoader.php @@ -0,0 +1,117 @@ +. + */ + +namespace Doctrine\Common; + +/** + * An IsolatedClassLoader is an autoloader for class files that can be + * installed on the SPL autoload stack. It is a class loader that loads only classes + * of a specific namespace and is suitable for working together with other autoloaders + * in the SPL autoload stack. + * + * If no base path is configured, an IsolatedClassLoader relies on the include_path. + * + * @author Roman Borschel + * @since 2.0 + */ +class IsolatedClassLoader +{ + private $_fileExtension = '.php'; + private $_namespace; + private $_basePath; + private $_namespaceSeparator = '\\'; + + /** + * Creates a new IsolatedClassLoader that loads classes of the + * specified namespace. + * + * @param string $ns The namespace to use. + */ + public function __construct($ns) + { + $this->_namespace = $ns; + } + + /** + * Sets the namespace separator used by classes in the namespace of this class loader. + * + * @param string $sep The separator to use. + */ + public function setNamespaceSeparator($sep) + { + $this->_namespaceSeparator = $sep; + } + + /** + * Sets the base include path for all class files in the namespace of this class loader. + * + * @param string $basePath + */ + public function setBasePath($basePath) + { + $this->_basePath = $basePath; + } + + /** + * Sets the file extension of class files in the namespace of this class loader. + * + * @param string $fileExtension + */ + public function setFileExtension($fileExtension) + { + $this->_fileExtension = $fileExtension; + } + + /** + * Installs this class loader on the SPL autoload stack. + */ + public function register() + { + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $classname The name of the class to load. + * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise. + */ + public function loadClass($className) + { + if (class_exists($className, false) || interface_exists($className, false)) { + return false; + } + + if (strpos($className, $this->_namespace) !== 0) { + return false; + } + + // Build the class file name + $class = ($this->_basePath !== null ? $this->_basePath . DIRECTORY_SEPARATOR : '') + . str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $className) + . $this->_fileExtension; + + require $class; + + return true; + } + +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 98b7ae1f2..96f28ea8d 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -113,6 +113,7 @@ class ClassMetadataFactory $this->_loadMetadata($className); } } + return $this->_loadedMetadata[$className]; } @@ -158,7 +159,7 @@ class ClassMetadataFactory } $parentClasses = array_reverse($parentClasses); $parentClasses[] = $name; - + // Move down the hierarchy of parent classes, starting from the topmost class $parent = null; $visited = array(); @@ -184,7 +185,7 @@ class ClassMetadataFactory $class->setVersionField($parent->versionField); $class->setDiscriminatorMap($parent->discriminatorMap); } - + // Invoke driver $this->_driver->loadMetadataForClass($className, $class); diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 6012c1396..62d816426 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -21,7 +21,8 @@ namespace Doctrine\ORM\Mapping\Driver; -use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\Common\DoctrineException; if ( ! class_exists('sfYaml', false)) { require_once __DIR__ . '/../../../../vendor/sfYaml/sfYaml.class.php'; @@ -48,9 +49,9 @@ class YamlDriver extends AbstractFileDriver public function loadMetadataForClass($className, ClassMetadata $metadata) { $class = $metadata->getReflectionClass(); - + $element = $this->getElement($className); - + if ($element['type'] == 'entity') { $metadata->setCustomRepositoryClass( isset($element['repositoryClass']) ? $xmlRoot['repositoryClass'] : null diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 821ee9ded..f086351a5 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -1286,10 +1286,10 @@ class Parser if ($glimpse['value'] != '.') { $token = $this->_lexer->lookahead; - $resultVariable = $this->ResultVariable(); + $expr = $this->ResultVariable(); // Check if ResultVariable is defined in query components - $queryComponent = $this->_validateIdentificationVariable($resultVariable, null, $token); + $queryComponent = $this->_validateIdentificationVariable($expr, null, $token); // Outer defininition used in inner subselect is not enough. // ResultVariable exists in queryComponents, check nesting level @@ -1562,10 +1562,10 @@ class Parser if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { $token = $this->_lexer->lookahead; - $resultVariable = $this->ResultVariable(); + $fieldAliasIdentificationVariable = $this->ResultVariable(); // Include ResultVariable in query components. - $this->_queryComponents[$resultVariable] = array( + $this->_queryComponents[$fieldAliasIdentificationVariable] = array( 'resultvariable' => $expression, 'nestingLevel' => $this->_nestingLevel, 'token' => $token, diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index fe8d878ac..121ddaf02 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -59,6 +59,9 @@ class SqlWalker implements TreeWalker private $_query; private $_dqlToSqlAliasMap = array(); + /** Map from result variable names to their SQL column alias names. */ + private $_scalarResultAliasMap = array(); + /** Map of all components/classes that appear in the DQL query. */ private $_queryComponents; @@ -581,13 +584,19 @@ class SqlWalker implements TreeWalker public function walkOrderByItem($orderByItem) { $expr = $orderByItem->expression; - $parts = $expr->parts; - $dqlAlias = $expr->identificationVariable; - $class = $this->_queryComponents[$dqlAlias]['metadata']; - $columnName = $class->getQuotedColumnName($parts[0], $this->_platform); - - return $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.' - . $columnName . ' ' . strtoupper($orderByItem->type); + if ($expr instanceof AST\PathExpression) { + $parts = $expr->parts; + $dqlAlias = $expr->identificationVariable; + $class = $this->_queryComponents[$dqlAlias]['metadata']; + $columnName = $class->getQuotedColumnName($parts[0], $this->_platform); + + return $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.' + . $columnName . ' ' . strtoupper($orderByItem->type); + } else { + $columnName = $this->_queryComponents[$expr]['token']['value']; + + return $this->_scalarResultAliasMap[$columnName] . ' ' . strtoupper($orderByItem->type); + } } /** @@ -762,6 +771,7 @@ class SqlWalker implements TreeWalker $columnAlias = 'sclr' . $this->_aliasCounter++; $sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias; + $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addScalarResult($columnAlias, $resultAlias); @@ -773,9 +783,10 @@ class SqlWalker implements TreeWalker } else { $resultAlias = $selectExpression->fieldIdentificationVariable; } - + $columnAlias = 'sclr' . $this->_aliasCounter++; $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias; + $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addScalarResult($columnAlias, $resultAlias); diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php index 6b7675c16..132dc0391 100644 --- a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php @@ -164,6 +164,11 @@ class SchemaToolTask extends AbstractTask $printer = $this->getPrinter(); $tool = new SchemaTool($this->_em); + if (empty($classes)) { + $printer->writeln('No classes to process.', 'INFO'); + return; + } + if ($isCreate) { if (isset($args['dump-sql'])) { foreach ($tool->getCreateSchemaSql($classes) as $sql) { diff --git a/tests/Doctrine/Tests/Common/ClassLoaderTest.php b/tests/Doctrine/Tests/Common/ClassLoaderTest.php index 2b659d99c..e27b54c09 100644 --- a/tests/Doctrine/Tests/Common/ClassLoaderTest.php +++ b/tests/Doctrine/Tests/Common/ClassLoaderTest.php @@ -2,41 +2,32 @@ namespace Doctrine\Tests\Common; -use Doctrine\Common\ClassLoader; +use Doctrine\Common\GlobalClassLoader, + Doctrine\Common\IsolatedClassLoader; require_once __DIR__ . '/../TestInit.php'; class ClassLoaderTest extends \Doctrine\Tests\DoctrineTestCase { - public function testCustomFileExtensionAndNamespaceSeparator() + public function testGlobalClassLoaderThrowsExceptionIfPutInChain() { - $classLoader = new \Doctrine\Common\ClassLoader(); - $classLoader->setBasePath('ClassLoaderTest', __DIR__); - $classLoader->setClassFileExtension('.class.php'); + $this->setExpectedException('Doctrine\Common\DoctrineException'); + + $classLoader1 = new IsolatedClassLoader('Foo'); + $classLoader1->register(); + + $globalClassLoader = new GlobalClassLoader; + $globalClassLoader->register(); + } + + public function testIsolatedClassLoaderReturnsFalseOnClassExists() + { + $classLoader = new IsolatedClassLoader('ClassLoaderTest'); + $classLoader->setBasePath( __DIR__); + $classLoader->setFileExtension('.class.php'); $classLoader->setNamespaceSeparator('_'); $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassA'), true); - $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassB'), true); - } - - public function testClassLoaderCheckFileExists() - { - $classLoader = new \Doctrine\Common\ClassLoader(); - $classLoader->setBasePath('ClassLoaderTest', __DIR__); - $classLoader->setCheckFileExists(true); - - // This would return a fatal error without check file exists true - $this->assertEquals($classLoader->loadClass('SomeInvalidClass'), false); - } - - public function testAlreadyLoadedClassReturnsFalse() - { - $classLoader = new \Doctrine\Common\ClassLoader(); - $classLoader->setBasePath('ClassLoaderTest', __DIR__); - $classLoader->setClassFileExtension('.class.php'); - $classLoader->setNamespaceSeparator('_'); - $classLoader->setCheckFileExists(true); - $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassA'), false); $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassC'), true); } diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index aae29e47f..8f909b7c3 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -408,6 +408,14 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } + public function testOrderByCollectionAssociationSize() + { + $this->assertSqlGeneration( + "select u, size(u.articles) as numArticles from Doctrine\Tests\Models\CMS\CmsUser u order by numArticles", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT COUNT(c1_.user_id) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr4 FROM cms_users c0_ ORDER BY sclr4 ASC" + ); + } + /* Not yet implemented, needs more thought public function testSingleValuedAssociationFieldInWhere() { diff --git a/tests/Doctrine/Tests/TestInit.php b/tests/Doctrine/Tests/TestInit.php index 3de030c43..5ec03b1b9 100644 --- a/tests/Doctrine/Tests/TestInit.php +++ b/tests/Doctrine/Tests/TestInit.php @@ -8,11 +8,13 @@ error_reporting(E_ALL | E_STRICT); require_once 'PHPUnit/Framework.php'; require_once 'PHPUnit/TextUI/TestRunner.php'; -require_once __DIR__ . '/../../../lib/Doctrine/Common/ClassLoader.php'; +require_once __DIR__ . '/../../../lib/Doctrine/Common/IsolatedClassLoader.php'; -$classLoader = new \Doctrine\Common\ClassLoader(); +$classLoader = new \Doctrine\Common\IsolatedClassLoader('Doctrine'); +$classLoader->register(); set_include_path( - get_include_path() + '.' . PATH_SEPARATOR . __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'lib' ); + diff --git a/tools/sandbox/Entities/Address.php b/tools/sandbox/Entities/Address.php new file mode 100644 index 000000000..bb084c30e --- /dev/null +++ b/tools/sandbox/Entities/Address.php @@ -0,0 +1,40 @@ +id; + } + + public function getStreet() { + return $this->street; + } + + public function setStreet($street) { + $this->street = $street; + } + + public function getUser() { + return $this->user; + } + + public function setUser(User $user) { + if ($this->user !== $user) { + $this->user = $user; + $user->setAddress($this); + } + } +} + diff --git a/tools/sandbox/Entities/User.php b/tools/sandbox/Entities/User.php new file mode 100644 index 000000000..95487f570 --- /dev/null +++ b/tools/sandbox/Entities/User.php @@ -0,0 +1,42 @@ +id; + } + + public function getName() { + return $this->name; + } + + public function setName($name) { + $this->name = $name; + } + + public function getAddress() { + return $this->address; + } + + public function setAddress(Address $address) { + if ($this->address !== $address) { + $this->address = $address; + $address->setUser($this); + } + } +} diff --git a/tools/sandbox/cli-config.php b/tools/sandbox/cli-config.php index fc638f20b..ff19f1b03 100644 --- a/tools/sandbox/cli-config.php +++ b/tools/sandbox/cli-config.php @@ -1,14 +1,33 @@ option where you can specify the configuration +# file to use for a particular task. If this option is not given, the CLI looks for a file +# named "cli-config.php" (this one) in the same directory and uses that by default. +# + +require_once __DIR__ . '/../../lib/Doctrine/Common/IsolatedClassLoader.php'; + +$classLoader = new \Doctrine\Common\IsolatedClassLoader('Entities'); +$classLoader->setBasePath(__DIR__); +$classLoader->register(); $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 diff --git a/tools/sandbox/config.php b/tools/sandbox/config.php deleted file mode 100644 index 12532c86e..000000000 --- a/tools/sandbox/config.php +++ /dev/null @@ -1,28 +0,0 @@ -setBasePath('Doctrine', realpath(__DIR__ . '/../../lib')); -$classLoader->setBasePath('Entities', __DIR__); - -$config = new \Doctrine\ORM\Configuration; -$cache = new \Doctrine\Common\Cache\ApcCache; -// Use ArrayCache is APC is not available -// Warning without APC Doctrine will not perform as well -$cache = new \Doctrine\Common\Cache\ArrayCache; -$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\XmlDriver(__DIR__ . '/xml')); - -$eventManager = new \Doctrine\Common\EventManager(); -$connectionOptions = array( - 'driver' => 'pdo_sqlite', - 'path' => 'database.sqlite' -); -$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $eventManager); diff --git a/tools/sandbox/doctrine.php b/tools/sandbox/doctrine.php index d868ced52..534073f1c 100644 --- a/tools/sandbox/doctrine.php +++ b/tools/sandbox/doctrine.php @@ -1,9 +1,10 @@ setBasePath('Doctrine', __DIR__ . '/../../lib'); +$classLoader = new \Doctrine\Common\IsolatedClassLoader('Doctrine'); +$classLoader->setBasePath(__DIR__ . '/../../lib'); +$classLoader->register(); $cli = new \Doctrine\ORM\Tools\Cli(); $cli->run($_SERVER['argv']); \ No newline at end of file diff --git a/tools/sandbox/index.php b/tools/sandbox/index.php index 58d30bbdb..dd787fead 100644 --- a/tools/sandbox/index.php +++ b/tools/sandbox/index.php @@ -1,5 +1,35 @@ registerNamespace('Doctrine', realpath(__DIR__ . '/../../lib')); +$classLoader->registerNamespace('Entities', __DIR__); +$classLoader->register(); + +// Set up caches +$config = new \Doctrine\ORM\Configuration; +$cache = new \Doctrine\Common\Cache\ApcCache; +$config->setMetadataCacheImpl($cache); +$config->setQueryCacheImpl($cache); + +// Database connection information +$connectionOptions = array( + 'driver' => 'pdo_sqlite', + 'path' => 'database.sqlite' +); + +// Create EntityManager +$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config); + +## PUT YOUR TEST CODE BELOW + +$user = new User; +$address = new Address; + +echo "Hello World!"; \ No newline at end of file diff --git a/tools/sandbox/xml/Entities.Address.dcm.xml b/tools/sandbox/xml/Entities.Address.dcm.xml new file mode 100644 index 000000000..7e8dd0183 --- /dev/null +++ b/tools/sandbox/xml/Entities.Address.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/sandbox/xml/Entities.User.dcm.xml b/tools/sandbox/xml/Entities.User.dcm.xml new file mode 100644 index 000000000..e548fd1a7 --- /dev/null +++ b/tools/sandbox/xml/Entities.User.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/tools/sandbox/yaml/Entities.Address.dcm.yml b/tools/sandbox/yaml/Entities.Address.dcm.yml new file mode 100644 index 000000000..140e90224 --- /dev/null +++ b/tools/sandbox/yaml/Entities.Address.dcm.yml @@ -0,0 +1,16 @@ +Entities\Address: + type: entity + table: addresses + id: + id: + type: integer + generator: + strategy: AUTO + fields: + street: + type: string + length: 255 + oneToOne: + user: + targetEntity: User + mappedBy: address \ No newline at end of file diff --git a/tools/sandbox/yaml/Entities.User.dcm.yml b/tools/sandbox/yaml/Entities.User.dcm.yml new file mode 100644 index 000000000..a93d48f9f --- /dev/null +++ b/tools/sandbox/yaml/Entities.User.dcm.yml @@ -0,0 +1,18 @@ +Entities\User: + type: entity + table: users + id: + id: + type: integer + generator: + strategy: AUTO + fields: + name: + type: string + length: 50 + oneToOne: + address: + targetEntity: Address + joinColumn: + name: address_id + referencedColumnName: id