Skip to content

Commit

Permalink
Reverse inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
franmomu committed Dec 22, 2023
1 parent 30870ed commit d083cc5
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 352 deletions.
346 changes: 1 addition & 345 deletions lib/Doctrine/ODM/MongoDB/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,12 @@

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\Reader;
use Doctrine\ODM\MongoDB\Events;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Mapping\Annotations\AbstractIndex;
use Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ODM\MongoDB\Mapping\MappingException;
use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use MongoDB\Driver\Exception\UnexpectedValueException;
use ReflectionClass;
use ReflectionMethod;

use function array_merge;
use function array_replace;
use function assert;
use function class_exists;
use function constant;
use function count;
use function interface_exists;
use function is_array;
use function MongoDB\BSON\fromJSON;
use function MongoDB\BSON\toPHP;
use function trigger_deprecation;

/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
*/
class AnnotationDriver implements MappingDriver
class AnnotationDriver extends AttributeDriver
{
use ColocatedMappingDriver;

/**
* The annotation reader.
*
Expand All @@ -60,323 +35,6 @@ public function __construct($reader, $paths = null)
$this->addPaths((array) $paths);
}

public function isTransient($className)
{
$classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className));

foreach ($classAnnotations as $annot) {
if ($annot instanceof ODM\AbstractDocument) {
return false;
}
}

return true;
}

public function loadMetadataForClass($className, \Doctrine\Persistence\Mapping\ClassMetadata $metadata): void
{
assert($metadata instanceof ClassMetadata);
$reflClass = $metadata->getReflectionClass();

$classAnnotations = $this->reader->getClassAnnotations($reflClass);

$documentAnnot = null;
foreach ($classAnnotations as $annot) {
$classAnnotations[$annot::class] = $annot;

if ($annot instanceof ODM\AbstractDocument) {
if ($documentAnnot !== null) {
throw MappingException::classCanOnlyBeMappedByOneAbstractDocument($className, $documentAnnot, $annot);
}

$documentAnnot = $annot;
}

// non-document class annotations
if ($annot instanceof ODM\AbstractIndex) {
$this->addIndex($metadata, $annot);
}

if ($annot instanceof ODM\Indexes) {
trigger_deprecation(
'doctrine/mongodb-odm',
'2.2',
'The "@Indexes" annotation used in class "%s" is deprecated. Specify all "@Index" and "@UniqueIndex" annotations on the class.',
$className,
);
$value = $annot->value;
foreach (is_array($value) ? $value : [$value] as $index) {
$this->addIndex($metadata, $index);
}
} elseif ($annot instanceof ODM\InheritanceType) {
$metadata->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $annot->value));
} elseif ($annot instanceof ODM\DiscriminatorField) {
$metadata->setDiscriminatorField($annot->value);
} elseif ($annot instanceof ODM\DiscriminatorMap) {
$value = $annot->value;
assert(is_array($value));
$metadata->setDiscriminatorMap($value);
} elseif ($annot instanceof ODM\DiscriminatorValue) {
$metadata->setDiscriminatorValue($annot->value);
} elseif ($annot instanceof ODM\ChangeTrackingPolicy) {
$metadata->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . $annot->value));
} elseif ($annot instanceof ODM\DefaultDiscriminatorValue) {
$metadata->setDefaultDiscriminatorValue($annot->value);
} elseif ($annot instanceof ODM\ReadPreference) {
$metadata->setReadPreference($annot->value, $annot->tags ?? []);
} elseif ($annot instanceof ODM\Validation) {
if (isset($annot->validator)) {
try {
$validatorBson = fromJSON($annot->validator);
} catch (UnexpectedValueException $e) {
throw MappingException::schemaValidationError($e->getCode(), $e->getMessage(), $className, 'validator');
}

$validator = toPHP($validatorBson, []);
$metadata->setValidator($validator);
}

if (isset($annot->action)) {
$metadata->setValidationAction($annot->action);
}

if (isset($annot->level)) {
$metadata->setValidationLevel($annot->level);
}
}
}

if ($documentAnnot === null) {
throw MappingException::classIsNotAValidDocument($className);
}

if ($documentAnnot instanceof ODM\MappedSuperclass) {
$metadata->isMappedSuperclass = true;
} elseif ($documentAnnot instanceof ODM\EmbeddedDocument) {
$metadata->isEmbeddedDocument = true;
} elseif ($documentAnnot instanceof ODM\QueryResultDocument) {
$metadata->isQueryResultDocument = true;
} elseif ($documentAnnot instanceof ODM\View) {
if (! $documentAnnot->rootClass) {
throw MappingException::viewWithoutRootClass($className);
}

if (! class_exists($documentAnnot->rootClass)) {
throw MappingException::viewRootClassNotFound($className, $documentAnnot->rootClass);
}

$metadata->markViewOf($documentAnnot->rootClass);
} elseif ($documentAnnot instanceof ODM\File) {
$metadata->isFile = true;

if ($documentAnnot->chunkSizeBytes !== null) {
$metadata->setChunkSizeBytes($documentAnnot->chunkSizeBytes);
}
}

if (isset($documentAnnot->db)) {
$metadata->setDatabase($documentAnnot->db);
}

if (isset($documentAnnot->collection)) {
$metadata->setCollection($documentAnnot->collection);
}

if (isset($documentAnnot->view)) {
$metadata->setCollection($documentAnnot->view);
}

// Store bucketName as collection name for GridFS files
if (isset($documentAnnot->bucketName)) {
$metadata->setBucketName($documentAnnot->bucketName);
}

if (isset($documentAnnot->repositoryClass)) {
$metadata->setCustomRepositoryClass($documentAnnot->repositoryClass);
}

if (isset($documentAnnot->writeConcern)) {
$metadata->setWriteConcern($documentAnnot->writeConcern);
}

if (isset($documentAnnot->indexes) && count($documentAnnot->indexes)) {
trigger_deprecation(
'doctrine/mongodb-odm',
'2.2',
'The "indexes" parameter in the "%s" annotation for class "%s" is deprecated. Specify all "@Index" and "@UniqueIndex" annotations on the class.',
$className,
$documentAnnot::class,
);

foreach ($documentAnnot->indexes as $index) {
$this->addIndex($metadata, $index);
}
}

if (! empty($documentAnnot->readOnly)) {
$metadata->markReadOnly();
}

foreach ($reflClass->getProperties() as $property) {
if (
($metadata->isMappedSuperclass && ! $property->isPrivate())
||
($metadata->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $metadata->name)
) {
continue;
}

$indexes = [];
$mapping = ['fieldName' => $property->getName()];
$fieldAnnot = null;

foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof ODM\AbstractField) {
$fieldAnnot = $annot;
}

if ($annot instanceof ODM\AbstractIndex) {
$indexes[] = $annot;
}

if ($annot instanceof ODM\Indexes) {
$value = $annot->value;
foreach (is_array($value) ? $value : [$value] as $index) {
$indexes[] = $index;
}
} elseif ($annot instanceof ODM\AlsoLoad) {
$mapping['alsoLoadFields'] = (array) $annot->value;
} elseif ($annot instanceof ODM\Version) {
$mapping['version'] = true;
} elseif ($annot instanceof ODM\Lock) {
$mapping['lock'] = true;
}
}

if ($fieldAnnot) {
$mapping = array_replace($mapping, (array) $fieldAnnot);
$metadata->mapField($mapping);
}

if (! $indexes) {
continue;
}

foreach ($indexes as $index) {
$name = $mapping['name'] ?? $mapping['fieldName'];
$keys = [$name => $index->order ?: 'asc'];
$this->addIndex($metadata, $index, $keys);
}
}

// Set shard key after all fields to ensure we mapped all its keys
if (isset($classAnnotations[ShardKey::class])) {
assert($classAnnotations[ShardKey::class] instanceof ShardKey);
$this->setShardKey($metadata, $classAnnotations[ShardKey::class]);
}

foreach ($reflClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
/* Filter for the declaring class only. Callbacks from parent
* classes will already be registered.
*/
if ($method->getDeclaringClass()->name !== $reflClass->name) {
continue;
}

foreach ($this->reader->getMethodAnnotations($method) as $annot) {
if ($annot instanceof ODM\AlsoLoad) {
$metadata->registerAlsoLoadMethod($method->getName(), $annot->value);
}

if (! isset($classAnnotations[ODM\HasLifecycleCallbacks::class])) {
continue;
}

if ($annot instanceof ODM\PrePersist) {
$metadata->addLifecycleCallback($method->getName(), Events::prePersist);
} elseif ($annot instanceof ODM\PostPersist) {
$metadata->addLifecycleCallback($method->getName(), Events::postPersist);
} elseif ($annot instanceof ODM\PreUpdate) {
$metadata->addLifecycleCallback($method->getName(), Events::preUpdate);
} elseif ($annot instanceof ODM\PostUpdate) {
$metadata->addLifecycleCallback($method->getName(), Events::postUpdate);
} elseif ($annot instanceof ODM\PreRemove) {
$metadata->addLifecycleCallback($method->getName(), Events::preRemove);
} elseif ($annot instanceof ODM\PostRemove) {
$metadata->addLifecycleCallback($method->getName(), Events::postRemove);
} elseif ($annot instanceof ODM\PreLoad) {
$metadata->addLifecycleCallback($method->getName(), Events::preLoad);
} elseif ($annot instanceof ODM\PostLoad) {
$metadata->addLifecycleCallback($method->getName(), Events::postLoad);
} elseif ($annot instanceof ODM\PreFlush) {
$metadata->addLifecycleCallback($method->getName(), Events::preFlush);
}
}
}
}

