├── docker-compose.yaml ├── src ├── Aggregation │ ├── Stage │ │ ├── Search │ │ │ ├── SupportsRangeOperator.php │ │ │ ├── SupportsRegexOperator.php │ │ │ ├── SupportsTextOperator.php │ │ │ ├── SupportsPhraseOperator.php │ │ │ ├── SupportsCompoundOperator.php │ │ │ ├── SupportsWildcardOperator.php │ │ │ ├── SupportsExistsOperator.php │ │ │ ├── SupportsGeoWithinOperator.php │ │ │ ├── SupportsAutocompleteOperator.php │ │ │ ├── SupportsEmbeddedDocumentOperator.php │ │ │ ├── SupportsQueryStringOperator.php │ │ │ ├── SupportsMoreLikeThisOperator.php │ │ │ ├── ScoredSearchOperator.php │ │ │ ├── SupportsEqualsOperator.php │ │ │ ├── SearchOperator.php │ │ │ ├── SupportsNearOperator.php │ │ │ ├── SupportsEmbeddableSearchOperators.php │ │ │ ├── SupportsGeoShapeOperator.php │ │ │ ├── SupportsCompoundableSearchOperators.php │ │ │ ├── SupportsAllSearchOperators.php │ │ │ ├── Compound │ │ │ │ ├── CompoundedNear.php │ │ │ │ ├── CompoundedText.php │ │ │ │ ├── CompoundedEquals.php │ │ │ │ ├── CompoundedExists.php │ │ │ │ ├── CompoundedPhrase.php │ │ │ │ ├── CompoundedRange.php │ │ │ │ ├── CompoundedRegex.php │ │ │ │ ├── CompoundedGeoShape.php │ │ │ │ ├── CompoundedWildcard.php │ │ │ │ ├── CompoundedGeoWithin.php │ │ │ │ ├── CompoundedQueryString.php │ │ │ │ ├── CompoundedAutocomplete.php │ │ │ │ ├── CompoundedMoreLikeThis.php │ │ │ │ └── CompoundedEmbeddedDocument.php │ │ │ ├── Exists.php │ │ │ ├── MoreLikeThis.php │ │ │ ├── ScoredSearchOperatorTrait.php │ │ │ ├── Phrase.php │ │ │ ├── QueryString.php │ │ │ ├── Regex.php │ │ │ ├── Wildcard.php │ │ │ ├── Equals.php │ │ │ ├── CompoundedSearchOperatorTrait.php │ │ │ └── EmbeddedDocument.php │ │ ├── ReplaceWith.php │ │ ├── IndexStats.php │ │ ├── Redact.php │ │ ├── Set.php │ │ ├── AddFields.php │ │ ├── ReplaceRoot.php │ │ ├── Skip.php │ │ ├── Limit.php │ │ ├── Count.php │ │ ├── Sample.php │ │ ├── UnsetStage.php │ │ ├── Group.php │ │ ├── SortByCount.php │ │ ├── Project.php │ │ └── Bucket │ │ │ └── BucketAutoOutput.php │ └── Operator │ │ ├── TimestampOperators.php │ │ ├── DataSizeOperators.php │ │ └── BooleanOperators.php ├── Mapping │ ├── Annotations │ │ ├── Annotation.php │ │ ├── EncryptQuery.php │ │ ├── Lock.php │ │ ├── AbstractField.php │ │ ├── AbstractIndex.php │ │ ├── Version.php │ │ ├── AbstractDocument.php │ │ ├── View.php │ │ ├── ShardKey.php │ │ ├── Id.php │ │ ├── Field.php │ │ ├── ReadPreference.php │ │ ├── Validation.php │ │ ├── EmbedOne.php │ │ ├── EmbedMany.php │ │ ├── PreLoad.php │ │ ├── File.php │ │ ├── PostLoad.php │ │ ├── PreFlush.php │ │ ├── QueryResultDocument.php │ │ ├── File │ │ │ ├── Length.php │ │ │ ├── Filename.php │ │ │ ├── Metadata.php │ │ │ ├── ChunkSize.php │ │ │ └── UploadDate.php │ │ ├── PreRemove.php │ │ ├── PreUpdate.php │ │ ├── PostRemove.php │ │ ├── PostUpdate.php │ │ ├── PrePersist.php │ │ ├── Document.php │ │ ├── Index.php │ │ ├── PostPersist.php │ │ ├── TimeSeries.php │ │ ├── Indexes.php │ │ ├── ReferenceOne.php │ │ ├── AlsoLoad.php │ │ ├── HasLifecycleCallbacks.php │ │ ├── InheritanceType.php │ │ ├── ReferenceMany.php │ │ ├── DiscriminatorValue.php │ │ ├── DiscriminatorField.php │ │ ├── UniqueIndex.php │ │ ├── ChangeTrackingPolicy.php │ │ ├── DiscriminatorMap.php │ │ ├── EmbeddedDocument.php │ │ ├── MappedSuperclass.php │ │ ├── Encrypt.php │ │ ├── DefaultDiscriminatorValue.php │ │ ├── VectorSearchIndex.php │ │ └── SearchIndex.php │ ├── Attribute │ │ ├── MappingAttribute.php │ │ ├── QueryResultDocument.php │ │ ├── Lock.php │ │ ├── PostLoad.php │ │ ├── PreFlush.php │ │ ├── PreLoad.php │ │ ├── Version.php │ │ ├── PreRemove.php │ │ ├── PreUpdate.php │ │ ├── PostPersist.php │ │ ├── PostRemove.php │ │ ├── PostUpdate.php │ │ ├── PrePersist.php │ │ ├── Index.php │ │ ├── AbstractDocument.php │ │ ├── HasLifecycleCallbacks.php │ │ ├── DiscriminatorValue.php │ │ ├── InheritanceType.php │ │ ├── ChangeTrackingPolicy.php │ │ ├── DiscriminatorField.php │ │ ├── AlsoLoad.php │ │ ├── File │ │ │ ├── Length.php │ │ │ ├── ChunkSize.php │ │ │ ├── Filename.php │ │ │ ├── UploadDate.php │ │ │ └── Metadata.php │ │ ├── EmbeddedDocument.php │ │ ├── ReadPreference.php │ │ ├── DiscriminatorMap.php │ │ ├── DefaultDiscriminatorValue.php │ │ ├── MappedSuperclass.php │ │ ├── ShardKey.php │ │ ├── VectorSearchIndex.php │ │ ├── Id.php │ │ ├── TimeSeries.php │ │ ├── View.php │ │ ├── Field.php │ │ ├── UniqueIndex.php │ │ ├── Validation.php │ │ ├── AbstractField.php │ │ ├── SearchIndex.php │ │ ├── Document.php │ │ ├── File.php │ │ ├── EmbedOne.php │ │ └── Encrypt.php │ ├── TimeSeries │ │ └── Granularity.php │ ├── EncryptQuery.php │ ├── Driver │ │ ├── SimplifiedXmlDriver.php │ │ └── AnnotationDriver.php │ ├── PropertyAccessors │ │ ├── PropertyAccessor.php │ │ ├── PropertyAccessorFactory.php │ │ ├── ReflectionReadonlyProperty.php │ │ └── ReadonlyAccessor.php │ └── ClassMetadataFactoryInterface.php ├── Event │ ├── OnFlushEventArgs.php │ ├── PreFlushEventArgs.php │ ├── PostFlushEventArgs.php │ ├── ManagerEventArgs.php │ ├── LoadClassMetadataEventArgs.php │ ├── PreLoadEventArgs.php │ ├── PostCollectionLoadEventArgs.php │ ├── LifecycleEventArgs.php │ ├── OnClassMetadataNotFoundEventArgs.php │ └── DocumentNotFoundEventArgs.php ├── Types │ ├── IntIdType.php │ ├── VectorInt8Type.php │ ├── BinDataFuncType.php │ ├── VectorFloat32Type.php │ ├── VectorPackedBitType.php │ ├── BinDataCustomType.php │ ├── BinDataUUIDRFC4122Type.php │ ├── InvalidTypeException.php │ ├── BinDataByteArrayType.php │ ├── Incrementable.php │ ├── BinDataUUIDType.php │ ├── BinDataMD5Type.php │ ├── Versionable.php │ ├── ClosureToPHP.php │ ├── RawType.php │ ├── CustomIdType.php │ ├── Int64Type.php │ ├── BooleanType.php │ ├── KeyType.php │ ├── StringType.php │ ├── HashType.php │ ├── FloatType.php │ ├── CollectionType.php │ ├── TimestampType.php │ ├── IntType.php │ ├── ObjectIdType.php │ ├── DateImmutableType.php │ ├── IdType.php │ ├── Decimal128Type.php │ └── BinDataType.php ├── Id │ ├── AbstractIdGenerator.php │ ├── IdGenerator.php │ ├── ObjectIdGenerator.php │ ├── AutoGenerator.php │ └── SymfonyUuidGenerator.php ├── Repository │ ├── UploadOptions.php │ ├── ViewRepository.php │ ├── RepositoryFactory.php │ ├── DefaultRepositoryFactory.php │ └── GridFSRepository.php ├── Iterator │ ├── Iterator.php │ └── IterableResult.php ├── Proxy │ ├── InternalProxy.php │ ├── Resolver │ │ ├── ClassNameResolver.php │ │ ├── LazyGhostProxyClassNameResolver.php │ │ ├── CachingClassNameResolver.php │ │ └── ProxyManagerClassNameResolver.php │ ├── FileLocator.php │ └── Factory │ │ └── ProxyFactory.php ├── LockMode.php ├── PersistentCollection │ ├── DefaultPersistentCollectionFactory.php │ ├── PersistentCollectionGenerator.php │ ├── PersistentCollectionFactory.php │ └── AbstractPersistentCollectionFactory.php ├── APM │ └── CommandLoggerInterface.php ├── Hydrator │ ├── HydratorInterface.php │ └── HydratorException.php ├── Tools │ └── Console │ │ ├── Command │ │ ├── Schema │ │ │ └── AbstractCommandCompatibility.php │ │ └── CommandCompatibility.php │ │ └── Helper │ │ └── DocumentManagerHelper.php ├── DocumentNotFoundException.php ├── SchemaException.php ├── PersistentCollection.php ├── Query │ └── CriteriaMerger.php └── LockException.php ├── UPGRADE-2.7.md ├── UPGRADE-2.5.md ├── UPGRADE-2.1.md ├── UPGRADE-2.6.md ├── README.markdown ├── LICENSE ├── UPGRADE-2.3.md └── UPGRADE-2.2.md /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mongodb-atlas-local: 5 | image: mongodb/mongodb-atlas-local 6 | ports: 7 | - "27018:27017" 8 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/SupportsRangeOperator.php: -------------------------------------------------------------------------------- 1 | |object $documents */ 10 | public function moreLikeThis(...$documents): MoreLikeThis; 11 | } 12 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Lock.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | interface Iterator extends \Iterator 12 | { 13 | /** @return array */ 14 | public function toArray(): array; 15 | } 16 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/PreRemove.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | interface InternalProxy extends Proxy 16 | { 17 | public function __setInitialized(bool $initialized): void; 18 | } 19 | -------------------------------------------------------------------------------- /src/Types/BinDataUUIDRFC4122Type.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function getExpression(): array; 16 | 17 | /** @internal */ 18 | public function getOperatorName(): string; 19 | 20 | /** @internal */ 21 | public function getOperatorParams(): object; 22 | } 23 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/Lock.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/InheritanceType.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/SupportsNearOperator.php: -------------------------------------------------------------------------------- 1 | |Point|null $origin 14 | * @param int|float|null $pivot 15 | */ 16 | public function near($origin = null, $pivot = null, string ...$path): Near; 17 | } 18 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/AbstractField.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/DiscriminatorField.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Repository/ViewRepository.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | interface ViewRepository extends ObjectRepository 15 | { 16 | /** 17 | * Appends the aggregation pipeline to the given builder 18 | */ 19 | public function createViewAggregation(Builder $builder): void; 20 | } 21 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/Version.php: -------------------------------------------------------------------------------- 1 | |null $geometry */ 15 | public function geoShape($geometry = null, string $relation = '', string ...$path): GeoShape; 16 | } 17 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/AbstractDocument.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class ManagerEventArgs extends BaseManagerEventArgs 16 | { 17 | public function getDocumentManager(): DocumentManager 18 | { 19 | return $this->getObjectManager(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Types/ClosureToPHP.php: -------------------------------------------------------------------------------- 1 | convertToPHPValue($value);', Type::class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /UPGRADE-2.6.md: -------------------------------------------------------------------------------- 1 | # UPGRADE FROM to 2.6 2 | 3 | ## PHP requirements 4 | 5 | * MongoDB ODM 2.6 requires PHP 8.1 or newer. If you're not running PHP 8.1 yet, 6 | it's recommended that you upgrade to PHP 8.1 before upgrading ODM. 7 | 8 | ## `Match` classes were removed 9 | 10 | Minimal requirement of PHP 8.1 has rendered `Match` classes useless as one may 11 | not use them for backward compatibility purposes as `match` is a reserved keyword. 12 | 13 | Following classes were removed: 14 | - `\Doctrine\ODM\MongoDB\Aggregation\Stage\GraphLookup\Match` 15 | - `\Doctrine\ODM\MongoDB\Aggregation\Stage\Match` 16 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/SupportsCompoundableSearchOperators.php: -------------------------------------------------------------------------------- 1 | $this->getReplaceExpression()]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/SupportsAllSearchOperators.php: -------------------------------------------------------------------------------- 1 | indexes = $indexes; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/APM/CommandLoggerInterface.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | $this->tags = $tags; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/Id.php: -------------------------------------------------------------------------------- 1 | */ 18 | public $value; 19 | 20 | /** @param array $value */ 21 | public function __construct(array $value) 22 | { 23 | $this->value = $value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/Field.php: -------------------------------------------------------------------------------- 1 | value = $value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Proxy/FileLocator.php: -------------------------------------------------------------------------------- 1 | new stdClass(), 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/EmbedMany.php: -------------------------------------------------------------------------------- 1 | } 14 | */ 15 | class Redact extends Operator 16 | { 17 | public function getExpression(): array 18 | { 19 | return [ 20 | '$redact' => $this->expr->getExpression(), 21 | ]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/PreLoad.php: -------------------------------------------------------------------------------- 1 | } 14 | * @final 15 | */ 16 | class Set extends Operator 17 | { 18 | /** @phpstan-return SetStageExpression */ 19 | public function getExpression(): array 20 | { 21 | return ['$set' => $this->expr->getExpression()]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/PostRemove.php: -------------------------------------------------------------------------------- 1 | $documentName 19 | * 20 | * @return ObjectRepository 21 | * 22 | * @template T of object 23 | */ 24 | public function getRepository(DocumentManager $documentManager, string $documentName): ObjectRepository; 25 | } 26 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/File/UploadDate.php: -------------------------------------------------------------------------------- 1 | } 14 | * @final 15 | */ 16 | class AddFields extends Operator 17 | { 18 | /** @return AddFieldsStageExpression */ 19 | public function getExpression(): array 20 | { 21 | return ['$addFields' => $this->expr->getExpression()]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Compound/CompoundedNear.php: -------------------------------------------------------------------------------- 1 | $data 20 | * @phpstan-param Hints $hints 21 | * 22 | * @return array 23 | */ 24 | public function hydrate(object $document, array $data, array $hints = []): array; 25 | } 26 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Compound/CompoundedGeoShape.php: -------------------------------------------------------------------------------- 1 | , DocumentManager> 15 | */ 16 | final class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs 17 | { 18 | public function getDocumentManager(): DocumentManager 19 | { 20 | return $this->getObjectManager(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/ChangeTrackingPolicy.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'newRoot' => $this->getReplaceExpression(), 25 | ], 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Repository/DefaultRepositoryFactory.php: -------------------------------------------------------------------------------- 1 | getUnitOfWork(), $metadata); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Proxy/Factory/ProxyFactory.php: -------------------------------------------------------------------------------- 1 | [] $classes */ 12 | public function generateProxyClasses(array $classes): int; 13 | 14 | /** 15 | * Gets a reference proxy instance for the entity of the given type and identified by 16 | * the given identifier. 17 | * 18 | * @param mixed $identifier 19 | * @phpstan-param ClassMetadata $metadata 20 | * 21 | * @return T 22 | * 23 | * @template T of object 24 | */ 25 | public function getProxy(ClassMetadata $metadata, $identifier): object; 26 | } 27 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Skip.php: -------------------------------------------------------------------------------- 1 | $this->skip, 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/MappedSuperclass.php: -------------------------------------------------------------------------------- 1 | repositoryClass = $repositoryClass; 27 | $this->collection = $collection; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/ShardKey.php: -------------------------------------------------------------------------------- 1 | keys = $keys; 26 | $this->unique = $unique; 27 | $this->numInitialChunks = $numInitialChunks; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Limit.php: -------------------------------------------------------------------------------- 1 | $this->limit, 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Types/BooleanType.php: -------------------------------------------------------------------------------- 1 | $fields */ 21 | public function __construct( 22 | public array $fields, 23 | public ?string $name = null, 24 | ) { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Id.php: -------------------------------------------------------------------------------- 1 | $this->fieldName, 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Sample.php: -------------------------------------------------------------------------------- 1 | ['size' => $this->size], 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Tools/Console/Command/Schema/AbstractCommandCompatibility.php: -------------------------------------------------------------------------------- 1 | hasReturnType()) { 12 | /** @internal */ 13 | trait AbstractCommandCompatibility 14 | { 15 | protected function configure(): void 16 | { 17 | $this->configureCommonOptions(); 18 | } 19 | } 20 | } else { 21 | /** @internal */ 22 | trait AbstractCommandCompatibility 23 | { 24 | /** @return void */ 25 | protected function configure() 26 | { 27 | $this->configureCommonOptions(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/Encrypt.php: -------------------------------------------------------------------------------- 1 | $this->prepareFieldPath($this->path)]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Event/PreLoadEventArgs.php: -------------------------------------------------------------------------------- 1 | $data */ 16 | public function __construct( 17 | object $document, 18 | DocumentManager $dm, 19 | private array &$data, 20 | ?Session $session = null, 21 | ) { 22 | parent::__construct($document, $dm, $session); 23 | } 24 | 25 | /** 26 | * Get the array of data to be loaded and hydrated. 27 | * 28 | * @return array 29 | */ 30 | public function &getData(): array 31 | { 32 | return $this->data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Proxy/Resolver/LazyGhostProxyClassNameResolver.php: -------------------------------------------------------------------------------- 1 | resolveClassName($class); 19 | } 20 | 21 | public function resolveClassName(string $className): string 22 | { 23 | $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); 24 | 25 | if ($pos === false) { 26 | return $className; 27 | } 28 | 29 | return substr($className, $pos + Proxy::MARKER_LENGTH + 2); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/View.php: -------------------------------------------------------------------------------- 1 | db = $db; 32 | $this->view = $view; 33 | $this->rootClass = $rootClass; 34 | $this->repositoryClass = $repositoryClass; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Types/HashType.php: -------------------------------------------------------------------------------- 1 | |null */ 27 | public function convertToPHPValue($value) 28 | { 29 | return $value !== null ? (array) $value : null; 30 | } 31 | 32 | public function closureToPHP(): string 33 | { 34 | return '$return = (array) $value;'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Mapping/Annotations/VectorSearchIndex.php: -------------------------------------------------------------------------------- 1 | */ 13 | private array $resolvedNames = []; 14 | 15 | public function __construct(private ProxyClassNameResolver $resolver) 16 | { 17 | } 18 | 19 | /** 20 | * Gets the real class name of a class name that could be a proxy. 21 | */ 22 | public function getRealClass(string $class): string 23 | { 24 | return $this->resolveClassName($class); 25 | } 26 | 27 | public function resolveClassName(string $className): string 28 | { 29 | return $this->resolvedNames[$className] ??= $this->resolver->resolveClassName($className); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/PersistentCollection/PersistentCollectionFactory.php: -------------------------------------------------------------------------------- 1 | |null $coll 22 | * @phpstan-param FieldMapping $mapping 23 | * 24 | * @return PersistentCollectionInterface 25 | */ 26 | public function create(DocumentManager $dm, array $mapping, ?BaseCollection $coll = null): PersistentCollectionInterface; 27 | } 28 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Doctrine MongoDB Object Document Mapper 2 | 3 | [![Build Status](https://github.com/doctrine/mongodb-odm/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/mongodb-odm/actions?query=workflow%3A%22Continuous+Integration%22) 4 | [![Code Coverage](https://codecov.io/gh/doctrine/mongodb-odm/branch/2.2.x/graph/badge.svg)](https://codecov.io/gh/doctrine/mongodb-odm/branch/2.2.x) 5 | [![Gitter](https://badges.gitter.im/doctrine/mongodb-odm.svg)](https://gitter.im/doctrine/mongodb-odm) 6 | 7 | 8 | The Doctrine MongoDB ODM project is a library that provides a PHP object mapping functionality for MongoDB. 9 | 10 | ## More resources: 11 | 12 | * [Website](https://www.doctrine-project.org/projects/mongodb-odm.html) 13 | * [Documentation](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/stable/) 14 | * [Issue Tracker](https://github.com/doctrine/mongodb-odm/issues) 15 | * [Releases](https://github.com/doctrine/mongodb-odm/releases) 16 | -------------------------------------------------------------------------------- /src/SchemaException.php: -------------------------------------------------------------------------------- 1 | |null */ 18 | public function convertToDatabaseValue($value) 19 | { 20 | if ($value !== null && ! is_array($value)) { 21 | throw MongoDBException::invalidValueForType('Collection', ['array', 'null'], $value); 22 | } 23 | 24 | return $value !== null ? array_values($value) : null; 25 | } 26 | 27 | /** @return list|null */ 28 | public function convertToPHPValue($value) 29 | { 30 | return $value !== null ? array_values($value) : null; 31 | } 32 | 33 | public function closureToPHP(): string 34 | { 35 | return '$return = array_values($value);'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Iterator/IterableResult.php: -------------------------------------------------------------------------------- 1 | $collection */ 19 | public function __construct(private PersistentCollectionInterface $collection, DocumentManager $dm) 20 | { 21 | parent::__construct($dm); 22 | } 23 | 24 | /** 25 | * Gets collection that was just initialized (loaded). 26 | * 27 | * @return PersistentCollectionInterface 28 | */ 29 | public function getCollection(): PersistentCollectionInterface 30 | { 31 | return $this->collection; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/PersistentCollection.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | final class PersistentCollection implements PersistentCollectionInterface 19 | { 20 | /** @use PersistentCollectionTrait */ 21 | use PersistentCollectionTrait; 22 | 23 | /** @param BaseCollection $coll */ 24 | public function __construct(BaseCollection $coll, DocumentManager $dm, UnitOfWork $uow) 25 | { 26 | $this->coll = $coll; 27 | $this->dm = $dm; 28 | $this->uow = $uow; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Field.php: -------------------------------------------------------------------------------- 1 | |null */ 19 | public $enumType; 20 | 21 | /** 22 | * @param mixed[] $options 23 | * @param class-string|null $enumType 24 | */ 25 | public function __construct( 26 | ?string $name = null, 27 | ?string $type = null, 28 | bool $nullable = false, 29 | array $options = [], 30 | ?string $strategy = null, 31 | bool $notSaved = false, 32 | ?string $enumType = null, 33 | ) { 34 | parent::__construct($name, $type, $nullable, $options, $strategy, $notSaved); 35 | 36 | $this->enumType = $enumType; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Mapping/PropertyAccessors/PropertyAccessor.php: -------------------------------------------------------------------------------- 1 | extractSeconds($value) : ($value !== null ? (string) $value : null); 33 | } 34 | 35 | private function extractSeconds(Timestamp $timestamp): int 36 | { 37 | $parts = explode(':', substr((string) $timestamp, 1, -1)); 38 | 39 | return (int) $parts[1]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/UniqueIndex.php: -------------------------------------------------------------------------------- 1 | } 18 | */ 19 | class UnsetStage extends Stage 20 | { 21 | /** @var list */ 22 | private array $fields; 23 | 24 | public function __construct(Builder $builder, private DocumentPersister $documentPersister, string ...$fields) 25 | { 26 | parent::__construct($builder); 27 | 28 | $this->fields = array_values($fields); 29 | } 30 | 31 | /** @return UnsetStageExpression */ 32 | public function getExpression(): array 33 | { 34 | return [ 35 | '$unset' => array_map([$this->documentPersister, 'prepareFieldName'], $this->fields), 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Types/ObjectIdType.php: -------------------------------------------------------------------------------- 1 | |object> */ 20 | private array $like = []; 21 | 22 | /** @param array|object $documents */ 23 | public function __construct(Search $search, DocumentPersister $persister, ...$documents) 24 | { 25 | parent::__construct($search, $persister); 26 | 27 | $this->like = array_values($documents); 28 | } 29 | 30 | public function getOperatorName(): string 31 | { 32 | return 'moreLikeThis'; 33 | } 34 | 35 | public function getOperatorParams(): object 36 | { 37 | return (object) [ 38 | 'like' => $this->prepareDocuments($this->like), 39 | ]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Aggregation/Operator/DataSizeOperators.php: -------------------------------------------------------------------------------- 1 | = 80400 20 | ? RawValuePropertyAccessor::fromReflectionProperty($reflectionProperty) 21 | : ObjectCastPropertyAccessor::fromReflectionProperty($reflectionProperty); 22 | 23 | if ($reflectionProperty->hasType() && ! $reflectionProperty->getType()->allowsNull()) { 24 | $accessor = new TypedNoDefaultPropertyAccessor($accessor, $reflectionProperty); 25 | } 26 | 27 | if ($reflectionProperty->isReadOnly()) { 28 | $accessor = new ReadonlyAccessor($accessor, $reflectionProperty); 29 | } 30 | 31 | return $accessor; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Id/SymfonyUuidGenerator.php: -------------------------------------------------------------------------------- 1 | UuidV1::class, 24 | 4 => UuidV4::class, 25 | 7 => UuidV7::class, 26 | ]; 27 | 28 | public function __construct(private readonly string $class) 29 | { 30 | if (! in_array($this->class, self::SUPPORTED_TYPES, true)) { 31 | throw new InvalidArgumentException(sprintf('Invalid UUID type "%s". Expected one of: %s.', $this->class, implode(', ', array_values(self::SUPPORTED_TYPES)))); 32 | } 33 | } 34 | 35 | public function generate(DocumentManager $dm, object $document): Uuid 36 | { 37 | return new $this->class(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Validation.php: -------------------------------------------------------------------------------- 1 | validator = $validator; 39 | $this->action = $action; 40 | $this->level = $level; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Types/DateImmutableType.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class LifecycleEventArgs extends BaseLifecycleEventArgs 19 | { 20 | public function __construct( 21 | object $object, 22 | ObjectManager $objectManager, 23 | public readonly ?Session $session = null, 24 | ) { 25 | parent::__construct($object, $objectManager); 26 | } 27 | 28 | public function getDocument(): object 29 | { 30 | return $this->getObject(); 31 | } 32 | 33 | public function getDocumentManager(): DocumentManager 34 | { 35 | return $this->getObjectManager(); 36 | } 37 | 38 | public function isInTransaction(): bool 39 | { 40 | return $this->session?->isInTransaction() ?? false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Types/IdType.php: -------------------------------------------------------------------------------- 1 | } 16 | */ 17 | class Group extends Operator implements GroupAccumulatorOperators 18 | { 19 | use ProvidesGroupAccumulatorOperators; 20 | 21 | /** @var Expr */ 22 | protected $expr; 23 | 24 | public function __construct(Builder $builder) 25 | { 26 | parent::__construct($builder); 27 | 28 | $this->expr = $builder->expr(); 29 | } 30 | 31 | /** @phpstan-return GroupStageExpression */ 32 | public function getExpression(): array 33 | { 34 | return [ 35 | '$group' => $this->expr->getExpression(), 36 | ]; 37 | } 38 | 39 | protected function getExpr(): Expr 40 | { 41 | return $this->expr; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Compound/CompoundedEmbeddedDocument.php: -------------------------------------------------------------------------------- 1 | name = $name; 40 | $this->type = $type; 41 | $this->nullable = $nullable; 42 | $this->options = $options; 43 | $this->strategy = $strategy; 44 | $this->notSaved = $notSaved; 45 | } 46 | } 47 | 48 | // @phpstan-ignore class.notFound 49 | class_alias(AbstractField::class, \Doctrine\ODM\MongoDB\Mapping\Annotations\AbstractField::class); 50 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/SearchIndex.php: -------------------------------------------------------------------------------- 1 | |null $fields 23 | * @param list|null $analyzers 24 | * @param SearchIndexStoredSource|null $storedSource 25 | * @param list|null $synonyms 26 | */ 27 | public function __construct( 28 | public ?string $name = null, 29 | public ?bool $dynamic = null, 30 | public ?array $fields = null, 31 | public ?string $analyzer = null, 32 | public ?string $searchAnalyzer = null, 33 | public ?array $analyzers = null, 34 | public $storedSource = null, 35 | public ?array $synonyms = null, 36 | ) { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/ScoredSearchOperatorTrait.php: -------------------------------------------------------------------------------- 1 | score) { 15 | return $params; 16 | } 17 | 18 | $params->score = $this->score; 19 | 20 | return $params; 21 | } 22 | 23 | public function boostScore(?float $value = null, ?string $path = null, ?float $undefined = null): static 24 | { 25 | $boost = (object) []; 26 | if ($value !== null) { 27 | $boost->value = $value; 28 | } 29 | 30 | if ($path !== null) { 31 | $boost->path = $path; 32 | } 33 | 34 | if ($undefined !== null) { 35 | $boost->undefined = $undefined; 36 | } 37 | 38 | $this->score = (object) ['boost' => $boost]; 39 | 40 | return $this; 41 | } 42 | 43 | public function constantScore(float $value): static 44 | { 45 | $this->score = (object) [ 46 | 'constant' => (object) ['value' => $value], 47 | ]; 48 | 49 | return $this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Query/CriteriaMerger.php: -------------------------------------------------------------------------------- 1 | ...$criterias Any number of query criteria arrays 24 | * 25 | * @return array 26 | */ 27 | public function merge(...$criterias): array 28 | { 29 | $nonEmptyCriterias = array_values(array_filter($criterias, static fn (array $criteria) => ! empty($criteria))); 30 | 31 | switch (count($nonEmptyCriterias)) { 32 | case 0: 33 | return []; 34 | 35 | case 1: 36 | return $nonEmptyCriterias[0]; 37 | 38 | default: 39 | return ['$and' => $nonEmptyCriterias]; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Proxy/Resolver/ProxyManagerClassNameResolver.php: -------------------------------------------------------------------------------- 1 | resolveClassName($class); 22 | } 23 | 24 | /** 25 | * @param class-string|class-string> $className 26 | * 27 | * @return class-string 28 | * 29 | * @phpstan-template RealClassName of object 30 | */ 31 | public function resolveClassName(string $className): string 32 | { 33 | return $this->getClassNameInflector()->getUserClassName($className); 34 | } 35 | 36 | private function getClassNameInflector(): ClassNameInflectorInterface 37 | { 38 | return $this->configuration->getProxyManagerConfiguration()->getClassNameInflector(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/SortByCount.php: -------------------------------------------------------------------------------- 1 | getUnitOfWork()->getDocumentPersister($class->name); 29 | $this->fieldName = '$' . $documentPersister->prepareFieldName(substr($fieldName, 1)); 30 | } 31 | 32 | /** @phpstan-return SortByCountStageExpression */ 33 | public function getExpression(): array 34 | { 35 | return [ 36 | '$sortByCount' => $this->fieldName, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Tools/Console/Helper/DocumentManagerHelper.php: -------------------------------------------------------------------------------- 1 | hasReturnType()) { 13 | /** @internal */ 14 | trait DocumentManagerHelperCompatibility 15 | { 16 | public function getName(): string 17 | { 18 | return 'documentManager'; 19 | } 20 | } 21 | } else { 22 | /** @internal */ 23 | trait DocumentManagerHelperCompatibility 24 | { 25 | /** @return string */ 26 | public function getName() 27 | { 28 | return 'documentManager'; 29 | } 30 | } 31 | } 32 | 33 | /** 34 | * Symfony console component helper for accessing a DocumentManager instance. 35 | */ 36 | class DocumentManagerHelper extends Helper 37 | { 38 | use DocumentManagerHelperCompatibility; 39 | 40 | /** @var DocumentManager */ 41 | protected $dm; 42 | 43 | public function __construct(DocumentManager $dm) 44 | { 45 | $this->dm = $dm; 46 | } 47 | 48 | public function getDocumentManager(): DocumentManager 49 | { 50 | return $this->dm; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Event/OnClassMetadataNotFoundEventArgs.php: -------------------------------------------------------------------------------- 1 | foundMetadata = $classMetadata; 29 | } 30 | 31 | public function getFoundMetadata(): ?ClassMetadata 32 | { 33 | return $this->foundMetadata; 34 | } 35 | 36 | /** 37 | * Retrieve class name for which a failed metadata fetch attempt was executed 38 | * 39 | * @return class-string 40 | */ 41 | public function getClassName(): string 42 | { 43 | return $this->className; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Event/DocumentNotFoundEventArgs.php: -------------------------------------------------------------------------------- 1 | identifier; 29 | } 30 | 31 | /** 32 | * Indicates whether the proxy initialization exception is disabled. 33 | */ 34 | public function isExceptionDisabled(): bool 35 | { 36 | return $this->disableException; 37 | } 38 | 39 | /** 40 | * Disable the throwing of an exception 41 | * 42 | * This method indicates to the proxy initializer that the missing document 43 | * has been handled and no exception should be thrown. This can't be reset. 44 | */ 45 | public function disableException(bool $disableException = true): void 46 | { 47 | $this->disableException = $disableException; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Mapping/ClassMetadataFactoryInterface.php: -------------------------------------------------------------------------------- 1 | 15 | * @method list getAllMetadata() 16 | * @method ClassMetadata[] getLoadedMetadata() 17 | * @method ClassMetadata getMetadataFor($className) 18 | */ 19 | interface ClassMetadataFactoryInterface extends ClassMetadataFactory 20 | { 21 | /** 22 | * Sets the cache for created metadata. 23 | */ 24 | public function setCache(CacheItemPoolInterface $cache): void; 25 | 26 | /** 27 | * Sets the configuration for the factory. 28 | */ 29 | public function setConfiguration(Configuration $config): void; 30 | 31 | /** 32 | * Sets the document manager owning the factory. 33 | */ 34 | public function setDocumentManager(DocumentManager $dm): void; 35 | 36 | /** 37 | * Sets a resolver for real class names of a proxy. 38 | * 39 | * @deprecated This method is deprecated and will be removed in Doctrine ODM 3.0. 40 | */ 41 | public function setProxyClassNameResolver(ProxyClassNameResolver $resolver): void; 42 | } 43 | -------------------------------------------------------------------------------- /UPGRADE-2.3.md: -------------------------------------------------------------------------------- 1 | # UPGRADE FROM 2.2 to 2.3 2 | 3 | ## Proxy Class Name Resolution 4 | 5 | The `Doctrine\ODM\MongoDB\Proxy\Resolver\ClassNameResolver` interface has been 6 | deprecated in favor of the `Doctrine\Persistence\Mapping\ProxyClassNameResolver` 7 | interface. 8 | 9 | The `getClassNameResolver` method in `DocumentManager` is deprecated and should 10 | not be used. To retrieve the mapped class name for any object or class string, 11 | fetch metadata for the class and read the class using `$metadata->getName()`. 12 | The metadata layer is aware of these proxy namespace changes and how to resolve 13 | them, so users should always go through the metadata layer to retrieve mapped 14 | class names. 15 | 16 | ## Annotation Mapping 17 | 18 | In order to make annotations usable as PHP 8 attributes, their classes no 19 | longer extend `Doctrine\Common\Annotations\Annotation` class and are now using 20 | `@NamedArgumentConstructor` which provides more type safety. 21 | This does not apply to `@Indexes` which is deprecated and can't be used as 22 | Attribute. Use `@Index` and `@UniqueIndex` instead. 23 | 24 | `@Inheritance` annotation has been removed as it was never used. 25 | 26 | ## Deprecated: Document Namespace Aliases 27 | 28 | Document namespace aliases are deprecated, use the magic ::class constant to abbreviate full class names 29 | in DocumentManager and DocumentRepository. 30 | 31 | ```diff 32 | - $documentManager->find('MyBundle:User', $id); 33 | + $documentManager->find(User::class, $id); 34 | ``` 35 | -------------------------------------------------------------------------------- /src/LockException.php: -------------------------------------------------------------------------------- 1 | document; 20 | } 21 | 22 | public static function lockFailed(?object $document): self 23 | { 24 | return new self('A lock failed on a document.', $document); 25 | } 26 | 27 | public static function lockFailedVersionMissmatch(object $document, int $expectedLockVersion, int $actualLockVersion): self 28 | { 29 | return new self('The optimistic lock failed, version ' . $expectedLockVersion . ' was expected, but is actually ' . $actualLockVersion, $document); 30 | } 31 | 32 | public static function notVersioned(string $documentName): self 33 | { 34 | return new self('Document ' . $documentName . ' is not versioned.'); 35 | } 36 | 37 | public static function invalidLockFieldType(string $type): self 38 | { 39 | return new self('Invalid lock field type ' . $type . '. Lock field must be int.'); 40 | } 41 | 42 | public static function invalidVersionFieldType(string $type): self 43 | { 44 | return new self('Type ' . $type . ' does not implement Versionable interface.'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Phrase.php: -------------------------------------------------------------------------------- 1 | */ 19 | private array $query = []; 20 | 21 | /** @var list */ 22 | private array $path = []; 23 | private ?int $slop = null; 24 | 25 | public function query(string ...$query): static 26 | { 27 | $this->query = array_values($query); 28 | 29 | return $this; 30 | } 31 | 32 | public function path(string ...$path): static 33 | { 34 | $this->path = $path; 35 | 36 | return $this; 37 | } 38 | 39 | public function slop(int $slop): static 40 | { 41 | $this->slop = $slop; 42 | 43 | return $this; 44 | } 45 | 46 | public function getOperatorName(): string 47 | { 48 | return 'phrase'; 49 | } 50 | 51 | public function getOperatorParams(): object 52 | { 53 | $params = (object) [ 54 | 'query' => $this->query, 55 | 'path' => $this->prepareFieldPath($this->path), 56 | ]; 57 | 58 | if ($this->slop !== null) { 59 | $params->slop = $this->slop; 60 | } 61 | 62 | return $this->appendScore($params); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Document.php: -------------------------------------------------------------------------------- 1 | db = $db; 47 | $this->repositoryClass = $repositoryClass; 48 | $this->indexes = $indexes; 49 | $this->readOnly = $readOnly; 50 | $this->shardKey = $shardKey; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Aggregation/Operator/BooleanOperators.php: -------------------------------------------------------------------------------- 1 | |Expr $expression 25 | * @param array|Expr ...$expressions 26 | */ 27 | public function and($expression, ...$expressions): static; 28 | 29 | /** 30 | * Evaluates a boolean and returns the opposite boolean value. 31 | * 32 | * @see https://docs.mongodb.com/manual/reference/operator/aggregation/not/ 33 | * 34 | * @param mixed|Expr $expression 35 | */ 36 | public function not($expression): static; 37 | 38 | /** 39 | * Adds one or more $or clause to the current expression. 40 | * 41 | * @see https://docs.mongodb.com/manual/reference/operator/aggregation/or/ 42 | * 43 | * @param array|Expr $expression 44 | * @param array|Expr ...$expressions 45 | */ 46 | public function or($expression, ...$expressions): static; 47 | } 48 | -------------------------------------------------------------------------------- /src/Mapping/Driver/AnnotationDriver.php: -------------------------------------------------------------------------------- 1 | reader = $reader; 38 | } 39 | 40 | /** 41 | * Factory method for the Annotation Driver 42 | * 43 | * @param string|string[]|ClassLocator $paths 44 | */ 45 | public static function create($paths = [], ?Reader $reader = null): AnnotationDriver 46 | { 47 | return new self($reader ?? new AnnotationReader(), $paths); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /UPGRADE-2.2.md: -------------------------------------------------------------------------------- 1 | # UPGRADE FROM 2.1 to 2.2 2 | 3 | ## Aggregation 4 | 5 | The new `Doctrine\ODM\MongoDB\Aggregation\Builder::getAggregation()` method 6 | returns an `Doctrine\ODM\MongoDB\Aggregation\Aggregation` instance, comparable 7 | to the `Query` class. 8 | 9 | The `Doctrine\ODM\MongoDB\Aggregation\Builder::execute()` method was deprecated 10 | and will be removed in ODM 3.0. 11 | 12 | The `Doctrine\ODM\MongoDB\Aggregation\Stage\Match` and 13 | `Doctrine\ODM\MongoDB\Aggregation\Stage\GraphLookup\Match` classes were 14 | deprecated and replaced by `Doctrine\ODM\MongoDB\Aggregation\Stage\MatchStage` 15 | and `Doctrine\ODM\MongoDB\Aggregation\Stage\GraphLookup\MatchStage` 16 | respectively. This change was necessary due to `match` being a reserved keyword 17 | in PHP 8. You must replace any usage of this class before you migrate to PHP 8. 18 | 19 | ## Document indexes (annotations) 20 | 21 | Using `@Index` annotation(s) on a class level is a preferred way for defining 22 | indexes for documents. Using `@Index` in the `@Indexes` annotation or an `indexes` 23 | property of other annotations was deprecated and will be removed in ODM 3.0. 24 | 25 | ## DocumentManager configuration 26 | 27 | Using doctrine/cache to cache metadata is deprecated in favor of using PSR-6. 28 | The `getMetadataCacheImpl` and `setMetadataCacheImpl` methods in 29 | `Doctrine\ODM\MongoDB\Configuration` have been deprecated. Please use 30 | `getMetadataCache`and `setMetadataCache` with a PSR-6 implementation instead. 31 | Note that even after switching to PSR-6, `getMetadataCacheImpl` will return a 32 | cache instance that wraps the PSR-6 cache. 33 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Project.php: -------------------------------------------------------------------------------- 1 | } 14 | */ 15 | class Project extends Operator 16 | { 17 | /** @phpstan-return ProjectStageExpression */ 18 | public function getExpression(): array 19 | { 20 | return [ 21 | '$project' => $this->expr->getExpression(), 22 | ]; 23 | } 24 | 25 | /** 26 | * Shorthand method to define which fields to be included. 27 | * 28 | * @param string[] $fields 29 | */ 30 | public function includeFields(array $fields): static 31 | { 32 | foreach ($fields as $fieldName) { 33 | $this->field($fieldName)->expression(true); 34 | } 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Shorthand method to define which fields to be excluded. 41 | * 42 | * If you specify the exclusion of a field other than _id, you cannot employ 43 | * any other $project specification forms. 44 | * 45 | * @param string[] $fields 46 | */ 47 | public function excludeFields(array $fields): static 48 | { 49 | foreach ($fields as $fieldName) { 50 | $this->field($fieldName)->expression(false); 51 | } 52 | 53 | return $this; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Types/BinDataType.php: -------------------------------------------------------------------------------- 1 | binDataType); 34 | } 35 | 36 | if ($value->getType() !== $this->binDataType) { 37 | return new Binary($value->getData(), $this->binDataType); 38 | } 39 | 40 | return $value; 41 | } 42 | 43 | /** @return mixed|string|null */ 44 | public function convertToPHPValue($value) 45 | { 46 | return $value !== null ? ($value instanceof Binary ? $value->getData() : $value) : null; 47 | } 48 | 49 | public function closureToMongo(): string 50 | { 51 | return sprintf('$return = $value !== null ? new \MongoDB\BSON\Binary($value, %d) : null;', $this->binDataType); 52 | } 53 | 54 | public function closureToPHP(): string 55 | { 56 | return '$return = $value !== null ? ($value instanceof \MongoDB\BSON\Binary ? $value->getData() : $value) : null;'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/QueryString.php: -------------------------------------------------------------------------------- 1 | query($query) 28 | ->defaultPath($defaultPath); 29 | } 30 | 31 | public function query(string $query): static 32 | { 33 | $this->query = $query; 34 | 35 | return $this; 36 | } 37 | 38 | public function defaultPath(string $defaultPath): static 39 | { 40 | $this->defaultPath = $defaultPath; 41 | 42 | return $this; 43 | } 44 | 45 | public function getOperatorName(): string 46 | { 47 | return 'queryString'; 48 | } 49 | 50 | public function getOperatorParams(): object 51 | { 52 | $params = (object) [ 53 | 'query' => $this->query, 54 | 'defaultPath' => $this->prepareFieldPath($this->defaultPath), 55 | ]; 56 | 57 | return $this->appendScore($params); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Regex.php: -------------------------------------------------------------------------------- 1 | */ 17 | private array $query = []; 18 | 19 | /** @var list */ 20 | private array $path = []; 21 | private ?bool $allowAnalyzedField = null; 22 | 23 | public function query(string ...$query): static 24 | { 25 | $this->query = $query; 26 | 27 | return $this; 28 | } 29 | 30 | public function path(string ...$path): static 31 | { 32 | $this->path = $path; 33 | 34 | return $this; 35 | } 36 | 37 | public function allowAnalyzedField(bool $allowAnalyzedField = true): static 38 | { 39 | $this->allowAnalyzedField = $allowAnalyzedField; 40 | 41 | return $this; 42 | } 43 | 44 | public function getOperatorName(): string 45 | { 46 | return 'regex'; 47 | } 48 | 49 | public function getOperatorParams(): object 50 | { 51 | $params = (object) [ 52 | 'query' => $this->query, 53 | 'path' => $this->prepareFieldPath($this->path), 54 | ]; 55 | 56 | if ($this->allowAnalyzedField !== null) { 57 | $params->allowAnalyzedField = $this->allowAnalyzedField; 58 | } 59 | 60 | return $this->appendScore($params); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Mapping/PropertyAccessors/ReflectionReadonlyProperty.php: -------------------------------------------------------------------------------- 1 | isReadOnly()) { 24 | throw new InvalidArgumentException('Given property is not readonly.'); 25 | } 26 | 27 | parent::__construct($wrappedProperty->class, $wrappedProperty->name); 28 | } 29 | 30 | public function getValue(object|null $object = null): mixed 31 | { 32 | return $this->wrappedProperty->getValue(...func_get_args()); 33 | } 34 | 35 | public function setValue(mixed $objectOrValue, mixed $value = null): void 36 | { 37 | if (func_num_args() < 2 || $objectOrValue === null || ! $this->isInitialized($objectOrValue)) { 38 | $this->wrappedProperty->setValue(...func_get_args()); 39 | 40 | return; 41 | } 42 | 43 | assert(is_object($objectOrValue)); 44 | 45 | if (parent::getValue($objectOrValue) !== $value) { 46 | throw new LogicException(sprintf('Attempting to change readonly property %s::$%s.', $this->class, $this->name)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Wildcard.php: -------------------------------------------------------------------------------- 1 | */ 17 | private array $query = []; 18 | 19 | /** @var list */ 20 | private array $path = []; 21 | private ?bool $allowAnalyzedField = null; 22 | 23 | public function query(string ...$query): static 24 | { 25 | $this->query = $query; 26 | 27 | return $this; 28 | } 29 | 30 | public function path(string ...$path): static 31 | { 32 | $this->path = $path; 33 | 34 | return $this; 35 | } 36 | 37 | public function allowAnalyzedField(bool $allowAnalyzedField = true): static 38 | { 39 | $this->allowAnalyzedField = $allowAnalyzedField; 40 | 41 | return $this; 42 | } 43 | 44 | public function getOperatorName(): string 45 | { 46 | return 'wildcard'; 47 | } 48 | 49 | public function getOperatorParams(): object 50 | { 51 | $params = (object) [ 52 | 'query' => $this->query, 53 | 'path' => $this->prepareFieldPath($this->path), 54 | ]; 55 | 56 | if ($this->allowAnalyzedField !== null) { 57 | $params->allowAnalyzedField = $this->allowAnalyzedField; 58 | } 59 | 60 | return $this->appendScore($params); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/File.php: -------------------------------------------------------------------------------- 1 | db = $db; 53 | $this->bucketName = $bucketName; 54 | $this->repositoryClass = $repositoryClass; 55 | $this->indexes = $indexes; 56 | $this->readOnly = $readOnly; 57 | $this->shardKey = $shardKey; 58 | $this->chunkSizeBytes = $chunkSizeBytes; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/EmbedOne.php: -------------------------------------------------------------------------------- 1 | |null */ 28 | public $discriminatorMap; 29 | 30 | /** @var string|null */ 31 | public $defaultDiscriminatorValue; 32 | 33 | /** @param array|null $discriminatorMap */ 34 | public function __construct( 35 | ?string $name = null, 36 | bool $nullable = false, 37 | array $options = [], 38 | ?string $strategy = null, 39 | bool $notSaved = false, 40 | ?string $targetDocument = null, 41 | ?string $discriminatorField = null, 42 | ?array $discriminatorMap = null, 43 | ?string $defaultDiscriminatorValue = null, 44 | ) { 45 | parent::__construct($name, ClassMetadata::ONE, $nullable, $options, $strategy, $notSaved); 46 | 47 | $this->targetDocument = $targetDocument; 48 | $this->discriminatorField = $discriminatorField; 49 | $this->discriminatorMap = $discriminatorMap; 50 | $this->defaultDiscriminatorValue = $defaultDiscriminatorValue; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/File/Metadata.php: -------------------------------------------------------------------------------- 1 | |null */ 26 | public $discriminatorMap; 27 | 28 | /** @var string|null */ 29 | public $defaultDiscriminatorValue; 30 | 31 | /** @param array|null $discriminatorMap */ 32 | public function __construct( 33 | bool $nullable = false, 34 | array $options = [], 35 | ?string $strategy = null, 36 | bool $notSaved = false, 37 | ?string $targetDocument = null, 38 | ?string $discriminatorField = null, 39 | ?array $discriminatorMap = null, 40 | ?string $defaultDiscriminatorValue = null, 41 | ) { 42 | parent::__construct('metadata', ClassMetadata::ONE, $nullable, $options, $strategy, $notSaved); 43 | 44 | $this->targetDocument = $targetDocument; 45 | $this->discriminatorField = $discriminatorField; 46 | $this->discriminatorMap = $discriminatorMap; 47 | $this->defaultDiscriminatorValue = $defaultDiscriminatorValue; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/Equals.php: -------------------------------------------------------------------------------- 1 | path($path) 32 | ->value($value); 33 | } 34 | 35 | public function path(string $path): static 36 | { 37 | $this->path = $path; 38 | 39 | return $this; 40 | } 41 | 42 | /** @param string|int|float|ObjectId|UTCDateTime|null $value */ 43 | public function value($value): static 44 | { 45 | $this->value = $value; 46 | 47 | return $this; 48 | } 49 | 50 | public function getOperatorName(): string 51 | { 52 | return 'equals'; 53 | } 54 | 55 | public function getOperatorParams(): object 56 | { 57 | $params = (object) [ 58 | 'path' => $this->prepareFieldPath($this->path), 59 | 'value' => $this->value, 60 | ]; 61 | 62 | return $this->appendScore($params); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/PersistentCollection/AbstractPersistentCollectionFactory.php: -------------------------------------------------------------------------------- 1 | createCollectionClass($mapping['collectionClass']) 22 | : new ArrayCollection(); 23 | } 24 | 25 | if (empty($mapping['collectionClass'])) { 26 | return new PersistentCollection($coll, $dm, $dm->getUnitOfWork()); 27 | } 28 | 29 | $className = $dm->getConfiguration()->getPersistentCollectionGenerator() 30 | ->loadClass($mapping['collectionClass'], $dm->getConfiguration()->getAutoGeneratePersistentCollectionClasses()); 31 | 32 | return new $className($coll, $dm, $dm->getUnitOfWork()); 33 | } 34 | 35 | /** 36 | * Creates instance of collection class to be wrapped by PersistentCollection. 37 | * 38 | * @param string $collectionClass FQCN of class to instantiate 39 | * 40 | * @return BaseCollection 41 | */ 42 | abstract protected function createCollectionClass(string $collectionClass): BaseCollection; 43 | } 44 | -------------------------------------------------------------------------------- /src/Mapping/PropertyAccessors/ReadonlyAccessor.php: -------------------------------------------------------------------------------- 1 | reflectionProperty->isReadOnly()) { 19 | throw new InvalidArgumentException(sprintf( 20 | '%s::$%s must be readonly property', 21 | $this->reflectionProperty->getDeclaringClass()->getName(), 22 | $this->reflectionProperty->getName(), 23 | )); 24 | } 25 | } 26 | 27 | public function setValue(object $object, mixed $value): void 28 | { 29 | if (! $this->reflectionProperty->isInitialized($object)) { 30 | $this->parent->setValue($object, $value); 31 | 32 | return; 33 | } 34 | 35 | if ($this->parent->getValue($object) !== $value) { 36 | throw new LogicException(sprintf( 37 | 'Attempting to change readonly property %s::$%s.', 38 | $this->reflectionProperty->getDeclaringClass()->getName(), 39 | $this->reflectionProperty->getName(), 40 | )); 41 | } 42 | } 43 | 44 | public function getValue(object $object): mixed 45 | { 46 | return $this->parent->getValue($object); 47 | } 48 | 49 | public function getUnderlyingReflector(): ReflectionProperty 50 | { 51 | return $this->reflectionProperty; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/CompoundedSearchOperatorTrait.php: -------------------------------------------------------------------------------- 1 | compound->must(); 27 | } 28 | 29 | public function mustNot(): Compound 30 | { 31 | return $this->compound->mustNot(); 32 | } 33 | 34 | public function should(?int $minimumShouldMatch = null): Compound 35 | { 36 | return $this->compound->should($minimumShouldMatch); 37 | } 38 | 39 | public function filter(): Compound 40 | { 41 | return $this->compound->filter(); 42 | } 43 | 44 | /** 45 | * @param T $operator 46 | * 47 | * @return T 48 | * 49 | * @template T of SearchOperator 50 | */ 51 | protected function addOperator(SearchOperator $operator): SearchOperator 52 | { 53 | return $this->getAddOperatorClosure()($operator); 54 | } 55 | 56 | protected function getAddOperatorClosure(): Closure 57 | { 58 | return $this->addOperator; 59 | } 60 | 61 | protected function getCompoundStage(): Compound 62 | { 63 | return $this->compound; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Mapping/Attribute/Encrypt.php: -------------------------------------------------------------------------------- 1 | |null $sparsity 30 | * @param positive-int|null $precision 31 | * @param positive-int|null $trimFactor 32 | * @param positive-int|null $contention 33 | */ 34 | public function __construct( 35 | public ?EncryptQuery $queryType = null, 36 | int|float|Int64|Decimal128|UTCDateTime|DateTimeInterface|null $min = null, 37 | int|float|Int64|Decimal128|UTCDateTime|DateTimeInterface|null $max = null, 38 | public ?int $sparsity = null, 39 | public ?int $precision = null, 40 | public ?int $trimFactor = null, 41 | public ?int $contention = null, 42 | ) { 43 | $this->min = $min instanceof DateTimeInterface ? new UTCDateTime($min) : $min; 44 | $this->max = $max instanceof DateTimeInterface ? new UTCDateTime($max) : $max; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Search/EmbeddedDocument.php: -------------------------------------------------------------------------------- 1 | path($path); 28 | } 29 | 30 | public function path(string $path): static 31 | { 32 | $this->path = $path; 33 | 34 | return $this; 35 | } 36 | 37 | /** 38 | * @param T $operator 39 | * 40 | * @return T 41 | * 42 | * @template T of SearchOperator 43 | */ 44 | protected function addOperator(SearchOperator $operator): SearchOperator 45 | { 46 | return $this->operator = $operator; 47 | } 48 | 49 | public function getOperatorName(): string 50 | { 51 | return 'embeddedDocument'; 52 | } 53 | 54 | public function getOperatorParams(): object 55 | { 56 | $params = (object) ['path' => $this->prepareFieldPath($this->path)]; 57 | 58 | if ($this->operator) { 59 | $params->operator = (object) $this->operator->getExpression(); 60 | } 61 | 62 | return $this->appendScore($params); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Repository/GridFSRepository.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | interface GridFSRepository extends ObjectRepository 14 | { 15 | /** 16 | * Opens a readable stream for reading a GridFS file. 17 | * 18 | * @param mixed $id File ID 19 | * 20 | * @return resource 21 | */ 22 | public function openDownloadStream($id); 23 | 24 | /** 25 | * Writes the contents of a GridFS file to a writable stream. 26 | * 27 | * @param mixed $id File ID 28 | * @param resource $destination Writable Stream 29 | */ 30 | public function downloadToStream($id, $destination): void; 31 | 32 | /** 33 | * Opens a writable stream for writing a GridFS file. 34 | * 35 | * @return resource 36 | */ 37 | public function openUploadStream(string $filename, ?UploadOptions $uploadOptions = null); 38 | 39 | /** 40 | * Writes the contents of a readable stream to a GridFS file. 41 | * 42 | * @param resource $source Readable stream 43 | * 44 | * @return object The newly created GridFS file 45 | */ 46 | public function uploadFromStream(string $filename, $source, ?UploadOptions $uploadOptions = null); 47 | 48 | /** 49 | * Writes the contents of a file to a GridFS file. 50 | * 51 | * @param string|null $filename The filename to upload the file with. If no filename is provided, the name of the source file will be used. 52 | * 53 | * @return object The newly created GridFS file 54 | */ 55 | public function uploadFromFile(string $source, ?string $filename = null, ?UploadOptions $uploadOptions = null); 56 | } 57 | -------------------------------------------------------------------------------- /src/Hydrator/HydratorException.php: -------------------------------------------------------------------------------- 1 | hasReturnType()) { 14 | /** @internal */ 15 | trait CommandCompatibility 16 | { 17 | protected function configure(): void 18 | { 19 | $this->doConfigure(); 20 | } 21 | 22 | protected function execute(InputInterface $input, OutputInterface $output): int 23 | { 24 | return $this->doExecute($input, $output); 25 | } 26 | } 27 | // Symfony 7 28 | } elseif ((new ReflectionMethod(Command::class, 'execute'))->hasReturnType()) { 29 | /** @internal */ 30 | trait CommandCompatibility 31 | { 32 | /** @return void */ 33 | protected function configure() 34 | { 35 | $this->doConfigure(); 36 | } 37 | 38 | protected function execute(InputInterface $input, OutputInterface $output): int 39 | { 40 | return $this->doExecute($input, $output); 41 | } 42 | } 43 | } else { 44 | /** @internal */ 45 | trait CommandCompatibility 46 | { 47 | /** @return void */ 48 | protected function configure() 49 | { 50 | $this->doConfigure(); 51 | } 52 | 53 | /** 54 | * {@inheritDoc} 55 | * 56 | * @return int 57 | */ 58 | protected function execute(InputInterface $input, OutputInterface $output) 59 | { 60 | return $this->doExecute($input, $output); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Aggregation/Stage/Bucket/BucketAutoOutput.php: -------------------------------------------------------------------------------- 1 | |Expr|string $expression 28 | */ 29 | public function groupBy($expression): Stage\BucketAuto 30 | { 31 | assert($this->bucket instanceof Stage\BucketAuto); 32 | 33 | return $this->bucket->groupBy($expression); 34 | } 35 | 36 | /** 37 | * A positive 32-bit integer that specifies the number of buckets into which input documents are grouped. 38 | */ 39 | public function buckets(int $buckets): Stage\BucketAuto 40 | { 41 | assert($this->bucket instanceof Stage\BucketAuto); 42 | 43 | return $this->bucket->buckets($buckets); 44 | } 45 | 46 | /** 47 | * A string that specifies the preferred number series to use to ensure that 48 | * the calculated boundary edges end on preferred round numbers or their 49 | * powers of 10. 50 | */ 51 | public function granularity(string $granularity): Stage\BucketAuto 52 | { 53 | assert($this->bucket instanceof Stage\BucketAuto); 54 | 55 | return $this->bucket->granularity($granularity); 56 | } 57 | } 58 | --------------------------------------------------------------------------------