Commit 14ec40e1 authored by guilhermeblanco's avatar guilhermeblanco

[2.0][DDC-281] Fixed several issues with mapping drivers and loading of mapping files.

parent a652bc69
<?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\ORM\Mapping\Driver;
/**
* Base driver for metadata drivers.
*
* A file driver operates in a mode where it loads the mapping files of individual
* classes on demand. This requires the user to adhere to the convention of 1 mapping
* file per class and the file names of the mapping files must correspond to the full
* class name, including namespace, with the namespace delimiters '\', replaced by dots '.'.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractDriver
{
/**
* The paths where to look for mapping files.
*
* @var array
*/
protected $_paths = array();
/**
* The file extension of mapping documents.
*
* @var string
*/
protected $_fileExtension = 'php';
/**
* Append lookup paths to metadata driver.
*
* @param array $paths
*/
public function addPaths(array $paths)
{
$this->_paths = array_unique(array_merge($this->_paths, $paths));
}
/**
* Retrieve the defined metadata lookup paths.
*
* @return array
*/
public function getPaths()
{
return $this->_paths;
}
/**
* Get the file extension used to look for mapping files under
*
* @return void
*/
public function getFileExtension()
{
return $this->_fileExtension;
}
/**
* Set the file extension used to look for mapping files under
*
* @param string $fileExtension The file extension to set
* @return void
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
}
\ No newline at end of file
......@@ -34,58 +34,19 @@ use Doctrine\ORM\Mapping\MappingException;
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision: 1393 $
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractFileDriver implements Driver
abstract class AbstractFileDriver extends AbstractDriver implements Driver
{
/**
* The paths where to look for mapping files.
*
* @var array
*/
protected $_paths;
/**
* The file extension of mapping documents.
*
* @var string
*/
protected $_fileExtension;
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
$this->_paths = (array) $paths;
}
/**
* Get the file extension used to look for mapping files under
*
* @return void
*/
public function getFileExtension()
{
return $this->_fileExtension;
}
/**
* Set the file extension used to look for mapping files under
*
* @param string $fileExtension The file extension to set
* @return void
* @var string Middle part file extension.
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
protected $_middleFileExtension = 'dcm';
/**
* Get the element of schema meta data for the class from the mapping file.
* This will lazily load the mapping file if it is not loaded yet
......@@ -95,6 +56,7 @@ abstract class AbstractFileDriver implements Driver
public function getElement($className)
{
$result = $this->_loadMappingFile($this->_findMappingFile($className));
return $result[$className];
}
......@@ -108,16 +70,13 @@ abstract class AbstractFileDriver implements Driver
*/
public function isTransient($className)
{
$isTransient = true;
// check whether file exists
foreach ((array)$this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . str_replace('\\', '.', $className) . $this->_fileExtension)) {
$isTransient = false;
break;
}
try {
$fileName = $this->_findMappingFile($className);
return false;
} catch (\Exception $e) {
return true;
}
return $isTransient;
}
/**
......@@ -127,19 +86,33 @@ abstract class AbstractFileDriver implements Driver
*/
public function getAllClassNames()
{
$classNames = array();
foreach ((array)$this->_paths as $path) {
if (is_dir($path)) {
$files = glob($path . '/*');
foreach ($files as $file) {
$classNames[] = str_replace(array($this->_fileExtension, '.'), array('', '\\'), basename($file));
$classes = array();
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if ( ! is_dir($path)) {
throw MappingException::driverRequiresConfiguredDirectoryPath();
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$info = pathinfo($file->getPathName());
if ( ! isset($info['extension']) || $info['extension'] != $this->_fileExtension) {
continue;
}
// NOTE: All files found here means classes are not transient!
$classes[] = str_replace('.', '\\', $file->getBasename('.' . $this->_getFileSuffix()));
}
} else if (is_file($path)) {
$classNames[] = str_replace(array($this->_fileExtension, '.'), array('', '\\'), basename($file));
}
}
return $classNames;
return $classes;
}
/**
......@@ -152,19 +125,27 @@ abstract class AbstractFileDriver implements Driver
*/
protected function _findMappingFile($className)
{
$fileName = null;
foreach ((array)$this->_paths as $path) {
$fileName = $path . DIRECTORY_SEPARATOR . str_replace('\\', '.', $className) . $this->_fileExtension;
if (file_exists($fileName)) {
break;
$fileName = str_replace('\\', '.', $className) . '.' . $this->_getFileSuffix();
// Check whether file exists
foreach ((array) $this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) {
return $path . DIRECTORY_SEPARATOR . $fileName;
}
}
if ($fileName === null) {
throw MappingException::mappingFileNotFound($className);
}
return $fileName;
throw MappingException::mappingFileNotFound($className);
}
/**
* Retrieves the mapping file name suffix.
*
* @return string File name suffix.
*/
protected function _getFileSuffix()
{
return ($this->_middleFileExtension != '' ? $this->_middleFileExtension . '.' : '')
. $this->_fileExtension;
}
/**
......
......@@ -32,35 +32,33 @@ require __DIR__ . '/DoctrineAnnotations.php';
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class AnnotationDriver implements Driver
class AnnotationDriver extends AbstractDriver implements Driver
{
/** The AnnotationReader. */
/**
* The AnnotationReader.
*
* @var AnnotationReader
*/
private $_reader;
private $_classDirectory;
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
* @param AnnotationReader $reader The AnnotationReader to use.
* @param $reader The AnnotationReader to use.
*/
public function __construct(AnnotationReader $reader, $classDirectory = null)
public function __construct(AnnotationReader $reader)
{
$this->_reader = $reader;
$this->_classDirectory = $classDirectory;
}
public function setClassDirectory($classDirectory)
{
$this->_classDirectory = $classDirectory;
}
/**
......@@ -345,40 +343,42 @@ class AnnotationDriver implements Driver
*/
public function getAllClassNames()
{
if ($this->_classDirectory) {
$classes = array();
$classes = array();
if ($this->_paths) {
$declared = get_declared_classes();
foreach ((array) $this->_paths as $path) {
if ( ! is_dir($path)) {
throw MappingException::annotationDriverRequiresConfiguredDirectoryPath();
}
foreach ((array) $this->_classDirectory as $dir) {
$iter = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->_classDirectory),
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
$declared = get_declared_classes();
foreach ($iter as $item) {
$info = pathinfo($item->getPathName());
foreach ($iterator as $file) {
$info = pathinfo($file->getPathName());
if ( ! isset($info['extension']) || $info['extension'] != 'php') {
if ( ! isset($info['extension']) || $info['extension'] != $this->_fileExtension) {
continue;
}
require_once $item->getPathName();
require_once $file->getPathName();
}
$declared = array_diff(get_declared_classes(), $declared);
}
$declared = array_diff(get_declared_classes(), $declared);
foreach ($declared as $className) {
if ( ! $this->isTransient($className)) {
$classes[] = $className;
}
foreach ($declared as $className) {
if ( ! $this->isTransient($className)) {
$classes[] = $className;
}
}
return $classes;
} else {
return array();
}
}
return $classes;
}
}
\ No newline at end of file
......@@ -155,12 +155,7 @@ class DatabaseDriver implements Driver
}
/**
* Whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a
* MappedSuperclass.
*
* @param string $className
* @return boolean
* {@inheritdoc}
*/
public function isTransient($className)
{
......@@ -172,11 +167,12 @@ class DatabaseDriver implements Driver
*/
public function getAllClassNames()
{
$tables = array();
$classes = array();
foreach ($this->_sm->listTables() as $table) {
$tables[] = $table->getName();
$classes[] = $table->getName(); // TODO: Why is this not correct? Inflector::classify($table->getName());
}
return $tables;
return $classes;
}
}
\ No newline at end of file
......@@ -33,33 +33,33 @@ use Doctrine\Common\DoctrineException,
* The PhpDriver includes php files which just populate ClassMetadataInfo
* instances with plain php code
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class PhpDriver implements Driver
class PhpDriver extends AbstractDriver implements Driver
{
/** The directory path to look in for php files */
private $_directory;
/** The array of class names found and the path to the file */
private $_classPaths = array();
public function __construct($directory)
{
$this->_directory = $directory;
}
/**
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$path = $this->_classPaths[$className];
include $path;
}
/**
* {@inheritdoc}
*/
public function isTransient($className)
{
return true;
......@@ -70,23 +70,33 @@ class PhpDriver implements Driver
*/
public function getAllClassNames()
{
if ( ! is_dir($this->_directory)) {
throw MappingException::phpDriverRequiresConfiguredDirectoryPath();
}
$iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_directory),
\RecursiveIteratorIterator::LEAVES_ONLY);
$classes = array();
foreach ($iter as $item) {
$info = pathinfo($item->getPathName());
if ( ! isset($info['extension']) || $info['extension'] != 'php') {
continue;
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if ( ! is_dir($path)) {
throw MappingException::phpDriverRequiresConfiguredDirectoryPath();
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$info = pathinfo($file->getPathName());
if ( ! isset($info['extension']) || $info['extension'] != $this->_fileExtension) {
continue;
}
$className = $info['filename'];
$classes[] = $className;
$this->_classPaths[$className] = $file->getPathName();
}
}
$className = $info['filename'];
$classes[] = $className;
$this->_classPaths[$className] = $item->getPathName();
}
return $classes;
}
}
\ No newline at end of file
......@@ -27,23 +27,24 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo,
/**
* XmlDriver is a metadata driver that enables mapping through XML files.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class XmlDriver extends AbstractFileDriver
{
protected $_fileExtension = '.dcm.xml';
/**
* {@inheritdoc}
*/
protected $_fileExtension = 'xml';
/**
* Loads the metadata for the specified class into the provided container.
*
* @param string $className
* @param ClassMetadata $metadata
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
......@@ -370,11 +371,7 @@ class XmlDriver extends AbstractFileDriver
}
/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding SimpleXMLElement nodes.
*
* @param string $file The mapping file to load.
* @return array
* {@inheritdoc}
*/
protected function _loadMappingFile($file)
{
......
......@@ -35,18 +35,25 @@ if ( ! class_exists('sfYaml', false)) {
/**
* The YamlDriver reads the mapping metadata from yaml schema files.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class YamlDriver extends AbstractFileDriver
{
protected $_fileExtension = '.dcm.yml';
/**
* {@inheritdoc}
*/
protected $_fileExtension = 'yml';
/**
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$element = $this->getElement($className);
......@@ -412,11 +419,7 @@ class YamlDriver extends AbstractFileDriver
}
/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding elements.
*
* @param string $file The mapping file to load.
* @return array
* {@inheritdoc}
*/
protected function _loadMappingFile($file)
{
......
......@@ -59,6 +59,11 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("The association mapping '$fieldName' misses the 'sourceEntity' attribute.");
}
public static function mappingFileNotFound($fileName)
{
return new self("No mapping file found named '$fileName'.");
}
public static function mappingNotFound($fieldName)
{
return new self("No mapping found for field '$fieldName'.");
......
......@@ -59,7 +59,7 @@ class GenerateProxiesTask extends AbstractTask
if ($metadataDriver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
if (isset($arguments['class-dir'])) {
$metadataDriver->setClassDirectory($arguments['class-dir']);
$metadataDriver->addPaths((array) $arguments['class-dir']);
} else {
throw new CliException(
'The supplied configuration uses the annotation metadata driver. ' .
......
......@@ -145,7 +145,7 @@ class SchemaToolTask extends AbstractTask
if ($metadataDriver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
if (isset($arguments['class-dir'])) {
$metadataDriver->setClassDirectory($arguments['class-dir']);
$metadataDriver->addPaths($arguments['class-dir']);
} else {
throw new CliException(
'The supplied configuration uses the annotation metadata driver. ' .
......
......@@ -108,19 +108,27 @@ class ClassMetadataExporter
if ( ! isset($this->_mappingDrivers[$type])) {
return false;
}
$class = $this->_mappingDrivers[$type];
if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractFileDriver')) {
if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractDriver')) {
if (is_null($source)) {
throw DoctrineException::fileMappingDriversRequireDirectoryPath();
}
$driver = new $class($source);
} else if ($class == 'Doctrine\ORM\Mapping\Driver\AnnotationDriver') {
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache);
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, $source);
if ($class == 'Doctrine\ORM\Mapping\Driver\AnnotationDriver') {
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache);
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
} else {
$driver = new $class();
}
$driver->addPaths((array) $source);
} else {
$driver = new $class($source);
}
return $driver;
}
......@@ -149,13 +157,16 @@ class ClassMetadataExporter
list($source, $driver) = $d;
$allClasses = $driver->getAllClassNames();
foreach ($allClasses as $className) {
if (class_exists($className, false)) {
$metadata = new ClassMetadata($className);
} else {
$metadata = new ClassMetadataInfo($className);
}
$driver->loadMetadataForClass($className, $metadata);
if ( ! $metadata->isMappedSuperclass) {
$classes[$metadata->name] = $metadata;
}
......@@ -179,6 +190,7 @@ class ClassMetadataExporter
}
$class = $this->_exporterDrivers[$type];
return new $class($source);
}
}
\ No newline at end of file
......@@ -90,6 +90,7 @@ class DatabaseDriverTest extends \Doctrine\Tests\OrmFunctionalTestCase
$metadatas = $cm->getMetadatasForMappingSources();
$output = false;
foreach ($metadatas AS $metadata) {
if ($metadata->name == $className) {
return $metadata;
......
......@@ -66,7 +66,7 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache);
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$metadataDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
$metadataDriver->setClassDirectory(__DIR__."/../../Models/Global/");
$metadataDriver->addPaths(array(__DIR__ . '/../../Models/Global/'));
$entityManager = $this->_createEntityManager($metadataDriver);
......
......@@ -13,7 +13,8 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testXmlMapping()
{
$className = 'Doctrine\Tests\ORM\Mapping\User';
$xmlDriver = new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml');
$xmlDriver = new XmlDriver();
$xmlDriver->addPaths(array(__DIR__ . DIRECTORY_SEPARATOR . 'xml'));
$class = new ClassMetadata($className);
......@@ -27,7 +28,8 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testYamlMapping()
{
$className = 'Doctrine\Tests\ORM\Mapping\User';
$yamlDriver = new YamlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'yaml');
$yamlDriver = new YamlDriver();
$yamlDriver->addPaths(array(__DIR__ . DIRECTORY_SEPARATOR . 'yaml'));
$class = new ClassMetadata($className);
......@@ -41,7 +43,9 @@ class MappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testXmlGetAllClassNames()
{
$className = 'Doctrine\Tests\ORM\Mapping\User';
$xmlDriver = new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml');
$xmlDriver = new XmlDriver();
$xmlDriver->addPaths(array(__DIR__ . DIRECTORY_SEPARATOR . 'xml'));
$class = new ClassMetadata($className);
$classNames = $xmlDriver->getAllClassNames();
......
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