[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.
This commit is contained in:
parent
5198776429
commit
320d21e2be
@ -1,184 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
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 <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
136
lib/Doctrine/Common/GlobalClassLoader.php
Normal file
136
lib/Doctrine/Common/GlobalClassLoader.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common;
|
||||
|
||||
/**
|
||||
* A <tt>GlobalClassLoader</tt> 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 <tt>GlobalClassLoader</tt> 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 <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
117
lib/Doctrine/Common/IsolatedClassLoader.php
Normal file
117
lib/Doctrine/Common/IsolatedClassLoader.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common;
|
||||
|
||||
/**
|
||||
* An <tt>IsolatedClassLoader</tt> 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 <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
class IsolatedClassLoader
|
||||
{
|
||||
private $_fileExtension = '.php';
|
||||
private $_namespace;
|
||||
private $_basePath;
|
||||
private $_namespaceSeparator = '\\';
|
||||
|
||||
/**
|
||||
* Creates a new <tt>IsolatedClassLoader</tt> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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'
|
||||
);
|
||||
|
||||
|
40
tools/sandbox/Entities/Address.php
Normal file
40
tools/sandbox/Entities/Address.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Entities;
|
||||
|
||||
/** @Entity @Table(name="addresses") */
|
||||
class Address {
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
/** @Column(type="string", length=255) */
|
||||
private $street;
|
||||
/** @OneToOne(targetEntity="User", mappedBy="address") */
|
||||
private $user;
|
||||
|
||||
public function getId() {
|
||||
return $this->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
tools/sandbox/Entities/User.php
Normal file
42
tools/sandbox/Entities/User.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Entities;
|
||||
|
||||
/** @Entity @Table(name="users") */
|
||||
class User {
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
/** @Column(type="string", length=50) */
|
||||
private $name;
|
||||
/**
|
||||
* @OneToOne(targetEntity="Address")
|
||||
* @JoinColumn(name="address_id", referencedColumnName="id")
|
||||
*/
|
||||
private $address;
|
||||
|
||||
public function getId() {
|
||||
return $this->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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,33 @@
|
||||
<?php
|
||||
#
|
||||
# This configuration file is loaded by the Doctrine CLI whenever you execute
|
||||
# a task. A CLI configuration file usually initializes two local variables:
|
||||
#
|
||||
# $em - An EntityManager instance that the CLI tasks should use.
|
||||
# $args - An array of default command line arguments that take effect when an
|
||||
# argument is not specifically set on the command line.
|
||||
#
|
||||
# You can create several CLI configuration files with different names, for different databases.
|
||||
# Every CLI task recognizes the --config=<path> 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'
|
||||
);
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
require '../../lib/Doctrine/Common/ClassLoader.php';
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader();
|
||||
$classLoader->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);
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../../lib/Doctrine/Common/ClassLoader.php';
|
||||
require __DIR__ . '/../../lib/Doctrine/Common/IsolatedClassLoader.php';
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader();
|
||||
$classLoader->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']);
|
@ -1,5 +1,35 @@
|
||||
<?php
|
||||
|
||||
require 'config.php';
|
||||
namespace Sandbox;
|
||||
|
||||
// Place your code here. $em is at your service.
|
||||
use Entities\User, Entities\Address;
|
||||
|
||||
require '../../lib/Doctrine/Common/GlobalClassLoader.php';
|
||||
|
||||
// Set up class loading, we could alternatively use 2 IsolatedClassLoaders
|
||||
$classLoader = new \Doctrine\Common\GlobalClassLoader();
|
||||
$classLoader->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!";
|
15
tools/sandbox/xml/Entities.Address.dcm.xml
Normal file
15
tools/sandbox/xml/Entities.Address.dcm.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?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://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Entities\Address" table="addresses">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
<field name="street" type="string" length="255"/>
|
||||
<one-to-one field="user" target-entity="User" mapped-by="address"/>
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
17
tools/sandbox/xml/Entities.User.dcm.xml
Normal file
17
tools/sandbox/xml/Entities.User.dcm.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?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://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Entities\User" table="users">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
<field name="name" type="string" length="50"/>
|
||||
<one-to-one field="address" target-entity="Address">
|
||||
<join-column name="address_id" referenced-column-name="id"/>
|
||||
</one-to-one>
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
16
tools/sandbox/yaml/Entities.Address.dcm.yml
Normal file
16
tools/sandbox/yaml/Entities.Address.dcm.yml
Normal file
@ -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
|
18
tools/sandbox/yaml/Entities.User.dcm.yml
Normal file
18
tools/sandbox/yaml/Entities.User.dcm.yml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user