/**
* @param ClassMetadata<object> $class
* @param array<string, int|string> $keys
*/
private function addIndex(ClassMetadata $class, AbstractIndex $index, array $keys = []): void
{
$keys = array_merge($keys, $index->keys);
$options = [];
$allowed = ['name', 'background', 'unique', 'sparse', 'expireAfterSeconds'];
foreach ($allowed as $name) {
if (! isset($index->$name)) {
continue;
}

$options[$name] = $index->$name;
}

if (! empty($index->partialFilterExpression)) {
$options['partialFilterExpression'] = $index->partialFilterExpression;
}

$options = array_merge($options, $index->options);
$class->addIndex($keys, $options);
}

/**
* @param ClassMetadata<object> $class
*
* @throws MappingException
*/
private function setShardKey(ClassMetadata $class, ODM\ShardKey $shardKey): void
{
$options = [];
$allowed = ['unique', 'numInitialChunks'];
foreach ($allowed as $name) {
if (! isset($shardKey->$name)) {
continue;
}

$options[$name] = $shardKey->$name;
}

$class->setShardKey($shardKey->keys, $options);
}

/**
* Retrieve the current annotation reader
*
* @return Reader
*/
public function getReader()
{
trigger_deprecation(
'doctrine/mongodb-odm',
'2.4',
'%s is deprecated with no replacement',
__METHOD__,
);

return $this->reader;
}

