Skip to content

Commit

Permalink
Removing code duplication, reusing Doctrine\Common\Persistenc\Mapping…
Browse files Browse the repository at this point in the history
…\Driver\AnnotationDriver
  • Loading branch information
Ocramius committed Jul 4, 2012
1 parent ccace8c commit abd3ddc
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 196 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -8,4 +8,4 @@ lib/Doctrine/Common
lib/Doctrine/DBAL
/.settings/
.buildpath
.project
.project
223 changes: 28 additions & 195 deletions lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
Expand Up @@ -25,7 +25,8 @@
Doctrine\ORM\Mapping\MappingException,
Doctrine\ORM\Mapping\JoinColumn,
Doctrine\ORM\Mapping\Column,
Doctrine\Common\Persistence\Mapping\ClassMetadata;
Doctrine\Common\Persistence\Mapping\ClassMetadata,
Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;

/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
Expand All @@ -36,99 +37,15 @@
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class AnnotationDriver implements Driver
class AnnotationDriver extends AbstractAnnotationDriver implements Driver
{
/**
* The AnnotationReader.
*
* @var AnnotationReader
*/
protected $_reader;

/**
* The paths where to look for mapping files.
*
* @var array
*/
protected $_paths = array();

/**
* The file extension of mapping documents.
*
* @var string
*/
protected $_fileExtension = '.php';

/**
* @param array
*/
protected $_classNames;

/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
* @param AnnotationReader $reader The AnnotationReader to use, duck-typed.
* @param string|array $paths One or multiple paths where mapping classes can be found.
*/
public function __construct($reader, $paths = null)
{
$this->_reader = $reader;
if ($paths) {
$this->addPaths((array) $paths);
}
}

/**
* 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;
}

/**
* Retrieve the current annotation reader
*
* @return AnnotationReader
*/
public function getReader()
{
return $this->_reader;
}

/**
* 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
* {@inheritdoc}
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
protected $entityAnnotationClasses = array(
'Doctrine\ORM\Mapping\Entity' => 1,
'Doctrine\ORM\Mapping\MappedSuperclass' => 2,
);

/**
* {@inheritdoc}
Expand All @@ -142,7 +59,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
$class = new \ReflectionClass($metadata->name);
}

$classAnnotations = $this->_reader->getClassAnnotations($class);
$classAnnotations = $this->reader->getClassAnnotations($class);

if ($classAnnotations && is_numeric(key($classAnnotations))) {
foreach ($classAnnotations as $annot) {
Expand Down Expand Up @@ -364,53 +281,53 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
// Check for JoinColummn/JoinColumns annotations
$joinColumns = array();

if ($joinColumnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
$joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
} else if ($joinColumnsAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
} else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
foreach ($joinColumnsAnnot->value as $joinColumn) {
$joinColumns[] = $this->joinColumnToArray($joinColumn);
}
}

// Field can only be annotated with one of:
// @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
if ($columnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
if ($columnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
if ($columnAnnot->type == null) {
throw MappingException::propertyTypeIsRequired($className, $property->getName());
}

$mapping = $this->columnToArray($property->getName(), $columnAnnot);

if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}

if ($generatedValueAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
}

if ($this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
$metadata->setVersionMapping($mapping);
}

$metadata->mapField($mapping);

// Check for SequenceGenerator/TableGenerator definition
if ($seqGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
$metadata->setSequenceGeneratorDefinition(array(
'sequenceName' => $seqGeneratorAnnot->sequenceName,
'allocationSize' => $seqGeneratorAnnot->allocationSize,
'initialValue' => $seqGeneratorAnnot->initialValue
));
} else if ($this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
} else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
throw MappingException::tableIdGeneratorNotImplemented($className);
} else if ($customGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
} else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
$metadata->setCustomGeneratorDefinition(array(
'class' => $customGeneratorAnnot->class
));
}
} else if ($oneToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
} else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}

Expand All @@ -422,21 +339,21 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
} else if ($oneToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);

if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}

$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
} else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}

Expand All @@ -446,10 +363,10 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
} else if ($manyToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();

if ($joinTableAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema
Expand All @@ -473,7 +390,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
$mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);

if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}

Expand Down Expand Up @@ -537,7 +454,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
foreach ($class->getMethods() as $method) {
// filter for the declaring class only, callbacks from parents will already be registered.
if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) {
$annotations = $this->_reader->getMethodAnnotations($method);
$annotations = $this->reader->getMethodAnnotations($method);

if ($annotations && is_numeric(key($annotations))) {
foreach ($annotations as $annot) {
Expand Down Expand Up @@ -581,90 +498,6 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
}
}

/**
* Whether the class with the specified name is transient. Only non-transient
* classes, that is entities and mapped superclasses, should have their metadata loaded.
* A class is non-transient if it is annotated with either @Entity or
* @MappedSuperclass in the class doc block.
*
* @param string $className
* @return boolean
*/
public function isTransient($className)
{
$classAnnotations = $this->_reader->getClassAnnotations(new \ReflectionClass($className));

if ($classAnnotations && is_numeric(key($classAnnotations))) {
foreach ($classAnnotations as $annot) {
if ($annot instanceof \Doctrine\ORM\Mapping\Entity) {
return false;
}
if ($annot instanceof \Doctrine\ORM\Mapping\MappedSuperclass) {
return false;
}
}

return true;
}

return ! isset($classAnnotations['Doctrine\ORM\Mapping\Entity']) &&
! isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass']);
}

/**
* {@inheritDoc}
*/
public function getAllClassNames()
{
if ($this->_classNames !== null) {
return $this->_classNames;
}

if ( ! $this->_paths) {
throw MappingException::pathRequired();
}

$classes = array();
$includedFiles = array();

foreach ($this->_paths as $path) {
if ( ! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}

$iterator = new \RegexIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i',
\RecursiveRegexIterator::GET_MATCH
);

foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);

require_once $sourceFile;

$includedFiles[] = $sourceFile;
}
}

$declared = get_declared_classes();

foreach ($declared as $className) {
$rc = new \ReflectionClass($className);
$sourceFile = $rc->getFileName();
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
$classes[] = $className;
}
}

$this->_classNames = $classes;

return $classes;
}

/**
* Attempts to resolve the fetch mode.
*
Expand Down

0 comments on commit abd3ddc

Please sign in to comment.