/**
* Factory method for the Annotation Driver
*
Expand All @@ -387,5 +45,3 @@ public static function create($paths = [], ?Reader $reader = null): AnnotationDr
return new self($reader ?? new AnnotationReader(), $paths);
}
}

interface_exists(\Doctrine\Persistence\Mapping\ClassMetadata::class);
8 changes: 1 addition & 7 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.17.0@c620f6e80d0abfca532b00bda366062aaedf6e5d">
<files psalm-version="5.18.0@b113f3ed0259fd6e212d87c3df80eec95a6abf19">
<file src="lib/Doctrine/ODM/MongoDB/Aggregation/Aggregation.php">
<MissingTemplateParam>
<code>IteratorAggregate</code>
Expand Down Expand Up @@ -79,12 +79,6 @@
<code>$mapping</code>
</InvalidArgument>
</file>
<file src="lib/Doctrine/ODM/MongoDB/Mapping/Driver/AnnotationDriver.php">
<InvalidArgument>
<code>$mapping</code>
<code>$options</code>
</InvalidArgument>
</file>
<file src="lib/Doctrine/ODM/MongoDB/Mapping/Driver/AttributeDriver.php">
<InvalidArgument>
<code>$mapping</code>
Expand Down

0 comments on commit d083cc5

Please sign in to comment.