From 05e38eadbeb3de19e5b26003c2b401e00bb71df4 Mon Sep 17 00:00:00 2001 From: polo Date: Sun, 18 Oct 2026 00:08:23 +0200 Subject: =?UTF-8?q?sortie=20de=20vendor=20du=20d=C3=A9p=C3=B4t,=20oubli=20?= =?UTF-8?q?dans=20config-template.ini?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/doctrine/orm/src/AbstractQuery.php | 1116 ------- vendor/doctrine/orm/src/Cache.php | 106 - .../orm/src/Cache/AssociationCacheEntry.php | 30 - .../doctrine/orm/src/Cache/CacheConfiguration.php | 60 - vendor/doctrine/orm/src/Cache/CacheEntry.php | 16 - vendor/doctrine/orm/src/Cache/CacheException.php | 26 - vendor/doctrine/orm/src/Cache/CacheFactory.php | 64 - vendor/doctrine/orm/src/Cache/CacheKey.php | 16 - .../orm/src/Cache/CollectionCacheEntry.php | 25 - .../doctrine/orm/src/Cache/CollectionCacheKey.php | 39 - .../doctrine/orm/src/Cache/CollectionHydrator.php | 21 - vendor/doctrine/orm/src/Cache/ConcurrentRegion.php | 36 - vendor/doctrine/orm/src/Cache/DefaultCache.php | 245 -- .../doctrine/orm/src/Cache/DefaultCacheFactory.php | 189 -- .../orm/src/Cache/DefaultCollectionHydrator.php | 75 - .../orm/src/Cache/DefaultEntityHydrator.php | 176 -- .../doctrine/orm/src/Cache/DefaultQueryCache.php | 414 --- vendor/doctrine/orm/src/Cache/EntityCacheEntry.php | 50 - vendor/doctrine/orm/src/Cache/EntityCacheKey.php | 38 - vendor/doctrine/orm/src/Cache/EntityHydrator.php | 28 - .../orm/src/Cache/Exception/CacheException.php | 14 - .../Exception/CannotUpdateReadOnlyCollection.php | 19 - .../Cache/Exception/CannotUpdateReadOnlyEntity.php | 15 - .../src/Cache/Exception/FeatureNotImplemented.php | 23 - .../orm/src/Cache/Exception/NonCacheableEntity.php | 18 - .../Exception/NonCacheableEntityAssociation.php | 19 - vendor/doctrine/orm/src/Cache/Lock.php | 25 - vendor/doctrine/orm/src/Cache/LockException.php | 14 - .../doctrine/orm/src/Cache/Logging/CacheLogger.php | 60 - .../orm/src/Cache/Logging/CacheLoggerChain.php | 94 - .../src/Cache/Logging/StatisticsCacheLogger.php | 174 -- .../orm/src/Cache/Persister/CachedPersister.php | 25 - .../Collection/AbstractCollectionPersister.php | 168 - .../Collection/CachedCollectionPersister.php | 36 - ...NonStrictReadWriteCachedCollectionPersister.php | 74 - .../ReadOnlyCachedCollectionPersister.php | 24 - .../ReadWriteCachedCollectionPersister.php | 103 - .../Persister/Entity/AbstractEntityPersister.php | 557 ---- .../Persister/Entity/CachedEntityPersister.php | 20 - .../NonStrictReadWriteCachedEntityPersister.php | 85 - .../Entity/ReadOnlyCachedEntityPersister.php | 19 - .../Entity/ReadWriteCachedEntityPersister.php | 105 - vendor/doctrine/orm/src/Cache/QueryCache.php | 28 - vendor/doctrine/orm/src/Cache/QueryCacheEntry.php | 29 - vendor/doctrine/orm/src/Cache/QueryCacheKey.php | 23 - .../doctrine/orm/src/Cache/QueryCacheValidator.php | 16 - vendor/doctrine/orm/src/Cache/Region.php | 73 - .../orm/src/Cache/Region/DefaultRegion.php | 113 - .../orm/src/Cache/Region/FileLockRegion.php | 194 -- .../orm/src/Cache/Region/UpdateTimestampCache.php | 20 - .../orm/src/Cache/RegionsConfiguration.php | 63 - .../doctrine/orm/src/Cache/TimestampCacheEntry.php | 29 - .../doctrine/orm/src/Cache/TimestampCacheKey.php | 17 - .../orm/src/Cache/TimestampQueryCacheValidator.php | 38 - vendor/doctrine/orm/src/Cache/TimestampRegion.php | 18 - vendor/doctrine/orm/src/Configuration.php | 649 ---- .../orm/src/Decorator/EntityManagerDecorator.php | 174 -- vendor/doctrine/orm/src/EntityManager.php | 626 ---- vendor/doctrine/orm/src/EntityManagerInterface.php | 242 -- .../doctrine/orm/src/EntityNotFoundException.php | 46 - vendor/doctrine/orm/src/EntityRepository.php | 236 -- vendor/doctrine/orm/src/Event/ListenersInvoker.php | 98 - .../orm/src/Event/LoadClassMetadataEventArgs.php | 25 - .../src/Event/OnClassMetadataNotFoundEventArgs.php | 49 - vendor/doctrine/orm/src/Event/OnClearEventArgs.php | 19 - vendor/doctrine/orm/src/Event/OnFlushEventArgs.php | 19 - .../doctrine/orm/src/Event/PostFlushEventArgs.php | 19 - .../doctrine/orm/src/Event/PostLoadEventArgs.php | 13 - .../orm/src/Event/PostPersistEventArgs.php | 13 - .../doctrine/orm/src/Event/PostRemoveEventArgs.php | 13 - .../doctrine/orm/src/Event/PostUpdateEventArgs.php | 13 - .../doctrine/orm/src/Event/PreFlushEventArgs.php | 19 - .../doctrine/orm/src/Event/PrePersistEventArgs.php | 13 - .../doctrine/orm/src/Event/PreRemoveEventArgs.php | 13 - .../doctrine/orm/src/Event/PreUpdateEventArgs.php | 100 - vendor/doctrine/orm/src/Events.php | 125 - .../orm/src/Exception/ConfigurationException.php | 9 - .../Exception/EntityIdentityCollisionException.php | 39 - .../orm/src/Exception/EntityManagerClosed.php | 15 - .../orm/src/Exception/EntityMissingAssignedId.php | 20 - .../orm/src/Exception/InvalidEntityRepository.php | 18 - .../orm/src/Exception/InvalidHydrationMode.php | 17 - .../orm/src/Exception/ManagerException.php | 11 - .../orm/src/Exception/MissingIdentifierField.php | 21 - .../MissingMappingDriverImplementation.php | 18 - .../Exception/MultipleSelectorsFoundException.php | 26 - vendor/doctrine/orm/src/Exception/NotSupported.php | 44 - vendor/doctrine/orm/src/Exception/ORMException.php | 11 - .../orm/src/Exception/PersisterException.php | 11 - .../orm/src/Exception/RepositoryException.php | 13 - .../orm/src/Exception/SchemaToolException.php | 11 - .../src/Exception/UnexpectedAssociationValue.php | 27 - .../src/Exception/UnrecognizedIdentifierFields.php | 23 - vendor/doctrine/orm/src/Id/AbstractIdGenerator.php | 28 - vendor/doctrine/orm/src/Id/AssignedGenerator.php | 45 - .../orm/src/Id/BigIntegerIdentityGenerator.php | 25 - vendor/doctrine/orm/src/Id/IdentityGenerator.php | 25 - vendor/doctrine/orm/src/Id/SequenceGenerator.php | 112 - .../src/Internal/Hydration/AbstractHydrator.php | 556 ---- .../orm/src/Internal/Hydration/ArrayHydrator.php | 270 -- .../src/Internal/Hydration/HydrationException.php | 67 - .../orm/src/Internal/Hydration/ObjectHydrator.php | 586 ---- .../Internal/Hydration/ScalarColumnHydrator.php | 34 - .../orm/src/Internal/Hydration/ScalarHydrator.php | 35 - .../Internal/Hydration/SimpleObjectHydrator.php | 176 -- .../Internal/Hydration/SingleScalarHydrator.php | 40 - .../orm/src/Internal/HydrationCompleteHandler.php | 64 - .../orm/src/Internal/NoUnknownNamedArguments.php | 55 - vendor/doctrine/orm/src/Internal/QueryType.php | 13 - .../doctrine/orm/src/Internal/SQLResultCasing.php | 30 - .../src/Internal/StronglyConnectedComponents.php | 159 - .../doctrine/orm/src/Internal/TopologicalSort.php | 155 - .../TopologicalSort/CycleDetectedException.php | 47 - vendor/doctrine/orm/src/LazyCriteriaCollection.php | 96 - .../doctrine/orm/src/Mapping/AnsiQuoteStrategy.php | 76 - .../orm/src/Mapping/ArrayAccessImplementation.php | 70 - .../orm/src/Mapping/AssociationMapping.php | 359 --- .../orm/src/Mapping/AssociationOverride.php | 51 - .../orm/src/Mapping/AssociationOverrides.php | 38 - .../doctrine/orm/src/Mapping/AttributeOverride.php | 15 - .../orm/src/Mapping/AttributeOverrides.php | 38 - .../orm/src/Mapping/Builder/AssociationBuilder.php | 171 - .../src/Mapping/Builder/ClassMetadataBuilder.php | 426 --- .../orm/src/Mapping/Builder/EmbeddedBuilder.php | 46 - .../src/Mapping/Builder/EntityListenerBuilder.php | 55 - .../orm/src/Mapping/Builder/FieldBuilder.php | 243 -- .../Builder/ManyToManyAssociationBuilder.php | 73 - .../Builder/OneToManyAssociationBuilder.php | 46 - vendor/doctrine/orm/src/Mapping/Cache.php | 19 - .../orm/src/Mapping/ChainTypedFieldMapper.php | 35 - .../orm/src/Mapping/ChangeTrackingPolicy.php | 17 - vendor/doctrine/orm/src/Mapping/ClassMetadata.php | 2649 ---------------- .../orm/src/Mapping/ClassMetadataFactory.php | 729 ----- vendor/doctrine/orm/src/Mapping/Column.php | 36 - .../doctrine/orm/src/Mapping/CustomIdGenerator.php | 16 - .../src/Mapping/DefaultEntityListenerResolver.php | 40 - .../orm/src/Mapping/DefaultNamingStrategy.php | 68 - .../orm/src/Mapping/DefaultQuoteStrategy.php | 145 - .../orm/src/Mapping/DefaultTypedFieldMapper.php | 80 - .../orm/src/Mapping/DiscriminatorColumn.php | 24 - .../orm/src/Mapping/DiscriminatorColumnMapping.php | 83 - .../doctrine/orm/src/Mapping/DiscriminatorMap.php | 17 - .../orm/src/Mapping/Driver/AttributeDriver.php | 768 ----- .../orm/src/Mapping/Driver/AttributeReader.php | 146 - .../orm/src/Mapping/Driver/DatabaseDriver.php | 528 ---- .../src/Mapping/Driver/ReflectionBasedDriver.php | 44 - .../Driver/RepeatableAttributeCollection.php | 16 - .../orm/src/Mapping/Driver/SimplifiedXmlDriver.php | 25 - .../doctrine/orm/src/Mapping/Driver/XmlDriver.php | 940 ------ vendor/doctrine/orm/src/Mapping/Embeddable.php | 12 - vendor/doctrine/orm/src/Mapping/Embedded.php | 17 - .../orm/src/Mapping/EmbeddedClassMapping.php | 93 - vendor/doctrine/orm/src/Mapping/Entity.php | 20 - .../orm/src/Mapping/EntityListenerResolver.php | 30 - .../doctrine/orm/src/Mapping/EntityListeners.php | 21 - .../Mapping/Exception/InvalidCustomGenerator.php | 28 - .../src/Mapping/Exception/UnknownGeneratorType.php | 16 - vendor/doctrine/orm/src/Mapping/FieldMapping.php | 169 - vendor/doctrine/orm/src/Mapping/GeneratedValue.php | 17 - .../orm/src/Mapping/HasLifecycleCallbacks.php | 12 - vendor/doctrine/orm/src/Mapping/Id.php | 12 - vendor/doctrine/orm/src/Mapping/Index.php | 26 - .../doctrine/orm/src/Mapping/InheritanceType.php | 17 - .../doctrine/orm/src/Mapping/InverseJoinColumn.php | 13 - .../orm/src/Mapping/InverseSideMapping.php | 30 - vendor/doctrine/orm/src/Mapping/JoinColumn.php | 13 - .../doctrine/orm/src/Mapping/JoinColumnMapping.php | 77 - .../orm/src/Mapping/JoinColumnProperties.php | 21 - vendor/doctrine/orm/src/Mapping/JoinColumns.php | 14 - vendor/doctrine/orm/src/Mapping/JoinTable.php | 35 - .../doctrine/orm/src/Mapping/JoinTableMapping.php | 115 - vendor/doctrine/orm/src/Mapping/ManyToMany.php | 27 - .../src/Mapping/ManyToManyAssociationMapping.php | 9 - .../src/Mapping/ManyToManyInverseSideMapping.php | 9 - .../src/Mapping/ManyToManyOwningSideMapping.php | 185 -- vendor/doctrine/orm/src/Mapping/ManyToOne.php | 24 - .../src/Mapping/ManyToOneAssociationMapping.php | 12 - .../doctrine/orm/src/Mapping/MappedSuperclass.php | 18 - .../doctrine/orm/src/Mapping/MappingAttribute.php | 10 - .../doctrine/orm/src/Mapping/MappingException.php | 691 ----- vendor/doctrine/orm/src/Mapping/NamingStrategy.php | 71 - vendor/doctrine/orm/src/Mapping/OneToMany.php | 26 - .../src/Mapping/OneToManyAssociationMapping.php | 75 - vendor/doctrine/orm/src/Mapping/OneToOne.php | 26 - .../orm/src/Mapping/OneToOneAssociationMapping.php | 9 - .../orm/src/Mapping/OneToOneInverseSideMapping.php | 9 - .../orm/src/Mapping/OneToOneOwningSideMapping.php | 9 - vendor/doctrine/orm/src/Mapping/OrderBy.php | 17 - .../doctrine/orm/src/Mapping/OwningSideMapping.php | 28 - vendor/doctrine/orm/src/Mapping/PostLoad.php | 12 - vendor/doctrine/orm/src/Mapping/PostPersist.php | 12 - vendor/doctrine/orm/src/Mapping/PostRemove.php | 12 - vendor/doctrine/orm/src/Mapping/PostUpdate.php | 12 - vendor/doctrine/orm/src/Mapping/PreFlush.php | 12 - vendor/doctrine/orm/src/Mapping/PrePersist.php | 12 - vendor/doctrine/orm/src/Mapping/PreRemove.php | 12 - vendor/doctrine/orm/src/Mapping/PreUpdate.php | 12 - vendor/doctrine/orm/src/Mapping/QuoteStrategy.php | 68 - .../orm/src/Mapping/ReflectionEmbeddedProperty.php | 61 - .../orm/src/Mapping/ReflectionEnumProperty.php | 87 - .../orm/src/Mapping/ReflectionReadonlyProperty.php | 49 - .../doctrine/orm/src/Mapping/SequenceGenerator.php | 18 - vendor/doctrine/orm/src/Mapping/Table.php | 45 - .../orm/src/Mapping/ToManyAssociationMapping.php | 16 - .../ToManyAssociationMappingImplementation.php | 69 - .../orm/src/Mapping/ToManyInverseSideMapping.php | 10 - .../orm/src/Mapping/ToManyOwningSideMapping.php | 10 - .../orm/src/Mapping/ToOneAssociationMapping.php | 9 - .../orm/src/Mapping/ToOneInverseSideMapping.php | 52 - .../orm/src/Mapping/ToOneOwningSideMapping.php | 212 -- .../doctrine/orm/src/Mapping/TypedFieldMapper.php | 20 - .../orm/src/Mapping/UnderscoreNamingStrategy.php | 108 - .../doctrine/orm/src/Mapping/UniqueConstraint.php | 24 - vendor/doctrine/orm/src/Mapping/Version.php | 12 - vendor/doctrine/orm/src/NativeQuery.php | 68 - vendor/doctrine/orm/src/NoResultException.php | 16 - .../doctrine/orm/src/NonUniqueResultException.php | 18 - .../orm/src/ORMInvalidArgumentException.php | 195 -- vendor/doctrine/orm/src/ORMSetup.php | 127 - .../doctrine/orm/src/OptimisticLockException.php | 55 - vendor/doctrine/orm/src/PersistentCollection.php | 652 ---- .../Collection/AbstractCollectionPersister.php | 50 - .../Persisters/Collection/CollectionPersister.php | 59 - .../Persisters/Collection/ManyToManyPersister.php | 770 ----- .../Persisters/Collection/OneToManyPersister.php | 264 -- .../Entity/AbstractEntityInheritancePersister.php | 66 - .../src/Persisters/Entity/BasicEntityPersister.php | 2085 ------------- .../Persisters/Entity/CachedPersisterContext.php | 60 - .../orm/src/Persisters/Entity/EntityPersister.php | 298 -- .../Persisters/Entity/JoinedSubclassPersister.php | 601 ---- .../src/Persisters/Entity/SingleTablePersister.php | 166 - .../Exception/CantUseInOperatorOnCompositeKeys.php | 15 - .../Persisters/Exception/InvalidOrientation.php | 15 - .../src/Persisters/Exception/UnrecognizedField.php | 24 - .../MatchingAssociationFieldRequiresObject.php | 22 - .../orm/src/Persisters/PersisterException.php | 23 - .../orm/src/Persisters/SqlExpressionVisitor.php | 79 - .../orm/src/Persisters/SqlValueVisitor.php | 88 - .../doctrine/orm/src/PessimisticLockException.php | 16 - vendor/doctrine/orm/src/Proxy/Autoloader.php | 86 - .../src/Proxy/DefaultProxyClassNameResolver.php | 35 - vendor/doctrine/orm/src/Proxy/InternalProxy.php | 18 - vendor/doctrine/orm/src/Proxy/NotAProxyClass.php | 22 - vendor/doctrine/orm/src/Proxy/ProxyFactory.php | 439 --- vendor/doctrine/orm/src/Query.php | 682 ---- vendor/doctrine/orm/src/Query/AST/ASTException.php | 20 - .../orm/src/Query/AST/AggregateExpression.php | 23 - .../orm/src/Query/AST/ArithmeticExpression.php | 34 - .../orm/src/Query/AST/ArithmeticFactor.php | 36 - .../doctrine/orm/src/Query/AST/ArithmeticTerm.php | 25 - .../orm/src/Query/AST/BetweenExpression.php | 23 - .../orm/src/Query/AST/CoalesceExpression.php | 25 - .../src/Query/AST/CollectionMemberExpression.php | 27 - .../orm/src/Query/AST/ComparisonExpression.php | 32 - .../orm/src/Query/AST/ConditionalExpression.php | 25 - .../orm/src/Query/AST/ConditionalFactor.php | 26 - .../orm/src/Query/AST/ConditionalPrimary.php | 34 - .../doctrine/orm/src/Query/AST/ConditionalTerm.php | 25 - vendor/doctrine/orm/src/Query/AST/DeleteClause.php | 26 - .../doctrine/orm/src/Query/AST/DeleteStatement.php | 26 - .../AST/EmptyCollectionComparisonExpression.php | 26 - .../orm/src/Query/AST/ExistsExpression.php | 26 - vendor/doctrine/orm/src/Query/AST/FromClause.php | 25 - .../orm/src/Query/AST/Functions/AbsFunction.php | 37 - .../orm/src/Query/AST/Functions/AvgFunction.php | 27 - .../orm/src/Query/AST/Functions/BitAndFunction.php | 43 - .../orm/src/Query/AST/Functions/BitOrFunction.php | 43 - .../orm/src/Query/AST/Functions/ConcatFunction.php | 58 - .../orm/src/Query/AST/Functions/CountFunction.php | 35 - .../Query/AST/Functions/CurrentDateFunction.php | 29 - .../Query/AST/Functions/CurrentTimeFunction.php | 29 - .../AST/Functions/CurrentTimestampFunction.php | 29 - .../src/Query/AST/Functions/DateAddFunction.php | 83 - .../src/Query/AST/Functions/DateDiffFunction.php | 41 - .../src/Query/AST/Functions/DateSubFunction.php | 62 - .../orm/src/Query/AST/Functions/FunctionNode.php | 32 - .../src/Query/AST/Functions/IdentityFunction.php | 90 - .../orm/src/Query/AST/Functions/LengthFunction.php | 45 - .../orm/src/Query/AST/Functions/LocateFunction.php | 62 - .../orm/src/Query/AST/Functions/LowerFunction.php | 40 - .../orm/src/Query/AST/Functions/MaxFunction.php | 27 - .../orm/src/Query/AST/Functions/MinFunction.php | 27 - .../orm/src/Query/AST/Functions/ModFunction.php | 43 - .../orm/src/Query/AST/Functions/SizeFunction.php | 113 - .../orm/src/Query/AST/Functions/SqrtFunction.php | 40 - .../src/Query/AST/Functions/SubstringFunction.php | 58 - .../orm/src/Query/AST/Functions/SumFunction.php | 27 - .../orm/src/Query/AST/Functions/TrimFunction.php | 119 - .../orm/src/Query/AST/Functions/UpperFunction.php | 40 - .../orm/src/Query/AST/GeneralCaseExpression.php | 27 - .../doctrine/orm/src/Query/AST/GroupByClause.php | 20 - vendor/doctrine/orm/src/Query/AST/HavingClause.php | 19 - .../AST/IdentificationVariableDeclaration.php | 28 - .../orm/src/Query/AST/InListExpression.php | 23 - .../orm/src/Query/AST/InSubselectExpression.php | 22 - vendor/doctrine/orm/src/Query/AST/IndexBy.php | 26 - .../doctrine/orm/src/Query/AST/InputParameter.php | 35 - .../orm/src/Query/AST/InstanceOfExpression.php | 29 - vendor/doctrine/orm/src/Query/AST/Join.php | 34 - .../src/Query/AST/JoinAssociationDeclaration.php | 27 - .../Query/AST/JoinAssociationPathExpression.php | 19 - .../orm/src/Query/AST/JoinClassPathExpression.php | 26 - .../orm/src/Query/AST/JoinVariableDeclaration.php | 24 - .../doctrine/orm/src/Query/AST/LikeExpression.php | 29 - vendor/doctrine/orm/src/Query/AST/Literal.php | 26 - .../orm/src/Query/AST/NewObjectExpression.php | 25 - vendor/doctrine/orm/src/Query/AST/Node.php | 85 - .../orm/src/Query/AST/NullComparisonExpression.php | 26 - .../orm/src/Query/AST/NullIfExpression.php | 24 - .../doctrine/orm/src/Query/AST/OrderByClause.php | 25 - vendor/doctrine/orm/src/Query/AST/OrderByItem.php | 38 - .../orm/src/Query/AST/ParenthesisExpression.php | 22 - .../doctrine/orm/src/Query/AST/PathExpression.php | 39 - .../src/Query/AST/Phase2OptimizableConditional.php | 17 - .../orm/src/Query/AST/QuantifiedExpression.php | 43 - .../orm/src/Query/AST/RangeVariableDeclaration.php | 27 - vendor/doctrine/orm/src/Query/AST/SelectClause.php | 27 - .../orm/src/Query/AST/SelectExpression.php | 28 - .../doctrine/orm/src/Query/AST/SelectStatement.php | 32 - .../src/Query/AST/SimpleArithmeticExpression.php | 25 - .../orm/src/Query/AST/SimpleCaseExpression.php | 28 - .../orm/src/Query/AST/SimpleSelectClause.php | 26 - .../orm/src/Query/AST/SimpleSelectExpression.php | 27 - .../orm/src/Query/AST/SimpleWhenClause.php | 26 - vendor/doctrine/orm/src/Query/AST/Subselect.php | 32 - .../orm/src/Query/AST/SubselectFromClause.php | 25 - .../SubselectIdentificationVariableDeclaration.php | 19 - .../doctrine/orm/src/Query/AST/TypedExpression.php | 15 - vendor/doctrine/orm/src/Query/AST/UpdateClause.php | 29 - vendor/doctrine/orm/src/Query/AST/UpdateItem.php | 26 - .../doctrine/orm/src/Query/AST/UpdateStatement.php | 26 - vendor/doctrine/orm/src/Query/AST/WhenClause.php | 26 - vendor/doctrine/orm/src/Query/AST/WhereClause.php | 24 - .../orm/src/Query/Exec/AbstractSqlExecutor.php | 61 - .../src/Query/Exec/MultiTableDeleteExecutor.php | 131 - .../src/Query/Exec/MultiTableUpdateExecutor.php | 180 -- .../orm/src/Query/Exec/SingleSelectExecutor.php | 31 - .../Query/Exec/SingleTableDeleteUpdateExecutor.php | 42 - vendor/doctrine/orm/src/Query/Expr.php | 615 ---- vendor/doctrine/orm/src/Query/Expr/Andx.php | 32 - vendor/doctrine/orm/src/Query/Expr/Base.php | 96 - vendor/doctrine/orm/src/Query/Expr/Comparison.php | 47 - vendor/doctrine/orm/src/Query/Expr/Composite.php | 50 - vendor/doctrine/orm/src/Query/Expr/From.php | 48 - vendor/doctrine/orm/src/Query/Expr/Func.php | 48 - vendor/doctrine/orm/src/Query/Expr/GroupBy.php | 25 - vendor/doctrine/orm/src/Query/Expr/Join.php | 77 - vendor/doctrine/orm/src/Query/Expr/Literal.php | 25 - vendor/doctrine/orm/src/Query/Expr/Math.php | 59 - vendor/doctrine/orm/src/Query/Expr/OrderBy.php | 60 - vendor/doctrine/orm/src/Query/Expr/Orx.php | 32 - vendor/doctrine/orm/src/Query/Expr/Select.php | 28 - .../orm/src/Query/Filter/FilterException.php | 23 - vendor/doctrine/orm/src/Query/Filter/SQLFilter.php | 174 -- vendor/doctrine/orm/src/Query/FilterCollection.php | 260 -- vendor/doctrine/orm/src/Query/Lexer.php | 150 - vendor/doctrine/orm/src/Query/Parameter.php | 89 - .../orm/src/Query/ParameterTypeInferer.php | 77 - vendor/doctrine/orm/src/Query/Parser.php | 3269 -------------------- vendor/doctrine/orm/src/Query/ParserResult.php | 118 - vendor/doctrine/orm/src/Query/Printer.php | 64 - vendor/doctrine/orm/src/Query/QueryException.php | 155 - .../orm/src/Query/QueryExpressionVisitor.php | 180 -- vendor/doctrine/orm/src/Query/ResultSetMapping.php | 547 ---- .../orm/src/Query/ResultSetMappingBuilder.php | 281 -- vendor/doctrine/orm/src/Query/SqlWalker.php | 2264 -------------- vendor/doctrine/orm/src/Query/TokenType.php | 91 - vendor/doctrine/orm/src/Query/TreeWalker.php | 44 - .../doctrine/orm/src/Query/TreeWalkerAdapter.php | 90 - vendor/doctrine/orm/src/Query/TreeWalkerChain.php | 88 - vendor/doctrine/orm/src/QueryBuilder.php | 1375 -------- .../src/Repository/DefaultRepositoryFactory.php | 49 - .../src/Repository/Exception/InvalidFindByCall.php | 21 - .../Exception/InvalidMagicMethodCall.php | 27 - .../orm/src/Repository/RepositoryFactory.php | 26 - .../src/Tools/AttachEntityListenersListener.php | 69 - .../Command/AbstractEntityManagerCommand.php | 25 - .../Command/ClearCache/CollectionRegionCommand.php | 119 - .../Command/ClearCache/EntityRegionCommand.php | 110 - .../Console/Command/ClearCache/MetadataCommand.php | 52 - .../Console/Command/ClearCache/QueryCommand.php | 54 - .../Command/ClearCache/QueryRegionCommand.php | 101 - .../Console/Command/ClearCache/ResultCommand.php | 65 - .../Console/Command/GenerateProxiesCommand.php | 96 - .../orm/src/Tools/Console/Command/InfoCommand.php | 80 - .../Console/Command/MappingDescribeCommand.php | 279 -- .../src/Tools/Console/Command/RunDqlCommand.php | 118 - .../Console/Command/SchemaTool/AbstractCommand.php | 39 - .../Console/Command/SchemaTool/CreateCommand.php | 75 - .../Console/Command/SchemaTool/DropCommand.php | 116 - .../Console/Command/SchemaTool/UpdateCommand.php | 147 - .../Console/Command/ValidateSchemaCommand.php | 89 - .../orm/src/Tools/Console/ConsoleRunner.php | 88 - .../src/Tools/Console/EntityManagerProvider.php | 14 - .../ConnectionFromManagerProvider.php | 26 - .../SingleManagerProvider.php | 31 - .../UnknownManagerException.php | 23 - .../orm/src/Tools/Console/MetadataFilter.php | 92 - vendor/doctrine/orm/src/Tools/Debug.php | 158 - .../orm/src/Tools/DebugUnitOfWorkListener.php | 144 - .../src/Tools/Event/GenerateSchemaEventArgs.php | 33 - .../Tools/Event/GenerateSchemaTableEventArgs.php | 40 - .../src/Tools/Exception/MissingColumnException.php | 23 - .../orm/src/Tools/Exception/NotSupported.php | 16 - .../orm/src/Tools/Pagination/CountOutputWalker.php | 125 - .../orm/src/Tools/Pagination/CountWalker.php | 68 - .../Exception/RowNumberOverFunctionNotEnabled.php | 16 - .../Tools/Pagination/LimitSubqueryOutputWalker.php | 544 ---- .../src/Tools/Pagination/LimitSubqueryWalker.php | 155 - .../orm/src/Tools/Pagination/Paginator.php | 263 -- .../orm/src/Tools/Pagination/RootTypeWalker.php | 48 - .../src/Tools/Pagination/RowNumberOverFunction.php | 40 - .../orm/src/Tools/Pagination/WhereInWalker.php | 116 - .../orm/src/Tools/ResolveTargetEntityListener.php | 117 - vendor/doctrine/orm/src/Tools/SchemaTool.php | 932 ------ vendor/doctrine/orm/src/Tools/SchemaValidator.php | 443 --- vendor/doctrine/orm/src/Tools/ToolEvents.php | 23 - vendor/doctrine/orm/src/Tools/ToolsException.php | 24 - .../orm/src/TransactionRequiredException.php | 21 - .../doctrine/orm/src/UnexpectedResultException.php | 15 - vendor/doctrine/orm/src/UnitOfWork.php | 3252 ------------------- .../src/Utility/HierarchyDiscriminatorResolver.php | 44 - .../orm/src/Utility/IdentifierFlattener.php | 83 - vendor/doctrine/orm/src/Utility/LockSqlHelper.php | 35 - .../doctrine/orm/src/Utility/PersisterHelper.php | 108 - 425 files changed, 51805 deletions(-) delete mode 100644 vendor/doctrine/orm/src/AbstractQuery.php delete mode 100644 vendor/doctrine/orm/src/Cache.php delete mode 100644 vendor/doctrine/orm/src/Cache/AssociationCacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/CacheConfiguration.php delete mode 100644 vendor/doctrine/orm/src/Cache/CacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/CacheException.php delete mode 100644 vendor/doctrine/orm/src/Cache/CacheFactory.php delete mode 100644 vendor/doctrine/orm/src/Cache/CacheKey.php delete mode 100644 vendor/doctrine/orm/src/Cache/CollectionCacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/CollectionCacheKey.php delete mode 100644 vendor/doctrine/orm/src/Cache/CollectionHydrator.php delete mode 100644 vendor/doctrine/orm/src/Cache/ConcurrentRegion.php delete mode 100644 vendor/doctrine/orm/src/Cache/DefaultCache.php delete mode 100644 vendor/doctrine/orm/src/Cache/DefaultCacheFactory.php delete mode 100644 vendor/doctrine/orm/src/Cache/DefaultCollectionHydrator.php delete mode 100644 vendor/doctrine/orm/src/Cache/DefaultEntityHydrator.php delete mode 100644 vendor/doctrine/orm/src/Cache/DefaultQueryCache.php delete mode 100644 vendor/doctrine/orm/src/Cache/EntityCacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/EntityCacheKey.php delete mode 100644 vendor/doctrine/orm/src/Cache/EntityHydrator.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/CacheException.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/CannotUpdateReadOnlyCollection.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/CannotUpdateReadOnlyEntity.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/FeatureNotImplemented.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/NonCacheableEntity.php delete mode 100644 vendor/doctrine/orm/src/Cache/Exception/NonCacheableEntityAssociation.php delete mode 100644 vendor/doctrine/orm/src/Cache/Lock.php delete mode 100644 vendor/doctrine/orm/src/Cache/LockException.php delete mode 100644 vendor/doctrine/orm/src/Cache/Logging/CacheLogger.php delete mode 100644 vendor/doctrine/orm/src/Cache/Logging/CacheLoggerChain.php delete mode 100644 vendor/doctrine/orm/src/Cache/Logging/StatisticsCacheLogger.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/AbstractCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Cache/QueryCache.php delete mode 100644 vendor/doctrine/orm/src/Cache/QueryCacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/QueryCacheKey.php delete mode 100644 vendor/doctrine/orm/src/Cache/QueryCacheValidator.php delete mode 100644 vendor/doctrine/orm/src/Cache/Region.php delete mode 100644 vendor/doctrine/orm/src/Cache/Region/DefaultRegion.php delete mode 100644 vendor/doctrine/orm/src/Cache/Region/FileLockRegion.php delete mode 100644 vendor/doctrine/orm/src/Cache/Region/UpdateTimestampCache.php delete mode 100644 vendor/doctrine/orm/src/Cache/RegionsConfiguration.php delete mode 100644 vendor/doctrine/orm/src/Cache/TimestampCacheEntry.php delete mode 100644 vendor/doctrine/orm/src/Cache/TimestampCacheKey.php delete mode 100644 vendor/doctrine/orm/src/Cache/TimestampQueryCacheValidator.php delete mode 100644 vendor/doctrine/orm/src/Cache/TimestampRegion.php delete mode 100644 vendor/doctrine/orm/src/Configuration.php delete mode 100644 vendor/doctrine/orm/src/Decorator/EntityManagerDecorator.php delete mode 100644 vendor/doctrine/orm/src/EntityManager.php delete mode 100644 vendor/doctrine/orm/src/EntityManagerInterface.php delete mode 100644 vendor/doctrine/orm/src/EntityNotFoundException.php delete mode 100644 vendor/doctrine/orm/src/EntityRepository.php delete mode 100644 vendor/doctrine/orm/src/Event/ListenersInvoker.php delete mode 100644 vendor/doctrine/orm/src/Event/LoadClassMetadataEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/OnClassMetadataNotFoundEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/OnClearEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/OnFlushEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PostFlushEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PostLoadEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PostPersistEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PostRemoveEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PostUpdateEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PreFlushEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PrePersistEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PreRemoveEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Event/PreUpdateEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Events.php delete mode 100644 vendor/doctrine/orm/src/Exception/ConfigurationException.php delete mode 100644 vendor/doctrine/orm/src/Exception/EntityIdentityCollisionException.php delete mode 100644 vendor/doctrine/orm/src/Exception/EntityManagerClosed.php delete mode 100644 vendor/doctrine/orm/src/Exception/EntityMissingAssignedId.php delete mode 100644 vendor/doctrine/orm/src/Exception/InvalidEntityRepository.php delete mode 100644 vendor/doctrine/orm/src/Exception/InvalidHydrationMode.php delete mode 100644 vendor/doctrine/orm/src/Exception/ManagerException.php delete mode 100644 vendor/doctrine/orm/src/Exception/MissingIdentifierField.php delete mode 100644 vendor/doctrine/orm/src/Exception/MissingMappingDriverImplementation.php delete mode 100644 vendor/doctrine/orm/src/Exception/MultipleSelectorsFoundException.php delete mode 100644 vendor/doctrine/orm/src/Exception/NotSupported.php delete mode 100644 vendor/doctrine/orm/src/Exception/ORMException.php delete mode 100644 vendor/doctrine/orm/src/Exception/PersisterException.php delete mode 100644 vendor/doctrine/orm/src/Exception/RepositoryException.php delete mode 100644 vendor/doctrine/orm/src/Exception/SchemaToolException.php delete mode 100644 vendor/doctrine/orm/src/Exception/UnexpectedAssociationValue.php delete mode 100644 vendor/doctrine/orm/src/Exception/UnrecognizedIdentifierFields.php delete mode 100644 vendor/doctrine/orm/src/Id/AbstractIdGenerator.php delete mode 100644 vendor/doctrine/orm/src/Id/AssignedGenerator.php delete mode 100644 vendor/doctrine/orm/src/Id/BigIntegerIdentityGenerator.php delete mode 100644 vendor/doctrine/orm/src/Id/IdentityGenerator.php delete mode 100644 vendor/doctrine/orm/src/Id/SequenceGenerator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/AbstractHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/ArrayHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/HydrationException.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/ObjectHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/ScalarColumnHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/ScalarHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/SimpleObjectHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/Hydration/SingleScalarHydrator.php delete mode 100644 vendor/doctrine/orm/src/Internal/HydrationCompleteHandler.php delete mode 100644 vendor/doctrine/orm/src/Internal/NoUnknownNamedArguments.php delete mode 100644 vendor/doctrine/orm/src/Internal/QueryType.php delete mode 100644 vendor/doctrine/orm/src/Internal/SQLResultCasing.php delete mode 100644 vendor/doctrine/orm/src/Internal/StronglyConnectedComponents.php delete mode 100644 vendor/doctrine/orm/src/Internal/TopologicalSort.php delete mode 100644 vendor/doctrine/orm/src/Internal/TopologicalSort/CycleDetectedException.php delete mode 100644 vendor/doctrine/orm/src/LazyCriteriaCollection.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AnsiQuoteStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ArrayAccessImplementation.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AssociationOverride.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AssociationOverrides.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AttributeOverride.php delete mode 100644 vendor/doctrine/orm/src/Mapping/AttributeOverrides.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/AssociationBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/ClassMetadataBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/EmbeddedBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/EntityListenerBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/FieldBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/ManyToManyAssociationBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Builder/OneToManyAssociationBuilder.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Cache.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ChainTypedFieldMapper.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ChangeTrackingPolicy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ClassMetadata.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Column.php delete mode 100644 vendor/doctrine/orm/src/Mapping/CustomIdGenerator.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DefaultEntityListenerResolver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DefaultNamingStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DefaultQuoteStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DefaultTypedFieldMapper.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DiscriminatorColumn.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DiscriminatorColumnMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/DiscriminatorMap.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/AttributeDriver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/DatabaseDriver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/ReflectionBasedDriver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/RepeatableAttributeCollection.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/SimplifiedXmlDriver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Driver/XmlDriver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Embeddable.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Embedded.php delete mode 100644 vendor/doctrine/orm/src/Mapping/EmbeddedClassMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Entity.php delete mode 100644 vendor/doctrine/orm/src/Mapping/EntityListenerResolver.php delete mode 100644 vendor/doctrine/orm/src/Mapping/EntityListeners.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Exception/InvalidCustomGenerator.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Exception/UnknownGeneratorType.php delete mode 100644 vendor/doctrine/orm/src/Mapping/FieldMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/GeneratedValue.php delete mode 100644 vendor/doctrine/orm/src/Mapping/HasLifecycleCallbacks.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Id.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Index.php delete mode 100644 vendor/doctrine/orm/src/Mapping/InheritanceType.php delete mode 100644 vendor/doctrine/orm/src/Mapping/InverseJoinColumn.php delete mode 100644 vendor/doctrine/orm/src/Mapping/InverseSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinColumn.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinColumnMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinColumnProperties.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinColumns.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinTable.php delete mode 100644 vendor/doctrine/orm/src/Mapping/JoinTableMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToMany.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToManyAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToManyInverseSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToManyOwningSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToOne.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ManyToOneAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/MappedSuperclass.php delete mode 100644 vendor/doctrine/orm/src/Mapping/MappingAttribute.php delete mode 100644 vendor/doctrine/orm/src/Mapping/MappingException.php delete mode 100644 vendor/doctrine/orm/src/Mapping/NamingStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToMany.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToManyAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToOne.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToOneAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToOneInverseSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OneToOneOwningSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OrderBy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/OwningSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PostLoad.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PostPersist.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PostRemove.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PostUpdate.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PreFlush.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PrePersist.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PreRemove.php delete mode 100644 vendor/doctrine/orm/src/Mapping/PreUpdate.php delete mode 100644 vendor/doctrine/orm/src/Mapping/QuoteStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ReflectionEmbeddedProperty.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ReflectionEnumProperty.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ReflectionReadonlyProperty.php delete mode 100644 vendor/doctrine/orm/src/Mapping/SequenceGenerator.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Table.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToManyAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToManyAssociationMappingImplementation.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToManyInverseSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToManyOwningSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToOneAssociationMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToOneInverseSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/ToOneOwningSideMapping.php delete mode 100644 vendor/doctrine/orm/src/Mapping/TypedFieldMapper.php delete mode 100644 vendor/doctrine/orm/src/Mapping/UnderscoreNamingStrategy.php delete mode 100644 vendor/doctrine/orm/src/Mapping/UniqueConstraint.php delete mode 100644 vendor/doctrine/orm/src/Mapping/Version.php delete mode 100644 vendor/doctrine/orm/src/NativeQuery.php delete mode 100644 vendor/doctrine/orm/src/NoResultException.php delete mode 100644 vendor/doctrine/orm/src/NonUniqueResultException.php delete mode 100644 vendor/doctrine/orm/src/ORMInvalidArgumentException.php delete mode 100644 vendor/doctrine/orm/src/ORMSetup.php delete mode 100644 vendor/doctrine/orm/src/OptimisticLockException.php delete mode 100644 vendor/doctrine/orm/src/PersistentCollection.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Collection/AbstractCollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Collection/CollectionPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Collection/ManyToManyPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Collection/OneToManyPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/AbstractEntityInheritancePersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/BasicEntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/CachedPersisterContext.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/EntityPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/JoinedSubclassPersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Entity/SingleTablePersister.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Exception/CantUseInOperatorOnCompositeKeys.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Exception/InvalidOrientation.php delete mode 100644 vendor/doctrine/orm/src/Persisters/Exception/UnrecognizedField.php delete mode 100644 vendor/doctrine/orm/src/Persisters/MatchingAssociationFieldRequiresObject.php delete mode 100644 vendor/doctrine/orm/src/Persisters/PersisterException.php delete mode 100644 vendor/doctrine/orm/src/Persisters/SqlExpressionVisitor.php delete mode 100644 vendor/doctrine/orm/src/Persisters/SqlValueVisitor.php delete mode 100644 vendor/doctrine/orm/src/PessimisticLockException.php delete mode 100644 vendor/doctrine/orm/src/Proxy/Autoloader.php delete mode 100644 vendor/doctrine/orm/src/Proxy/DefaultProxyClassNameResolver.php delete mode 100644 vendor/doctrine/orm/src/Proxy/InternalProxy.php delete mode 100644 vendor/doctrine/orm/src/Proxy/NotAProxyClass.php delete mode 100644 vendor/doctrine/orm/src/Proxy/ProxyFactory.php delete mode 100644 vendor/doctrine/orm/src/Query.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ASTException.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/AggregateExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ArithmeticExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ArithmeticFactor.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ArithmeticTerm.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/BetweenExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/CoalesceExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/CollectionMemberExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ComparisonExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ConditionalExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ConditionalFactor.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ConditionalPrimary.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ConditionalTerm.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/DeleteClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/DeleteStatement.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/EmptyCollectionComparisonExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ExistsExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/FromClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/AbsFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/AvgFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/BitAndFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/BitOrFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/ConcatFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/CountFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/CurrentDateFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimeFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimestampFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/DateAddFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/DateDiffFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/DateSubFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/FunctionNode.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/IdentityFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/LengthFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/LocateFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/LowerFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/MaxFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/MinFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/ModFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/SizeFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/SqrtFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/SubstringFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/SumFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/TrimFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Functions/UpperFunction.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/GeneralCaseExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/GroupByClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/HavingClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/IdentificationVariableDeclaration.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/InListExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/InSubselectExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/IndexBy.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/InputParameter.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/InstanceOfExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Join.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/JoinAssociationDeclaration.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/JoinAssociationPathExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/JoinClassPathExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/JoinVariableDeclaration.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/LikeExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Literal.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/NewObjectExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Node.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/NullComparisonExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/NullIfExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/OrderByClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/OrderByItem.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/ParenthesisExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/PathExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Phase2OptimizableConditional.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/QuantifiedExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/RangeVariableDeclaration.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SelectClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SelectExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SelectStatement.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SimpleArithmeticExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SimpleCaseExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SimpleSelectClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SimpleSelectExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SimpleWhenClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/Subselect.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SubselectFromClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/SubselectIdentificationVariableDeclaration.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/TypedExpression.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/UpdateClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/UpdateItem.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/UpdateStatement.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/WhenClause.php delete mode 100644 vendor/doctrine/orm/src/Query/AST/WhereClause.php delete mode 100644 vendor/doctrine/orm/src/Query/Exec/AbstractSqlExecutor.php delete mode 100644 vendor/doctrine/orm/src/Query/Exec/MultiTableDeleteExecutor.php delete mode 100644 vendor/doctrine/orm/src/Query/Exec/MultiTableUpdateExecutor.php delete mode 100644 vendor/doctrine/orm/src/Query/Exec/SingleSelectExecutor.php delete mode 100644 vendor/doctrine/orm/src/Query/Exec/SingleTableDeleteUpdateExecutor.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Andx.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Base.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Comparison.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Composite.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/From.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Func.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/GroupBy.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Join.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Literal.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Math.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/OrderBy.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Orx.php delete mode 100644 vendor/doctrine/orm/src/Query/Expr/Select.php delete mode 100644 vendor/doctrine/orm/src/Query/Filter/FilterException.php delete mode 100644 vendor/doctrine/orm/src/Query/Filter/SQLFilter.php delete mode 100644 vendor/doctrine/orm/src/Query/FilterCollection.php delete mode 100644 vendor/doctrine/orm/src/Query/Lexer.php delete mode 100644 vendor/doctrine/orm/src/Query/Parameter.php delete mode 100644 vendor/doctrine/orm/src/Query/ParameterTypeInferer.php delete mode 100644 vendor/doctrine/orm/src/Query/Parser.php delete mode 100644 vendor/doctrine/orm/src/Query/ParserResult.php delete mode 100644 vendor/doctrine/orm/src/Query/Printer.php delete mode 100644 vendor/doctrine/orm/src/Query/QueryException.php delete mode 100644 vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php delete mode 100644 vendor/doctrine/orm/src/Query/ResultSetMapping.php delete mode 100644 vendor/doctrine/orm/src/Query/ResultSetMappingBuilder.php delete mode 100644 vendor/doctrine/orm/src/Query/SqlWalker.php delete mode 100644 vendor/doctrine/orm/src/Query/TokenType.php delete mode 100644 vendor/doctrine/orm/src/Query/TreeWalker.php delete mode 100644 vendor/doctrine/orm/src/Query/TreeWalkerAdapter.php delete mode 100644 vendor/doctrine/orm/src/Query/TreeWalkerChain.php delete mode 100644 vendor/doctrine/orm/src/QueryBuilder.php delete mode 100644 vendor/doctrine/orm/src/Repository/DefaultRepositoryFactory.php delete mode 100644 vendor/doctrine/orm/src/Repository/Exception/InvalidFindByCall.php delete mode 100644 vendor/doctrine/orm/src/Repository/Exception/InvalidMagicMethodCall.php delete mode 100644 vendor/doctrine/orm/src/Repository/RepositoryFactory.php delete mode 100644 vendor/doctrine/orm/src/Tools/AttachEntityListenersListener.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/AbstractEntityManagerCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/CollectionRegionCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/EntityRegionCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/MetadataCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryRegionCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/ResultCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/GenerateProxiesCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/InfoCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/MappingDescribeCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/RunDqlCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/AbstractCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/CreateCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/DropCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/UpdateCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/Command/ValidateSchemaCommand.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/ConsoleRunner.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/ConnectionFromManagerProvider.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/SingleManagerProvider.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/UnknownManagerException.php delete mode 100644 vendor/doctrine/orm/src/Tools/Console/MetadataFilter.php delete mode 100644 vendor/doctrine/orm/src/Tools/Debug.php delete mode 100644 vendor/doctrine/orm/src/Tools/DebugUnitOfWorkListener.php delete mode 100644 vendor/doctrine/orm/src/Tools/Event/GenerateSchemaEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Tools/Event/GenerateSchemaTableEventArgs.php delete mode 100644 vendor/doctrine/orm/src/Tools/Exception/MissingColumnException.php delete mode 100644 vendor/doctrine/orm/src/Tools/Exception/NotSupported.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/CountOutputWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryOutputWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/Paginator.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/ResolveTargetEntityListener.php delete mode 100644 vendor/doctrine/orm/src/Tools/SchemaTool.php delete mode 100644 vendor/doctrine/orm/src/Tools/SchemaValidator.php delete mode 100644 vendor/doctrine/orm/src/Tools/ToolEvents.php delete mode 100644 vendor/doctrine/orm/src/Tools/ToolsException.php delete mode 100644 vendor/doctrine/orm/src/TransactionRequiredException.php delete mode 100644 vendor/doctrine/orm/src/UnexpectedResultException.php delete mode 100644 vendor/doctrine/orm/src/UnitOfWork.php delete mode 100644 vendor/doctrine/orm/src/Utility/HierarchyDiscriminatorResolver.php delete mode 100644 vendor/doctrine/orm/src/Utility/IdentifierFlattener.php delete mode 100644 vendor/doctrine/orm/src/Utility/LockSqlHelper.php delete mode 100644 vendor/doctrine/orm/src/Utility/PersisterHelper.php (limited to 'vendor/doctrine/orm/src') diff --git a/vendor/doctrine/orm/src/AbstractQuery.php b/vendor/doctrine/orm/src/AbstractQuery.php deleted file mode 100644 index 0ff92c3..0000000 --- a/vendor/doctrine/orm/src/AbstractQuery.php +++ /dev/null @@ -1,1116 +0,0 @@ - - */ - protected ArrayCollection $parameters; - - /** - * The user-specified ResultSetMapping to use. - */ - protected ResultSetMapping|null $resultSetMapping = null; - - /** - * The map of query hints. - * - * @psalm-var array - */ - protected array $hints = []; - - /** - * The hydration mode. - * - * @psalm-var string|AbstractQuery::HYDRATE_* - */ - protected string|int $hydrationMode = self::HYDRATE_OBJECT; - - protected QueryCacheProfile|null $queryCacheProfile = null; - - /** - * Whether or not expire the result cache. - */ - protected bool $expireResultCache = false; - - protected QueryCacheProfile|null $hydrationCacheProfile = null; - - /** - * Whether to use second level cache, if available. - */ - protected bool $cacheable = false; - - protected bool $hasCache = false; - - /** - * Second level cache region name. - */ - protected string|null $cacheRegion = null; - - /** - * Second level query cache mode. - * - * @psalm-var Cache::MODE_*|null - */ - protected int|null $cacheMode = null; - - protected CacheLogger|null $cacheLogger = null; - - protected int $lifetime = 0; - - /** - * Initializes a new instance of a class derived from AbstractQuery. - */ - public function __construct( - /** - * The entity manager used by this query object. - */ - protected EntityManagerInterface $em, - ) { - $this->parameters = new ArrayCollection(); - $this->hints = $em->getConfiguration()->getDefaultQueryHints(); - $this->hasCache = $this->em->getConfiguration()->isSecondLevelCacheEnabled(); - - if ($this->hasCache) { - $this->cacheLogger = $em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheLogger(); - } - } - - /** - * Enable/disable second level query (result) caching for this query. - * - * @return $this - */ - public function setCacheable(bool $cacheable): static - { - $this->cacheable = $cacheable; - - return $this; - } - - /** @return bool TRUE if the query results are enabled for second level cache, FALSE otherwise. */ - public function isCacheable(): bool - { - return $this->cacheable; - } - - /** @return $this */ - public function setCacheRegion(string $cacheRegion): static - { - $this->cacheRegion = $cacheRegion; - - return $this; - } - - /** - * Obtain the name of the second level query cache region in which query results will be stored - * - * @return string|null The cache region name; NULL indicates the default region. - */ - public function getCacheRegion(): string|null - { - return $this->cacheRegion; - } - - /** @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise. */ - protected function isCacheEnabled(): bool - { - return $this->cacheable && $this->hasCache; - } - - public function getLifetime(): int - { - return $this->lifetime; - } - - /** - * Sets the life-time for this query into second level cache. - * - * @return $this - */ - public function setLifetime(int $lifetime): static - { - $this->lifetime = $lifetime; - - return $this; - } - - /** @psalm-return Cache::MODE_*|null */ - public function getCacheMode(): int|null - { - return $this->cacheMode; - } - - /** - * @psalm-param Cache::MODE_* $cacheMode - * - * @return $this - */ - public function setCacheMode(int $cacheMode): static - { - $this->cacheMode = $cacheMode; - - return $this; - } - - /** - * Gets the SQL query that corresponds to this query object. - * The returned SQL syntax depends on the connection driver that is used - * by this query object at the time of this method call. - * - * @return list|string SQL query - */ - abstract public function getSQL(): string|array; - - /** - * Retrieves the associated EntityManager of this Query instance. - */ - public function getEntityManager(): EntityManagerInterface - { - return $this->em; - } - - /** - * Frees the resources used by the query object. - * - * Resets Parameters, Parameter Types and Query Hints. - */ - public function free(): void - { - $this->parameters = new ArrayCollection(); - - $this->hints = $this->em->getConfiguration()->getDefaultQueryHints(); - } - - /** - * Get all defined parameters. - * - * @psalm-return ArrayCollection - */ - public function getParameters(): ArrayCollection - { - return $this->parameters; - } - - /** - * Gets a query parameter. - * - * @param int|string $key The key (index or name) of the bound parameter. - * - * @return Parameter|null The value of the bound parameter, or NULL if not available. - */ - public function getParameter(int|string $key): Parameter|null - { - $key = Parameter::normalizeName($key); - - $filteredParameters = $this->parameters->filter( - static fn (Parameter $parameter): bool => $parameter->getName() === $key - ); - - return ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null; - } - - /** - * Sets a collection of query parameters. - * - * @param ArrayCollection|mixed[] $parameters - * @psalm-param ArrayCollection|mixed[] $parameters - * - * @return $this - */ - public function setParameters(ArrayCollection|array $parameters): static - { - if (is_array($parameters)) { - /** @psalm-var ArrayCollection $parameterCollection */ - $parameterCollection = new ArrayCollection(); - - foreach ($parameters as $key => $value) { - $parameterCollection->add(new Parameter($key, $value)); - } - - $parameters = $parameterCollection; - } - - $this->parameters = $parameters; - - return $this; - } - - /** - * Sets a query parameter. - * - * @param string|int $key The parameter position or name. - * @param mixed $value The parameter value. - * @param ParameterType|ArrayParameterType|string|int|null $type The parameter type. If specified, the given value - * will be run through the type conversion of this - * type. This is usually not needed for strings and - * numeric types. - * - * @return $this - */ - public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|int|null $type = null): static - { - $existingParameter = $this->getParameter($key); - - if ($existingParameter !== null) { - $existingParameter->setValue($value, $type); - - return $this; - } - - $this->parameters->add(new Parameter($key, $value, $type)); - - return $this; - } - - /** - * Processes an individual parameter value. - * - * @throws ORMInvalidArgumentException - */ - public function processParameterValue(mixed $value): mixed - { - if (is_scalar($value)) { - return $value; - } - - if ($value instanceof Collection) { - $value = iterator_to_array($value); - } - - if (is_array($value)) { - $value = $this->processArrayParameterValue($value); - - return $value; - } - - if ($value instanceof ClassMetadata) { - return $value->name; - } - - if ($value instanceof BackedEnum) { - return $value->value; - } - - if (! is_object($value)) { - return $value; - } - - try { - $class = DefaultProxyClassNameResolver::getClass($value); - $value = $this->em->getUnitOfWork()->getSingleIdentifierValue($value); - - if ($value === null) { - throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class); - } - } catch (MappingException | ORMMappingException) { - /* Silence any mapping exceptions. These can occur if the object in - question is not a mapped entity, in which case we just don't do - any preparation on the value. - Depending on MappingDriver, either MappingException or - ORMMappingException is thrown. */ - - $value = $this->potentiallyProcessIterable($value); - } - - return $value; - } - - /** - * If no mapping is detected, trying to resolve the value as a Traversable - */ - private function potentiallyProcessIterable(mixed $value): mixed - { - if ($value instanceof Traversable) { - $value = iterator_to_array($value); - $value = $this->processArrayParameterValue($value); - } - - return $value; - } - - /** - * Process a parameter value which was previously identified as an array - * - * @param mixed[] $value - * - * @return mixed[] - */ - private function processArrayParameterValue(array $value): array - { - foreach ($value as $key => $paramValue) { - $paramValue = $this->processParameterValue($paramValue); - $value[$key] = is_array($paramValue) ? reset($paramValue) : $paramValue; - } - - return $value; - } - - /** - * Sets the ResultSetMapping that should be used for hydration. - * - * @return $this - */ - public function setResultSetMapping(ResultSetMapping $rsm): static - { - $this->translateNamespaces($rsm); - $this->resultSetMapping = $rsm; - - return $this; - } - - /** - * Gets the ResultSetMapping used for hydration. - */ - protected function getResultSetMapping(): ResultSetMapping|null - { - return $this->resultSetMapping; - } - - /** - * Allows to translate entity namespaces to full qualified names. - */ - private function translateNamespaces(ResultSetMapping $rsm): void - { - $translate = fn ($alias): string => $this->em->getClassMetadata($alias)->getName(); - - $rsm->aliasMap = array_map($translate, $rsm->aliasMap); - $rsm->declaringClasses = array_map($translate, $rsm->declaringClasses); - } - - /** - * Set a cache profile for hydration caching. - * - * If no result cache driver is set in the QueryCacheProfile, the default - * result cache driver is used from the configuration. - * - * Important: Hydration caching does NOT register entities in the - * UnitOfWork when retrieved from the cache. Never use result cached - * entities for requests that also flush the EntityManager. If you want - * some form of caching with UnitOfWork registration you should use - * {@see AbstractQuery::setResultCacheProfile()}. - * - * @return $this - * - * @example - * $lifetime = 100; - * $resultKey = "abc"; - * $query->setHydrationCacheProfile(new QueryCacheProfile()); - * $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey)); - */ - public function setHydrationCacheProfile(QueryCacheProfile|null $profile): static - { - if ($profile === null) { - $this->hydrationCacheProfile = null; - - return $this; - } - - if (! $profile->getResultCache()) { - $defaultHydrationCacheImpl = $this->em->getConfiguration()->getHydrationCache(); - if ($defaultHydrationCacheImpl) { - $profile = $profile->setResultCache($defaultHydrationCacheImpl); - } - } - - $this->hydrationCacheProfile = $profile; - - return $this; - } - - public function getHydrationCacheProfile(): QueryCacheProfile|null - { - return $this->hydrationCacheProfile; - } - - /** - * Set a cache profile for the result cache. - * - * If no result cache driver is set in the QueryCacheProfile, the default - * result cache driver is used from the configuration. - * - * @return $this - */ - public function setResultCacheProfile(QueryCacheProfile|null $profile): static - { - if ($profile === null) { - $this->queryCacheProfile = null; - - return $this; - } - - if (! $profile->getResultCache()) { - $defaultResultCache = $this->em->getConfiguration()->getResultCache(); - if ($defaultResultCache) { - $profile = $profile->setResultCache($defaultResultCache); - } - } - - $this->queryCacheProfile = $profile; - - return $this; - } - - /** - * Defines a cache driver to be used for caching result sets and implicitly enables caching. - */ - public function setResultCache(CacheItemPoolInterface|null $resultCache): static - { - if ($resultCache === null) { - if ($this->queryCacheProfile) { - $this->queryCacheProfile = new QueryCacheProfile($this->queryCacheProfile->getLifetime(), $this->queryCacheProfile->getCacheKey()); - } - - return $this; - } - - $this->queryCacheProfile = $this->queryCacheProfile - ? $this->queryCacheProfile->setResultCache($resultCache) - : new QueryCacheProfile(0, null, $resultCache); - - return $this; - } - - /** - * Enables caching of the results of this query, for given or default amount of seconds - * and optionally specifies which ID to use for the cache entry. - * - * @param int|null $lifetime How long the cache entry is valid, in seconds. - * @param string|null $resultCacheId ID to use for the cache entry. - * - * @return $this - */ - public function enableResultCache(int|null $lifetime = null, string|null $resultCacheId = null): static - { - $this->setResultCacheLifetime($lifetime); - $this->setResultCacheId($resultCacheId); - - return $this; - } - - /** - * Disables caching of the results of this query. - * - * @return $this - */ - public function disableResultCache(): static - { - $this->queryCacheProfile = null; - - return $this; - } - - /** - * Defines how long the result cache will be active before expire. - * - * @param int|null $lifetime How long the cache entry is valid, in seconds. - * - * @return $this - */ - public function setResultCacheLifetime(int|null $lifetime): static - { - $lifetime = (int) $lifetime; - - if ($this->queryCacheProfile) { - $this->queryCacheProfile = $this->queryCacheProfile->setLifetime($lifetime); - - return $this; - } - - $this->queryCacheProfile = new QueryCacheProfile($lifetime); - - $cache = $this->em->getConfiguration()->getResultCache(); - if (! $cache) { - return $this; - } - - $this->queryCacheProfile = $this->queryCacheProfile->setResultCache($cache); - - return $this; - } - - /** - * Defines if the result cache is active or not. - * - * @param bool $expire Whether or not to force resultset cache expiration. - * - * @return $this - */ - public function expireResultCache(bool $expire = true): static - { - $this->expireResultCache = $expire; - - return $this; - } - - /** - * Retrieves if the resultset cache is active or not. - */ - public function getExpireResultCache(): bool - { - return $this->expireResultCache; - } - - public function getQueryCacheProfile(): QueryCacheProfile|null - { - return $this->queryCacheProfile; - } - - /** - * Change the default fetch mode of an association for this query. - * - * @param class-string $class - * @psalm-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode - */ - public function setFetchMode(string $class, string $assocName, int $fetchMode): static - { - $this->hints['fetchMode'][$class][$assocName] = $fetchMode; - - return $this; - } - - /** - * Defines the processing mode to be used during hydration / result set transformation. - * - * @param string|int $hydrationMode Doctrine processing mode to be used during hydration process. - * One of the Query::HYDRATE_* constants. - * @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode - * - * @return $this - */ - public function setHydrationMode(string|int $hydrationMode): static - { - $this->hydrationMode = $hydrationMode; - - return $this; - } - - /** - * Gets the hydration mode currently used by the query. - * - * @psalm-return string|AbstractQuery::HYDRATE_* - */ - public function getHydrationMode(): string|int - { - return $this->hydrationMode; - } - - /** - * Gets the list of results for the query. - * - * Alias for execute(null, $hydrationMode = HYDRATE_OBJECT). - * - * @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode - */ - public function getResult(string|int $hydrationMode = self::HYDRATE_OBJECT): mixed - { - return $this->execute(null, $hydrationMode); - } - - /** - * Gets the array of results for the query. - * - * Alias for execute(null, HYDRATE_ARRAY). - * - * @return mixed[] - */ - public function getArrayResult(): array - { - return $this->execute(null, self::HYDRATE_ARRAY); - } - - /** - * Gets one-dimensional array of results for the query. - * - * Alias for execute(null, HYDRATE_SCALAR_COLUMN). - * - * @return mixed[] - */ - public function getSingleColumnResult(): array - { - return $this->execute(null, self::HYDRATE_SCALAR_COLUMN); - } - - /** - * Gets the scalar results for the query. - * - * Alias for execute(null, HYDRATE_SCALAR). - * - * @return mixed[] - */ - public function getScalarResult(): array - { - return $this->execute(null, self::HYDRATE_SCALAR); - } - - /** - * Get exactly one result or null. - * - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @throws NonUniqueResultException - */ - public function getOneOrNullResult(string|int|null $hydrationMode = null): mixed - { - try { - $result = $this->execute(null, $hydrationMode); - } catch (NoResultException) { - return null; - } - - if ($this->hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) { - return null; - } - - if (! is_array($result)) { - return $result; - } - - if (count($result) > 1) { - throw new NonUniqueResultException(); - } - - return array_shift($result); - } - - /** - * Gets the single result of the query. - * - * Enforces the presence as well as the uniqueness of the result. - * - * If the result is not unique, a NonUniqueResultException is thrown. - * If there is no result, a NoResultException is thrown. - * - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @throws NonUniqueResultException If the query result is not unique. - * @throws NoResultException If the query returned no result. - */ - public function getSingleResult(string|int|null $hydrationMode = null): mixed - { - $result = $this->execute(null, $hydrationMode); - - if ($this->hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) { - throw new NoResultException(); - } - - if (! is_array($result)) { - return $result; - } - - if (count($result) > 1) { - throw new NonUniqueResultException(); - } - - return array_shift($result); - } - - /** - * Gets the single scalar result of the query. - * - * Alias for getSingleResult(HYDRATE_SINGLE_SCALAR). - * - * @return bool|float|int|string|null The scalar result. - * - * @throws NoResultException If the query returned no result. - * @throws NonUniqueResultException If the query result is not unique. - */ - public function getSingleScalarResult(): mixed - { - return $this->getSingleResult(self::HYDRATE_SINGLE_SCALAR); - } - - /** - * Sets a query hint. If the hint name is not recognized, it is silently ignored. - * - * @return $this - */ - public function setHint(string $name, mixed $value): static - { - $this->hints[$name] = $value; - - return $this; - } - - /** - * Gets the value of a query hint. If the hint name is not recognized, FALSE is returned. - * - * @return mixed The value of the hint or FALSE, if the hint name is not recognized. - */ - public function getHint(string $name): mixed - { - return $this->hints[$name] ?? false; - } - - public function hasHint(string $name): bool - { - return isset($this->hints[$name]); - } - - /** - * Return the key value map of query hints that are currently set. - * - * @return array - */ - public function getHints(): array - { - return $this->hints; - } - - /** - * Executes the query and returns an iterable that can be used to incrementally - * iterate over the result. - * - * @psalm-param ArrayCollection|mixed[] $parameters - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @return iterable - */ - public function toIterable( - ArrayCollection|array $parameters = [], - string|int|null $hydrationMode = null, - ): iterable { - if ($hydrationMode !== null) { - $this->setHydrationMode($hydrationMode); - } - - if (count($parameters) !== 0) { - $this->setParameters($parameters); - } - - $rsm = $this->getResultSetMapping(); - if ($rsm === null) { - throw new LogicException('Uninitialized result set mapping.'); - } - - if ($rsm->isMixed && count($rsm->scalarMappings) > 0) { - throw QueryException::iterateWithMixedResultNotAllowed(); - } - - $stmt = $this->_doExecute(); - - return $this->em->newHydrator($this->hydrationMode)->toIterable($stmt, $rsm, $this->hints); - } - - /** - * Executes the query. - * - * @psalm-param ArrayCollection|mixed[]|null $parameters - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - */ - public function execute( - ArrayCollection|array|null $parameters = null, - string|int|null $hydrationMode = null, - ): mixed { - if ($this->cacheable && $this->isCacheEnabled()) { - return $this->executeUsingQueryCache($parameters, $hydrationMode); - } - - return $this->executeIgnoreQueryCache($parameters, $hydrationMode); - } - - /** - * Execute query ignoring second level cache. - * - * @psalm-param ArrayCollection|mixed[]|null $parameters - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - */ - private function executeIgnoreQueryCache( - ArrayCollection|array|null $parameters = null, - string|int|null $hydrationMode = null, - ): mixed { - if ($hydrationMode !== null) { - $this->setHydrationMode($hydrationMode); - } - - if (! empty($parameters)) { - $this->setParameters($parameters); - } - - $setCacheEntry = static function ($data): void { - }; - - if ($this->hydrationCacheProfile !== null) { - [$cacheKey, $realCacheKey] = $this->getHydrationCacheId(); - - $cache = $this->getHydrationCache(); - $cacheItem = $cache->getItem($cacheKey); - $result = $cacheItem->isHit() ? $cacheItem->get() : []; - - if (isset($result[$realCacheKey])) { - return $result[$realCacheKey]; - } - - if (! $result) { - $result = []; - } - - $setCacheEntry = static function ($data) use ($cache, $result, $cacheItem, $realCacheKey): void { - $cache->save($cacheItem->set($result + [$realCacheKey => $data])); - }; - } - - $stmt = $this->_doExecute(); - - if (is_numeric($stmt)) { - $setCacheEntry($stmt); - - return $stmt; - } - - $rsm = $this->getResultSetMapping(); - if ($rsm === null) { - throw new LogicException('Uninitialized result set mapping.'); - } - - $data = $this->em->newHydrator($this->hydrationMode)->hydrateAll($stmt, $rsm, $this->hints); - - $setCacheEntry($data); - - return $data; - } - - private function getHydrationCache(): CacheItemPoolInterface - { - assert($this->hydrationCacheProfile !== null); - - $cache = $this->hydrationCacheProfile->getResultCache(); - assert($cache !== null); - - return $cache; - } - - /** - * Load from second level cache or executes the query and put into cache. - * - * @psalm-param ArrayCollection|mixed[]|null $parameters - * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - */ - private function executeUsingQueryCache( - ArrayCollection|array|null $parameters = null, - string|int|null $hydrationMode = null, - ): mixed { - $rsm = $this->getResultSetMapping(); - if ($rsm === null) { - throw new LogicException('Uninitialized result set mapping.'); - } - - $queryCache = $this->em->getCache()->getQueryCache($this->cacheRegion); - $queryKey = new QueryCacheKey( - $this->getHash(), - $this->lifetime, - $this->cacheMode ?: Cache::MODE_NORMAL, - $this->getTimestampKey(), - ); - - $result = $queryCache->get($queryKey, $rsm, $this->hints); - - if ($result !== null) { - if ($this->cacheLogger) { - $this->cacheLogger->queryCacheHit($queryCache->getRegion()->getName(), $queryKey); - } - - return $result; - } - - $result = $this->executeIgnoreQueryCache($parameters, $hydrationMode); - $cached = $queryCache->put($queryKey, $rsm, $result, $this->hints); - - if ($this->cacheLogger) { - $this->cacheLogger->queryCacheMiss($queryCache->getRegion()->getName(), $queryKey); - - if ($cached) { - $this->cacheLogger->queryCachePut($queryCache->getRegion()->getName(), $queryKey); - } - } - - return $result; - } - - private function getTimestampKey(): TimestampCacheKey|null - { - assert($this->resultSetMapping !== null); - $entityName = reset($this->resultSetMapping->aliasMap); - - if (empty($entityName)) { - return null; - } - - $metadata = $this->em->getClassMetadata($entityName); - - return new TimestampCacheKey($metadata->rootEntityName); - } - - /** - * Get the result cache id to use to store the result set cache entry. - * Will return the configured id if it exists otherwise a hash will be - * automatically generated for you. - * - * @return string[] ($key, $hash) - * @psalm-return array{string, string} ($key, $hash) - */ - protected function getHydrationCacheId(): array - { - $parameters = []; - $types = []; - - foreach ($this->getParameters() as $parameter) { - $parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue()); - $types[$parameter->getName()] = $parameter->getType(); - } - - $sql = $this->getSQL(); - assert(is_string($sql)); - $queryCacheProfile = $this->getHydrationCacheProfile(); - $hints = $this->getHints(); - $hints['hydrationMode'] = $this->getHydrationMode(); - - ksort($hints); - assert($queryCacheProfile !== null); - - return $queryCacheProfile->generateCacheKeys($sql, $parameters, $types, $hints); - } - - /** - * Set the result cache id to use to store the result set cache entry. - * If this is not explicitly set by the developer then a hash is automatically - * generated for you. - */ - public function setResultCacheId(string|null $id): static - { - if (! $this->queryCacheProfile) { - return $this->setResultCacheProfile(new QueryCacheProfile(0, $id)); - } - - $this->queryCacheProfile = $this->queryCacheProfile->setCacheKey($id); - - return $this; - } - - /** - * Executes the query and returns a the resulting Statement object. - * - * @return Result|int The executed database statement that holds - * the results, or an integer indicating how - * many rows were affected. - */ - abstract protected function _doExecute(): Result|int; - - /** - * Cleanup Query resource when clone is called. - */ - public function __clone() - { - $this->parameters = new ArrayCollection(); - - $this->hints = []; - $this->hints = $this->em->getConfiguration()->getDefaultQueryHints(); - } - - /** - * Generates a string of currently query to use for the cache second level cache. - */ - protected function getHash(): string - { - $query = $this->getSQL(); - assert(is_string($query)); - $hints = $this->getHints(); - $params = array_map(function (Parameter $parameter) { - $value = $parameter->getValue(); - - // Small optimization - // Does not invoke processParameterValue for scalar value - if (is_scalar($value)) { - return $value; - } - - return $this->processParameterValue($value); - }, $this->parameters->getValues()); - - ksort($hints); - - return sha1($query . '-' . serialize($params) . '-' . serialize($hints)); - } -} diff --git a/vendor/doctrine/orm/src/Cache.php b/vendor/doctrine/orm/src/Cache.php deleted file mode 100644 index 8020b27..0000000 --- a/vendor/doctrine/orm/src/Cache.php +++ /dev/null @@ -1,106 +0,0 @@ - $identifier The entity identifier. - * @param class-string $class The entity class name - */ - public function __construct( - public readonly string $class, - public readonly array $identifier, - ) { - } - - /** - * Creates a new AssociationCacheEntry - * - * This method allow Doctrine\Common\Cache\PhpFileCache compatibility - * - * @param array $values array containing property values - */ - public static function __set_state(array $values): self - { - return new self($values['class'], $values['identifier']); - } -} diff --git a/vendor/doctrine/orm/src/Cache/CacheConfiguration.php b/vendor/doctrine/orm/src/Cache/CacheConfiguration.php deleted file mode 100644 index 0f8dea7..0000000 --- a/vendor/doctrine/orm/src/Cache/CacheConfiguration.php +++ /dev/null @@ -1,60 +0,0 @@ -cacheFactory; - } - - public function setCacheFactory(CacheFactory $factory): void - { - $this->cacheFactory = $factory; - } - - public function getCacheLogger(): CacheLogger|null - { - return $this->cacheLogger; - } - - public function setCacheLogger(CacheLogger $logger): void - { - $this->cacheLogger = $logger; - } - - public function getRegionsConfiguration(): RegionsConfiguration - { - return $this->regionsConfig ??= new RegionsConfiguration(); - } - - public function setRegionsConfiguration(RegionsConfiguration $regionsConfig): void - { - $this->regionsConfig = $regionsConfig; - } - - public function getQueryValidator(): QueryCacheValidator - { - return $this->queryValidator ??= new TimestampQueryCacheValidator( - $this->cacheFactory->getTimestampRegion(), - ); - } - - public function setQueryValidator(QueryCacheValidator $validator): void - { - $this->queryValidator = $validator; - } -} diff --git a/vendor/doctrine/orm/src/Cache/CacheEntry.php b/vendor/doctrine/orm/src/Cache/CacheEntry.php deleted file mode 100644 index 6e12de1..0000000 --- a/vendor/doctrine/orm/src/Cache/CacheEntry.php +++ /dev/null @@ -1,16 +0,0 @@ -IMPORTANT NOTE: - * - * Fields of classes that implement CacheEntry are public for performance reason. - */ -interface CacheEntry -{ -} diff --git a/vendor/doctrine/orm/src/Cache/CacheException.php b/vendor/doctrine/orm/src/Cache/CacheException.php deleted file mode 100644 index b422095..0000000 --- a/vendor/doctrine/orm/src/Cache/CacheException.php +++ /dev/null @@ -1,26 +0,0 @@ - $cache The cache configuration. - */ - public function getRegion(array $cache): Region; - - /** - * Build timestamp cache region - */ - public function getTimestampRegion(): TimestampRegion; - - /** - * Build \Doctrine\ORM\Cache - */ - public function createCache(EntityManagerInterface $entityManager): Cache; -} diff --git a/vendor/doctrine/orm/src/Cache/CacheKey.php b/vendor/doctrine/orm/src/Cache/CacheKey.php deleted file mode 100644 index 970702c..0000000 --- a/vendor/doctrine/orm/src/Cache/CacheKey.php +++ /dev/null @@ -1,16 +0,0 @@ - $values array containing property values - */ - public static function __set_state(array $values): CollectionCacheEntry - { - return new self($values['identifiers']); - } -} diff --git a/vendor/doctrine/orm/src/Cache/CollectionCacheKey.php b/vendor/doctrine/orm/src/Cache/CollectionCacheKey.php deleted file mode 100644 index 51b408f..0000000 --- a/vendor/doctrine/orm/src/Cache/CollectionCacheKey.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ - public readonly array $ownerIdentifier; - - /** - * @param array $ownerIdentifier The identifier of the owning entity. - * @param class-string $entityClass The owner entity class - */ - public function __construct( - public readonly string $entityClass, - public readonly string $association, - array $ownerIdentifier, - ) { - ksort($ownerIdentifier); - - $this->ownerIdentifier = $ownerIdentifier; - - parent::__construct(str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association); - } -} diff --git a/vendor/doctrine/orm/src/Cache/CollectionHydrator.php b/vendor/doctrine/orm/src/Cache/CollectionHydrator.php deleted file mode 100644 index 16a6572..0000000 --- a/vendor/doctrine/orm/src/Cache/CollectionHydrator.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ - private array $queryCaches = []; - - private QueryCache|null $defaultQueryCache = null; - - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->uow = $em->getUnitOfWork(); - $this->cacheFactory = $em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheFactory(); - } - - public function getEntityCacheRegion(string $className): Region|null - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - - if (! ($persister instanceof CachedPersister)) { - return null; - } - - return $persister->getCacheRegion(); - } - - public function getCollectionCacheRegion(string $className, string $association): Region|null - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - - if (! ($persister instanceof CachedPersister)) { - return null; - } - - return $persister->getCacheRegion(); - } - - public function containsEntity(string $className, mixed $identifier): bool - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - - if (! ($persister instanceof CachedPersister)) { - return false; - } - - return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier)); - } - - public function evictEntity(string $className, mixed $identifier): void - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - - if (! ($persister instanceof CachedPersister)) { - return; - } - - $persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier)); - } - - public function evictEntityRegion(string $className): void - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - - if (! ($persister instanceof CachedPersister)) { - return; - } - - $persister->getCacheRegion()->evictAll(); - } - - public function evictEntityRegions(): void - { - $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); - - foreach ($metadatas as $metadata) { - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - - if (! ($persister instanceof CachedPersister)) { - continue; - } - - $persister->getCacheRegion()->evictAll(); - } - } - - public function containsCollection(string $className, string $association, mixed $ownerIdentifier): bool - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - - if (! ($persister instanceof CachedPersister)) { - return false; - } - - return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); - } - - public function evictCollection(string $className, string $association, mixed $ownerIdentifier): void - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - - if (! ($persister instanceof CachedPersister)) { - return; - } - - $persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); - } - - public function evictCollectionRegion(string $className, string $association): void - { - $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - - if (! ($persister instanceof CachedPersister)) { - return; - } - - $persister->getCacheRegion()->evictAll(); - } - - public function evictCollectionRegions(): void - { - $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); - - foreach ($metadatas as $metadata) { - foreach ($metadata->associationMappings as $association) { - if (! $association->isToMany()) { - continue; - } - - $persister = $this->uow->getCollectionPersister($association); - - if (! ($persister instanceof CachedPersister)) { - continue; - } - - $persister->getCacheRegion()->evictAll(); - } - } - } - - public function containsQuery(string $regionName): bool - { - return isset($this->queryCaches[$regionName]); - } - - public function evictQueryRegion(string|null $regionName = null): void - { - if ($regionName === null && $this->defaultQueryCache !== null) { - $this->defaultQueryCache->clear(); - - return; - } - - if (isset($this->queryCaches[$regionName])) { - $this->queryCaches[$regionName]->clear(); - } - } - - public function evictQueryRegions(): void - { - $this->getQueryCache()->clear(); - - foreach ($this->queryCaches as $queryCache) { - $queryCache->clear(); - } - } - - public function getQueryCache(string|null $regionName = null): QueryCache - { - if ($regionName === null) { - return $this->defaultQueryCache ??= $this->cacheFactory->buildQueryCache($this->em); - } - - return $this->queryCaches[$regionName] ??= $this->cacheFactory->buildQueryCache($this->em, $regionName); - } - - private function buildEntityCacheKey(ClassMetadata $metadata, mixed $identifier): EntityCacheKey - { - if (! is_array($identifier)) { - $identifier = $this->toIdentifierArray($metadata, $identifier); - } - - return new EntityCacheKey($metadata->rootEntityName, $identifier); - } - - private function buildCollectionCacheKey( - ClassMetadata $metadata, - string $association, - mixed $ownerIdentifier, - ): CollectionCacheKey { - if (! is_array($ownerIdentifier)) { - $ownerIdentifier = $this->toIdentifierArray($metadata, $ownerIdentifier); - } - - return new CollectionCacheKey($metadata->rootEntityName, $association, $ownerIdentifier); - } - - /** @return array */ - private function toIdentifierArray(ClassMetadata $metadata, mixed $identifier): array - { - if (is_object($identifier)) { - $class = DefaultProxyClassNameResolver::getClass($identifier); - if ($this->em->getMetadataFactory()->hasMetadataFor($class)) { - $identifier = $this->uow->getSingleIdentifierValue($identifier) - ?? throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class); - } - } - - return [$metadata->identifier[0] => $identifier]; - } -} diff --git a/vendor/doctrine/orm/src/Cache/DefaultCacheFactory.php b/vendor/doctrine/orm/src/Cache/DefaultCacheFactory.php deleted file mode 100644 index 84ea490..0000000 --- a/vendor/doctrine/orm/src/Cache/DefaultCacheFactory.php +++ /dev/null @@ -1,189 +0,0 @@ -fileLockRegionDirectory = $fileLockRegionDirectory; - } - - public function getFileLockRegionDirectory(): string|null - { - return $this->fileLockRegionDirectory; - } - - public function setRegion(Region $region): void - { - $this->regions[$region->getName()] = $region; - } - - public function setTimestampRegion(TimestampRegion $region): void - { - $this->timestampRegion = $region; - } - - public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata): CachedEntityPersister - { - assert($metadata->cache !== null); - $region = $this->getRegion($metadata->cache); - $usage = $metadata->cache['usage']; - - if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) { - return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata); - } - - if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) { - return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata); - } - - if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) { - if (! $region instanceof ConcurrentRegion) { - throw new InvalidArgumentException(sprintf('Unable to use access strategy type of [%s] without a ConcurrentRegion', $usage)); - } - - return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata); - } - - throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage)); - } - - public function buildCachedCollectionPersister( - EntityManagerInterface $em, - CollectionPersister $persister, - AssociationMapping $mapping, - ): CachedCollectionPersister { - assert(isset($mapping->cache)); - $usage = $mapping->cache['usage']; - $region = $this->getRegion($mapping->cache); - - if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) { - return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping); - } - - if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) { - return new NonStrictReadWriteCachedCollectionPersister($persister, $region, $em, $mapping); - } - - if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) { - if (! $region instanceof ConcurrentRegion) { - throw new InvalidArgumentException(sprintf('Unable to use access strategy type of [%s] without a ConcurrentRegion', $usage)); - } - - return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping); - } - - throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage)); - } - - public function buildQueryCache(EntityManagerInterface $em, string|null $regionName = null): QueryCache - { - return new DefaultQueryCache( - $em, - $this->getRegion( - [ - 'region' => $regionName ?: Cache::DEFAULT_QUERY_REGION_NAME, - 'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE, - ], - ), - ); - } - - public function buildCollectionHydrator(EntityManagerInterface $em, AssociationMapping $mapping): CollectionHydrator - { - return new DefaultCollectionHydrator($em); - } - - public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata): EntityHydrator - { - return new DefaultEntityHydrator($em); - } - - /** - * {@inheritDoc} - */ - public function getRegion(array $cache): Region - { - if (isset($this->regions[$cache['region']])) { - return $this->regions[$cache['region']]; - } - - $name = $cache['region']; - $lifetime = $this->regionsConfig->getLifetime($cache['region']); - $region = new DefaultRegion($name, $this->cacheItemPool, $lifetime); - - if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) { - if ( - $this->fileLockRegionDirectory === '' || - $this->fileLockRegionDirectory === null - ) { - throw new LogicException( - 'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' . - 'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). ', - ); - } - - $directory = $this->fileLockRegionDirectory . DIRECTORY_SEPARATOR . $cache['region']; - $region = new FileLockRegion($region, $directory, (string) $this->regionsConfig->getLockLifetime($cache['region'])); - } - - return $this->regions[$cache['region']] = $region; - } - - public function getTimestampRegion(): TimestampRegion - { - if ($this->timestampRegion === null) { - $name = Cache::DEFAULT_TIMESTAMP_REGION_NAME; - $lifetime = $this->regionsConfig->getLifetime($name); - - $this->timestampRegion = new UpdateTimestampCache($name, $this->cacheItemPool, $lifetime); - } - - return $this->timestampRegion; - } - - public function createCache(EntityManagerInterface $entityManager): Cache - { - return new DefaultCache($entityManager); - } -} diff --git a/vendor/doctrine/orm/src/Cache/DefaultCollectionHydrator.php b/vendor/doctrine/orm/src/Cache/DefaultCollectionHydrator.php deleted file mode 100644 index 249d48f..0000000 --- a/vendor/doctrine/orm/src/Cache/DefaultCollectionHydrator.php +++ /dev/null @@ -1,75 +0,0 @@ - */ - private static array $hints = [Query::HINT_CACHE_ENABLED => true]; - - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->uow = $em->getUnitOfWork(); - } - - public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, array|Collection $collection): CollectionCacheEntry - { - $data = []; - - foreach ($collection as $index => $entity) { - $data[$index] = new EntityCacheKey($metadata->rootEntityName, $this->uow->getEntityIdentifier($entity)); - } - - return new CollectionCacheEntry($data); - } - - public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection): array|null - { - $assoc = $metadata->associationMappings[$key->association]; - $targetPersister = $this->uow->getEntityPersister($assoc->targetEntity); - assert($targetPersister instanceof CachedPersister); - $targetRegion = $targetPersister->getCacheRegion(); - $list = []; - - /** @var EntityCacheEntry[]|null $entityEntries */ - $entityEntries = $targetRegion->getMultiple($entry); - - if ($entityEntries === null) { - return null; - } - - foreach ($entityEntries as $index => $entityEntry) { - $entity = $this->uow->createEntity( - $entityEntry->class, - $entityEntry->resolveAssociationEntries($this->em), - self::$hints, - ); - - $collection->hydrateSet($index, $entity); - - $list[$index] = $entity; - } - - $this->uow->hydrationComplete(); - - return $list; - } -} diff --git a/vendor/doctrine/orm/src/Cache/DefaultEntityHydrator.php b/vendor/doctrine/orm/src/Cache/DefaultEntityHydrator.php deleted file mode 100644 index 6bd1524..0000000 --- a/vendor/doctrine/orm/src/Cache/DefaultEntityHydrator.php +++ /dev/null @@ -1,176 +0,0 @@ - */ - private static array $hints = [Query::HINT_CACHE_ENABLED => true]; - - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->uow = $em->getUnitOfWork(); - $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); - } - - public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, object $entity): EntityCacheEntry - { - $data = $this->uow->getOriginalEntityData($entity); - $data = [...$data, ...$metadata->getIdentifierValues($entity)]; // why update has no identifier values ? - - if ($metadata->requiresFetchAfterChange) { - if ($metadata->isVersioned) { - assert($metadata->versionField !== null); - $data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField); - } - - foreach ($metadata->fieldMappings as $name => $fieldMapping) { - if (isset($fieldMapping->generated)) { - $data[$name] = $metadata->getFieldValue($entity, $name); - } - } - } - - foreach ($metadata->associationMappings as $name => $assoc) { - if (! isset($data[$name])) { - continue; - } - - if (! $assoc->isToOne()) { - unset($data[$name]); - - continue; - } - - if (! isset($assoc->cache)) { - $targetClassMetadata = $this->em->getClassMetadata($assoc->targetEntity); - $owningAssociation = $this->em->getMetadataFactory()->getOwningSide($assoc); - $associationIds = $this->identifierFlattener->flattenIdentifier( - $targetClassMetadata, - $targetClassMetadata->getIdentifierValues($data[$name]), - ); - - unset($data[$name]); - - foreach ($associationIds as $fieldName => $fieldValue) { - if (isset($targetClassMetadata->fieldMappings[$fieldName])) { - assert($owningAssociation->isToOneOwningSide()); - $fieldMapping = $targetClassMetadata->fieldMappings[$fieldName]; - - $data[$owningAssociation->targetToSourceKeyColumns[$fieldMapping->columnName]] = $fieldValue; - - continue; - } - - $targetAssoc = $targetClassMetadata->associationMappings[$fieldName]; - - assert($assoc->isToOneOwningSide()); - foreach ($assoc->targetToSourceKeyColumns as $referencedColumn => $localColumn) { - if (isset($targetAssoc->sourceToTargetKeyColumns[$referencedColumn])) { - $data[$localColumn] = $fieldValue; - } - } - } - - continue; - } - - if (! isset($assoc->id)) { - $targetClass = DefaultProxyClassNameResolver::getClass($data[$name]); - $targetId = $this->uow->getEntityIdentifier($data[$name]); - $data[$name] = new AssociationCacheEntry($targetClass, $targetId); - - continue; - } - - // handle association identifier - $targetId = is_object($data[$name]) && $this->uow->isInIdentityMap($data[$name]) - ? $this->uow->getEntityIdentifier($data[$name]) - : $data[$name]; - - // @TODO - fix it ! - // handle UnitOfWork#createEntity hash generation - if (! is_array($targetId)) { - assert($assoc->isToOneOwningSide()); - $data[reset($assoc->joinColumnFieldNames)] = $targetId; - - $targetEntity = $this->em->getClassMetadata($assoc->targetEntity); - $targetId = [$targetEntity->identifier[0] => $targetId]; - } - - $data[$name] = new AssociationCacheEntry($assoc->targetEntity, $targetId); - } - - return new EntityCacheEntry($metadata->name, $data); - } - - public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, object|null $entity = null): object|null - { - $data = $entry->data; - $hints = self::$hints; - - if ($entity !== null) { - $hints[Query::HINT_REFRESH] = true; - $hints[Query::HINT_REFRESH_ENTITY] = $entity; - } - - foreach ($metadata->associationMappings as $name => $assoc) { - if (! isset($assoc->cache) || ! isset($data[$name])) { - continue; - } - - $assocClass = $data[$name]->class; - $assocId = $data[$name]->identifier; - $isEagerLoad = ($assoc->fetch === ClassMetadata::FETCH_EAGER || ($assoc->isOneToOne() && ! $assoc->isOwningSide())); - - if (! $isEagerLoad) { - $data[$name] = $this->em->getReference($assocClass, $assocId); - - continue; - } - - $assocMetadata = $this->em->getClassMetadata($assoc->targetEntity); - $assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocId); - $assocPersister = $this->uow->getEntityPersister($assoc->targetEntity); - $assocRegion = $assocPersister->getCacheRegion(); - $assocEntry = $assocRegion->get($assocKey); - - if ($assocEntry === null) { - return null; - } - - $data[$name] = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), $hints); - } - - if ($entity !== null) { - $this->uow->registerManaged($entity, $key->identifier, $data); - } - - $result = $this->uow->createEntity($entry->class, $data, $hints); - - $this->uow->hydrationComplete(); - - return $result; - } -} diff --git a/vendor/doctrine/orm/src/Cache/DefaultQueryCache.php b/vendor/doctrine/orm/src/Cache/DefaultQueryCache.php deleted file mode 100644 index f3bb8ac..0000000 --- a/vendor/doctrine/orm/src/Cache/DefaultQueryCache.php +++ /dev/null @@ -1,414 +0,0 @@ - */ - private static array $hints = [Query::HINT_CACHE_ENABLED => true]; - - public function __construct( - private readonly EntityManagerInterface $em, - private readonly Region $region, - ) { - $cacheConfig = $em->getConfiguration()->getSecondLevelCacheConfiguration(); - - $this->uow = $em->getUnitOfWork(); - $this->cacheLogger = $cacheConfig->getCacheLogger(); - $this->validator = $cacheConfig->getQueryValidator(); - } - - /** - * {@inheritDoc} - */ - public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = []): array|null - { - if (! ($key->cacheMode & Cache::MODE_GET)) { - return null; - } - - $cacheEntry = $this->region->get($key); - - if (! $cacheEntry instanceof QueryCacheEntry) { - return null; - } - - if (! $this->validator->isValid($key, $cacheEntry)) { - $this->region->evict($key); - - return null; - } - - $result = []; - $entityName = reset($rsm->aliasMap); - $hasRelation = ! empty($rsm->relationMap); - $persister = $this->uow->getEntityPersister($entityName); - assert($persister instanceof CachedEntityPersister); - - $region = $persister->getCacheRegion(); - $regionName = $region->getName(); - - $cm = $this->em->getClassMetadata($entityName); - - $generateKeys = static fn (array $entry): EntityCacheKey => new EntityCacheKey($cm->rootEntityName, $entry['identifier']); - - $cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $cacheEntry->result)); - $entries = $region->getMultiple($cacheKeys) ?? []; - - // @TODO - move to cache hydration component - foreach ($cacheEntry->result as $index => $entry) { - $entityEntry = $entries[$index] ?? null; - - if (! $entityEntry instanceof EntityCacheEntry) { - $this->cacheLogger?->entityCacheMiss($regionName, $cacheKeys->identifiers[$index]); - - return null; - } - - $this->cacheLogger?->entityCacheHit($regionName, $cacheKeys->identifiers[$index]); - - if (! $hasRelation) { - $result[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints); - - continue; - } - - $data = $entityEntry->data; - - foreach ($entry['associations'] as $name => $assoc) { - $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); - assert($assocPersister instanceof CachedEntityPersister); - - $assocRegion = $assocPersister->getCacheRegion(); - $assocMetadata = $this->em->getClassMetadata($assoc['targetEntity']); - - if ($assoc['type'] & ClassMetadata::TO_ONE) { - $assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assoc['identifier']); - $assocEntry = $assocRegion->get($assocKey); - - if ($assocEntry === null) { - $this->cacheLogger?->entityCacheMiss($assocRegion->getName(), $assocKey); - - $this->uow->hydrationComplete(); - - return null; - } - - $data[$name] = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), self::$hints); - - $this->cacheLogger?->entityCacheHit($assocRegion->getName(), $assocKey); - - continue; - } - - if (! isset($assoc['list']) || empty($assoc['list'])) { - continue; - } - - $generateKeys = static fn (array $id): EntityCacheKey => new EntityCacheKey($assocMetadata->rootEntityName, $id); - - $collection = new PersistentCollection($this->em, $assocMetadata, new ArrayCollection()); - $assocKeys = new CollectionCacheEntry(array_map($generateKeys, $assoc['list'])); - $assocEntries = $assocRegion->getMultiple($assocKeys); - - foreach ($assoc['list'] as $assocIndex => $assocId) { - $assocEntry = is_array($assocEntries) ? ($assocEntries[$assocIndex] ?? null) : null; - - if ($assocEntry === null) { - $this->cacheLogger?->entityCacheMiss($assocRegion->getName(), $assocKeys->identifiers[$assocIndex]); - - $this->uow->hydrationComplete(); - - return null; - } - - $element = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), self::$hints); - - $collection->hydrateSet($assocIndex, $element); - - $this->cacheLogger?->entityCacheHit($assocRegion->getName(), $assocKeys->identifiers[$assocIndex]); - } - - $data[$name] = $collection; - - $collection->setInitialized(true); - } - - foreach ($data as $fieldName => $unCachedAssociationData) { - // In some scenarios, such as EAGER+ASSOCIATION+ID+CACHE, the - // cache key information in `$cacheEntry` will not contain details - // for fields that are associations. - // - // This means that `$data` keys for some associations that may - // actually not be cached will not be converted to actual association - // data, yet they contain L2 cache AssociationCacheEntry objects. - // - // We need to unwrap those associations into proxy references, - // since we don't have actual data for them except for identifiers. - if ($unCachedAssociationData instanceof AssociationCacheEntry) { - $data[$fieldName] = $this->em->getReference( - $unCachedAssociationData->class, - $unCachedAssociationData->identifier, - ); - } - } - - $result[$index] = $this->uow->createEntity($entityEntry->class, $data, self::$hints); - } - - $this->uow->hydrationComplete(); - - return $result; - } - - /** - * {@inheritDoc} - */ - public function put(QueryCacheKey $key, ResultSetMapping $rsm, mixed $result, array $hints = []): bool - { - if ($rsm->scalarMappings) { - throw FeatureNotImplemented::scalarResults(); - } - - if (count($rsm->entityMappings) > 1) { - throw FeatureNotImplemented::multipleRootEntities(); - } - - if (! $rsm->isSelect) { - throw FeatureNotImplemented::nonSelectStatements(); - } - - if (! ($key->cacheMode & Cache::MODE_PUT)) { - return false; - } - - $data = []; - $entityName = reset($rsm->aliasMap); - $rootAlias = key($rsm->aliasMap); - $persister = $this->uow->getEntityPersister($entityName); - - if (! $persister instanceof CachedEntityPersister) { - throw NonCacheableEntity::fromEntity($entityName); - } - - $region = $persister->getCacheRegion(); - - $cm = $this->em->getClassMetadata($entityName); - assert($cm instanceof ClassMetadata); - - foreach ($result as $index => $entity) { - $identifier = $this->uow->getEntityIdentifier($entity); - $entityKey = new EntityCacheKey($cm->rootEntityName, $identifier); - - if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) { - // Cancel put result if entity put fail - if (! $persister->storeEntityCache($entity, $entityKey)) { - return false; - } - } - - $data[$index]['identifier'] = $identifier; - $data[$index]['associations'] = []; - - // @TODO - move to cache hydration components - foreach ($rsm->relationMap as $alias => $name) { - $parentAlias = $rsm->parentAliasMap[$alias]; - $parentClass = $rsm->aliasMap[$parentAlias]; - $metadata = $this->em->getClassMetadata($parentClass); - $assoc = $metadata->associationMappings[$name]; - $assocValue = $this->getAssociationValue($rsm, $alias, $entity); - - if ($assocValue === null) { - continue; - } - - // root entity association - if ($rootAlias === $parentAlias) { - // Cancel put result if association put fail - $assocInfo = $this->storeAssociationCache($key, $assoc, $assocValue); - if ($assocInfo === null) { - return false; - } - - $data[$index]['associations'][$name] = $assocInfo; - - continue; - } - - // store single nested association - if (! is_array($assocValue)) { - // Cancel put result if association put fail - if ($this->storeAssociationCache($key, $assoc, $assocValue) === null) { - return false; - } - - continue; - } - - // store array of nested association - foreach ($assocValue as $aVal) { - // Cancel put result if association put fail - if ($this->storeAssociationCache($key, $assoc, $aVal) === null) { - return false; - } - } - } - } - - return $this->region->put($key, new QueryCacheEntry($data)); - } - - /** - * @return mixed[]|null - * @psalm-return array{targetEntity: class-string, type: mixed, list?: array[], identifier?: array}|null - */ - private function storeAssociationCache(QueryCacheKey $key, AssociationMapping $assoc, mixed $assocValue): array|null - { - $assocPersister = $this->uow->getEntityPersister($assoc->targetEntity); - $assocMetadata = $assocPersister->getClassMetadata(); - $assocRegion = $assocPersister->getCacheRegion(); - - // Handle *-to-one associations - if ($assoc->isToOne()) { - $assocIdentifier = $this->uow->getEntityIdentifier($assocValue); - $entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier); - - if (! $this->uow->isUninitializedObject($assocValue) && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) { - // Entity put fail - if (! $assocPersister->storeEntityCache($assocValue, $entityKey)) { - return null; - } - } - - return [ - 'targetEntity' => $assocMetadata->rootEntityName, - 'identifier' => $assocIdentifier, - 'type' => $assoc->type(), - ]; - } - - // Handle *-to-many associations - $list = []; - - foreach ($assocValue as $assocItemIndex => $assocItem) { - $assocIdentifier = $this->uow->getEntityIdentifier($assocItem); - $entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier); - - if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) { - // Entity put fail - if (! $assocPersister->storeEntityCache($assocItem, $entityKey)) { - return null; - } - } - - $list[$assocItemIndex] = $assocIdentifier; - } - - return [ - 'targetEntity' => $assocMetadata->rootEntityName, - 'type' => $assoc->type(), - 'list' => $list, - ]; - } - - /** @psalm-return list|object|null */ - private function getAssociationValue( - ResultSetMapping $rsm, - string $assocAlias, - object $entity, - ): array|object|null { - $path = []; - $alias = $assocAlias; - - while (isset($rsm->parentAliasMap[$alias])) { - $parent = $rsm->parentAliasMap[$alias]; - $field = $rsm->relationMap[$alias]; - $class = $rsm->aliasMap[$parent]; - - array_unshift($path, [ - 'field' => $field, - 'class' => $class, - ]); - - $alias = $parent; - } - - return $this->getAssociationPathValue($entity, $path); - } - - /** - * @psalm-param array $path - * - * @psalm-return list|object|null - */ - private function getAssociationPathValue(mixed $value, array $path): array|object|null - { - $mapping = array_shift($path); - $metadata = $this->em->getClassMetadata($mapping['class']); - $assoc = $metadata->associationMappings[$mapping['field']]; - $value = $metadata->getFieldValue($value, $mapping['field']); - - if ($value === null) { - return null; - } - - if ($path === []) { - return $value; - } - - // Handle *-to-one associations - if ($assoc->isToOne()) { - return $this->getAssociationPathValue($value, $path); - } - - $values = []; - - foreach ($value as $item) { - $values[] = $this->getAssociationPathValue($item, $path); - } - - return $values; - } - - public function clear(): bool - { - return $this->region->evictAll(); - } - - public function getRegion(): Region - { - return $this->region; - } -} diff --git a/vendor/doctrine/orm/src/Cache/EntityCacheEntry.php b/vendor/doctrine/orm/src/Cache/EntityCacheEntry.php deleted file mode 100644 index 69bc813..0000000 --- a/vendor/doctrine/orm/src/Cache/EntityCacheEntry.php +++ /dev/null @@ -1,50 +0,0 @@ - $data The entity map data - * @psalm-param class-string $class The entity class name - */ - public function __construct( - public readonly string $class, - public readonly array $data, - ) { - } - - /** - * Creates a new EntityCacheEntry - * - * This method allows Doctrine\Common\Cache\PhpFileCache compatibility - * - * @param array $values array containing property values - */ - public static function __set_state(array $values): self - { - return new self($values['class'], $values['data']); - } - - /** - * Retrieves the entity data resolving cache entries - * - * @return array - */ - public function resolveAssociationEntries(EntityManagerInterface $em): array - { - return array_map(static function ($value) use ($em) { - if (! ($value instanceof AssociationCacheEntry)) { - return $value; - } - - return $em->getReference($value->class, $value->identifier); - }, $this->data); - } -} diff --git a/vendor/doctrine/orm/src/Cache/EntityCacheKey.php b/vendor/doctrine/orm/src/Cache/EntityCacheKey.php deleted file mode 100644 index 095ddaa..0000000 --- a/vendor/doctrine/orm/src/Cache/EntityCacheKey.php +++ /dev/null @@ -1,38 +0,0 @@ - - */ - public readonly array $identifier; - - /** - * @param class-string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class. - * @param array $identifier The entity identifier - */ - public function __construct( - public readonly string $entityClass, - array $identifier, - ) { - ksort($identifier); - - $this->identifier = $identifier; - - parent::__construct(str_replace('\\', '.', strtolower($entityClass) . '_' . implode(' ', $identifier))); - } -} diff --git a/vendor/doctrine/orm/src/Cache/EntityHydrator.php b/vendor/doctrine/orm/src/Cache/EntityHydrator.php deleted file mode 100644 index 13cd21f..0000000 --- a/vendor/doctrine/orm/src/Cache/EntityHydrator.php +++ /dev/null @@ -1,28 +0,0 @@ -time = $time ?? time(); - } - - public static function createLockRead(): Lock - { - return new self(uniqid((string) time(), true)); - } -} diff --git a/vendor/doctrine/orm/src/Cache/LockException.php b/vendor/doctrine/orm/src/Cache/LockException.php deleted file mode 100644 index bb2d4ec..0000000 --- a/vendor/doctrine/orm/src/Cache/LockException.php +++ /dev/null @@ -1,14 +0,0 @@ - */ - private array $loggers = []; - - public function setLogger(string $name, CacheLogger $logger): void - { - $this->loggers[$name] = $logger; - } - - public function getLogger(string $name): CacheLogger|null - { - return $this->loggers[$name] ?? null; - } - - /** @return array */ - public function getLoggers(): array - { - return $this->loggers; - } - - public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->collectionCacheHit($regionName, $key); - } - } - - public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->collectionCacheMiss($regionName, $key); - } - } - - public function collectionCachePut(string $regionName, CollectionCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->collectionCachePut($regionName, $key); - } - } - - public function entityCacheHit(string $regionName, EntityCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->entityCacheHit($regionName, $key); - } - } - - public function entityCacheMiss(string $regionName, EntityCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->entityCacheMiss($regionName, $key); - } - } - - public function entityCachePut(string $regionName, EntityCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->entityCachePut($regionName, $key); - } - } - - public function queryCacheHit(string $regionName, QueryCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->queryCacheHit($regionName, $key); - } - } - - public function queryCacheMiss(string $regionName, QueryCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->queryCacheMiss($regionName, $key); - } - } - - public function queryCachePut(string $regionName, QueryCacheKey $key): void - { - foreach ($this->loggers as $logger) { - $logger->queryCachePut($regionName, $key); - } - } -} diff --git a/vendor/doctrine/orm/src/Cache/Logging/StatisticsCacheLogger.php b/vendor/doctrine/orm/src/Cache/Logging/StatisticsCacheLogger.php deleted file mode 100644 index 092104e..0000000 --- a/vendor/doctrine/orm/src/Cache/Logging/StatisticsCacheLogger.php +++ /dev/null @@ -1,174 +0,0 @@ - */ - private array $cacheMissCountMap = []; - - /** @var array */ - private array $cacheHitCountMap = []; - - /** @var array */ - private array $cachePutCountMap = []; - - public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void - { - $this->cacheMissCountMap[$regionName] - = ($this->cacheMissCountMap[$regionName] ?? 0) + 1; - } - - public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void - { - $this->cacheHitCountMap[$regionName] - = ($this->cacheHitCountMap[$regionName] ?? 0) + 1; - } - - public function collectionCachePut(string $regionName, CollectionCacheKey $key): void - { - $this->cachePutCountMap[$regionName] - = ($this->cachePutCountMap[$regionName] ?? 0) + 1; - } - - public function entityCacheMiss(string $regionName, EntityCacheKey $key): void - { - $this->cacheMissCountMap[$regionName] - = ($this->cacheMissCountMap[$regionName] ?? 0) + 1; - } - - public function entityCacheHit(string $regionName, EntityCacheKey $key): void - { - $this->cacheHitCountMap[$regionName] - = ($this->cacheHitCountMap[$regionName] ?? 0) + 1; - } - - public function entityCachePut(string $regionName, EntityCacheKey $key): void - { - $this->cachePutCountMap[$regionName] - = ($this->cachePutCountMap[$regionName] ?? 0) + 1; - } - - public function queryCacheHit(string $regionName, QueryCacheKey $key): void - { - $this->cacheHitCountMap[$regionName] - = ($this->cacheHitCountMap[$regionName] ?? 0) + 1; - } - - public function queryCacheMiss(string $regionName, QueryCacheKey $key): void - { - $this->cacheMissCountMap[$regionName] - = ($this->cacheMissCountMap[$regionName] ?? 0) + 1; - } - - public function queryCachePut(string $regionName, QueryCacheKey $key): void - { - $this->cachePutCountMap[$regionName] - = ($this->cachePutCountMap[$regionName] ?? 0) + 1; - } - - /** - * Get the number of entries successfully retrieved from cache. - * - * @param string $regionName The name of the cache region. - */ - public function getRegionHitCount(string $regionName): int - { - return $this->cacheHitCountMap[$regionName] ?? 0; - } - - /** - * Get the number of cached entries *not* found in cache. - * - * @param string $regionName The name of the cache region. - */ - public function getRegionMissCount(string $regionName): int - { - return $this->cacheMissCountMap[$regionName] ?? 0; - } - - /** - * Get the number of cacheable entries put in cache. - * - * @param string $regionName The name of the cache region. - */ - public function getRegionPutCount(string $regionName): int - { - return $this->cachePutCountMap[$regionName] ?? 0; - } - - /** @return array */ - public function getRegionsMiss(): array - { - return $this->cacheMissCountMap; - } - - /** @return array */ - public function getRegionsHit(): array - { - return $this->cacheHitCountMap; - } - - /** @return array */ - public function getRegionsPut(): array - { - return $this->cachePutCountMap; - } - - /** - * Clear region statistics - * - * @param string $regionName The name of the cache region. - */ - public function clearRegionStats(string $regionName): void - { - $this->cachePutCountMap[$regionName] = 0; - $this->cacheHitCountMap[$regionName] = 0; - $this->cacheMissCountMap[$regionName] = 0; - } - - /** - * Clear all statistics - */ - public function clearStats(): void - { - $this->cachePutCountMap = []; - $this->cacheHitCountMap = []; - $this->cacheMissCountMap = []; - } - - /** - * Get the total number of put in cache. - */ - public function getPutCount(): int - { - return array_sum($this->cachePutCountMap); - } - - /** - * Get the total number of entries successfully retrieved from cache. - */ - public function getHitCount(): int - { - return array_sum($this->cacheHitCountMap); - } - - /** - * Get the total number of cached entries *not* found in cache. - */ - public function getMissCount(): int - { - return array_sum($this->cacheMissCountMap); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php b/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php deleted file mode 100644 index 223692c..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php +++ /dev/null @@ -1,25 +0,0 @@ -getConfiguration(); - $cacheConfig = $configuration->getSecondLevelCacheConfiguration(); - $cacheFactory = $cacheConfig->getCacheFactory(); - - $this->regionName = $region->getName(); - $this->uow = $em->getUnitOfWork(); - $this->metadataFactory = $em->getMetadataFactory(); - $this->cacheLogger = $cacheConfig->getCacheLogger(); - $this->hydrator = $cacheFactory->buildCollectionHydrator($em, $association); - $this->sourceEntity = $em->getClassMetadata($association->sourceEntity); - $this->targetEntity = $em->getClassMetadata($association->targetEntity); - } - - public function getCacheRegion(): Region - { - return $this->region; - } - - public function getSourceEntityMetadata(): ClassMetadata - { - return $this->sourceEntity; - } - - public function getTargetEntityMetadata(): ClassMetadata - { - return $this->targetEntity; - } - - public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key): array|null - { - $cache = $this->region->get($key); - - if ($cache === null) { - return null; - } - - return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection); - } - - public function storeCollectionCache(CollectionCacheKey $key, Collection|array $elements): void - { - $associationMapping = $this->sourceEntity->associationMappings[$key->association]; - $targetPersister = $this->uow->getEntityPersister($this->targetEntity->rootEntityName); - assert($targetPersister instanceof CachedEntityPersister); - $targetRegion = $targetPersister->getCacheRegion(); - $targetHydrator = $targetPersister->getEntityHydrator(); - - // Only preserve ordering if association configured it - if (! $associationMapping->isIndexed()) { - // Elements may be an array or a Collection - $elements = array_values($elements instanceof Collection ? $elements->getValues() : $elements); - } - - $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); - - foreach ($entry->identifiers as $index => $entityKey) { - if ($targetRegion->contains($entityKey)) { - continue; - } - - $class = $this->targetEntity; - $className = DefaultProxyClassNameResolver::getClass($elements[$index]); - - if ($className !== $this->targetEntity->name) { - $class = $this->metadataFactory->getMetadataFor($className); - } - - $entity = $elements[$index]; - $entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity); - - $targetRegion->put($entityKey, $entityEntry); - } - - if ($this->region->put($key, $entry)) { - $this->cacheLogger?->collectionCachePut($this->regionName, $key); - } - } - - public function contains(PersistentCollection $collection, object $element): bool - { - return $this->persister->contains($collection, $element); - } - - public function containsKey(PersistentCollection $collection, mixed $key): bool - { - return $this->persister->containsKey($collection, $key); - } - - public function count(PersistentCollection $collection): int - { - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); - $entry = $this->region->get($key); - - if ($entry !== null) { - return count($entry->identifiers); - } - - return $this->persister->count($collection); - } - - public function get(PersistentCollection $collection, mixed $index): mixed - { - return $this->persister->get($collection, $index); - } - - /** - * {@inheritDoc} - */ - public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array - { - return $this->persister->slice($collection, $offset, $length); - } - - /** - * {@inheritDoc} - */ - public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array - { - return $this->persister->loadCriteria($collection, $criteria); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php deleted file mode 100644 index 6b10c80..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php +++ /dev/null @@ -1,36 +0,0 @@ -queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $item) { - $this->storeCollectionCache($item['key'], $item['list']); - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $key) { - $this->region->evict($key); - } - } - - $this->queuedCache = []; - } - - public function afterTransactionRolledBack(): void - { - $this->queuedCache = []; - } - - public function delete(PersistentCollection $collection): void - { - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); - - $this->persister->delete($collection); - - $this->queuedCache['delete'][spl_object_id($collection)] = $key; - } - - public function update(PersistentCollection $collection): void - { - $isInitialized = $collection->isInitialized(); - $isDirty = $collection->isDirty(); - - if (! $isInitialized && ! $isDirty) { - return; - } - - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); - - // Invalidate non initialized collections OR ordered collection - if ($isDirty && ! $isInitialized || $this->association->isOrdered()) { - $this->persister->update($collection); - - $this->queuedCache['delete'][spl_object_id($collection)] = $key; - - return; - } - - $this->persister->update($collection); - - $this->queuedCache['update'][spl_object_id($collection)] = [ - 'key' => $key, - 'list' => $collection, - ]; - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php deleted file mode 100644 index 96e0a4b..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php +++ /dev/null @@ -1,24 +0,0 @@ -isDirty() && $collection->getSnapshot()) { - throw CannotUpdateReadOnlyCollection::fromEntityAndField( - DefaultProxyClassNameResolver::getClass($collection->getOwner()), - $this->association->fieldName, - ); - } - - parent::update($collection); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php deleted file mode 100644 index 347a065..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php +++ /dev/null @@ -1,103 +0,0 @@ -queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $item) { - $this->region->evict($item['key']); - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $item) { - $this->region->evict($item['key']); - } - } - - $this->queuedCache = []; - } - - public function afterTransactionRolledBack(): void - { - if (isset($this->queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $item) { - $this->region->evict($item['key']); - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $item) { - $this->region->evict($item['key']); - } - } - - $this->queuedCache = []; - } - - public function delete(PersistentCollection $collection): void - { - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); - $lock = $this->region->lock($key); - - $this->persister->delete($collection); - - if ($lock === null) { - return; - } - - $this->queuedCache['delete'][spl_object_id($collection)] = [ - 'key' => $key, - 'lock' => $lock, - ]; - } - - public function update(PersistentCollection $collection): void - { - $isInitialized = $collection->isInitialized(); - $isDirty = $collection->isDirty(); - - if (! $isInitialized && ! $isDirty) { - return; - } - - $this->persister->update($collection); - - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); - $lock = $this->region->lock($key); - - if ($lock === null) { - return; - } - - $this->queuedCache['update'][spl_object_id($collection)] = [ - 'key' => $key, - 'lock' => $lock, - ]; - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php deleted file mode 100644 index 9f371d8..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php +++ /dev/null @@ -1,557 +0,0 @@ -|null - */ - protected array|null $joinedAssociations = null; - - public function __construct( - protected EntityPersister $persister, - protected Region $region, - EntityManagerInterface $em, - protected ClassMetadata $class, - ) { - $configuration = $em->getConfiguration(); - $cacheConfig = $configuration->getSecondLevelCacheConfiguration(); - $cacheFactory = $cacheConfig->getCacheFactory(); - - $this->cache = $em->getCache(); - $this->regionName = $region->getName(); - $this->uow = $em->getUnitOfWork(); - $this->metadataFactory = $em->getMetadataFactory(); - $this->cacheLogger = $cacheConfig->getCacheLogger(); - $this->timestampRegion = $cacheFactory->getTimestampRegion(); - $this->hydrator = $cacheFactory->buildEntityHydrator($em, $class); - $this->timestampKey = new TimestampCacheKey($this->class->rootEntityName); - } - - public function addInsert(object $entity): void - { - $this->persister->addInsert($entity); - } - - /** - * {@inheritDoc} - */ - public function getInserts(): array - { - return $this->persister->getInserts(); - } - - public function getSelectSQL( - array|Criteria $criteria, - AssociationMapping|null $assoc = null, - LockMode|int|null $lockMode = null, - int|null $limit = null, - int|null $offset = null, - array|null $orderBy = null, - ): string { - return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy); - } - - public function getCountSQL(array|Criteria $criteria = []): string - { - return $this->persister->getCountSQL($criteria); - } - - public function getInsertSQL(): string - { - return $this->persister->getInsertSQL(); - } - - public function getResultSetMapping(): ResultSetMapping - { - return $this->persister->getResultSetMapping(); - } - - public function getSelectConditionStatementSQL( - string $field, - mixed $value, - AssociationMapping|null $assoc = null, - string|null $comparison = null, - ): string { - return $this->persister->getSelectConditionStatementSQL($field, $value, $assoc, $comparison); - } - - public function exists(object $entity, Criteria|null $extraConditions = null): bool - { - if ($extraConditions === null) { - $key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity)); - - if ($this->region->contains($key)) { - return true; - } - } - - return $this->persister->exists($entity, $extraConditions); - } - - public function getCacheRegion(): Region - { - return $this->region; - } - - public function getEntityHydrator(): EntityHydrator - { - return $this->hydrator; - } - - public function storeEntityCache(object $entity, EntityCacheKey $key): bool - { - $class = $this->class; - $className = DefaultProxyClassNameResolver::getClass($entity); - - if ($className !== $this->class->name) { - $class = $this->metadataFactory->getMetadataFor($className); - } - - $entry = $this->hydrator->buildCacheEntry($class, $key, $entity); - $cached = $this->region->put($key, $entry); - - if ($cached) { - $this->cacheLogger?->entityCachePut($this->regionName, $key); - } - - return $cached; - } - - private function storeJoinedAssociations(object $entity): void - { - if ($this->joinedAssociations === null) { - $associations = []; - - foreach ($this->class->associationMappings as $name => $assoc) { - if ( - isset($assoc->cache) && - ($assoc->isToOne()) && - ($assoc->fetch === ClassMetadata::FETCH_EAGER || ! $assoc->isOwningSide()) - ) { - $associations[] = $name; - } - } - - $this->joinedAssociations = $associations; - } - - foreach ($this->joinedAssociations as $name) { - $assoc = $this->class->associationMappings[$name]; - $assocEntity = $this->class->getFieldValue($entity, $name); - - if ($assocEntity === null) { - continue; - } - - $assocId = $this->uow->getEntityIdentifier($assocEntity); - $assocMetadata = $this->metadataFactory->getMetadataFor($assoc->targetEntity); - $assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocId); - $assocPersister = $this->uow->getEntityPersister($assoc->targetEntity); - - $assocPersister->storeEntityCache($assocEntity, $assocKey); - } - } - - /** - * Generates a string of currently query - * - * @param string[]|Criteria $criteria - * @param array|null $orderBy - */ - protected function getHash( - string $query, - array|Criteria $criteria, - array|null $orderBy = null, - int|null $limit = null, - int|null $offset = null, - ): string { - [$params] = $criteria instanceof Criteria - ? $this->persister->expandCriteriaParameters($criteria) - : $this->persister->expandParameters($criteria); - - return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset); - } - - /** - * {@inheritDoc} - */ - public function expandParameters(array $criteria): array - { - return $this->persister->expandParameters($criteria); - } - - /** - * {@inheritDoc} - */ - public function expandCriteriaParameters(Criteria $criteria): array - { - return $this->persister->expandCriteriaParameters($criteria); - } - - public function getClassMetadata(): ClassMetadata - { - return $this->persister->getClassMetadata(); - } - - /** - * {@inheritDoc} - */ - public function getManyToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array { - return $this->persister->getManyToManyCollection($assoc, $sourceEntity, $offset, $limit); - } - - /** - * {@inheritDoc} - */ - public function getOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array { - return $this->persister->getOneToManyCollection($assoc, $sourceEntity, $offset, $limit); - } - - public function getOwningTable(string $fieldName): string - { - return $this->persister->getOwningTable($fieldName); - } - - public function executeInserts(): void - { - // The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert() - // are performed, so collect all the new entities. - $newInserts = $this->persister->getInserts(); - - if ($newInserts) { - $this->queuedCache['insert'] = array_merge($this->queuedCache['insert'] ?? [], $newInserts); - } - - $this->persister->executeInserts(); - } - - /** - * {@inheritDoc} - */ - public function load( - array $criteria, - object|null $entity = null, - AssociationMapping|null $assoc = null, - array $hints = [], - LockMode|int|null $lockMode = null, - int|null $limit = null, - array|null $orderBy = null, - ): object|null { - if ($entity !== null || $assoc !== null || $hints !== [] || $lockMode !== null) { - return $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy); - } - - //handle only EntityRepository#findOneBy - $query = $this->persister->getSelectSQL($criteria, null, null, $limit, null, $orderBy); - $hash = $this->getHash($query, $criteria); - $rsm = $this->getResultSetMapping(); - $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); - $queryCache = $this->cache->getQueryCache($this->regionName); - $result = $queryCache->get($queryKey, $rsm); - - if ($result !== null) { - $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); - - return $result[0]; - } - - $result = $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy); - - if ($result === null) { - return null; - } - - $cached = $queryCache->put($queryKey, $rsm, [$result]); - - $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); - - if ($cached) { - $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); - } - - return $result; - } - - /** - * {@inheritDoc} - */ - public function loadAll( - array $criteria = [], - array|null $orderBy = null, - int|null $limit = null, - int|null $offset = null, - ): array { - $query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); - $hash = $this->getHash($query, $criteria); - $rsm = $this->getResultSetMapping(); - $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); - $queryCache = $this->cache->getQueryCache($this->regionName); - $result = $queryCache->get($queryKey, $rsm); - - if ($result !== null) { - $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); - - return $result; - } - - $result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset); - $cached = $queryCache->put($queryKey, $rsm, $result); - - if ($result) { - $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); - } - - if ($cached) { - $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); - } - - return $result; - } - - /** - * {@inheritDoc} - */ - public function loadById(array $identifier, object|null $entity = null): object|null - { - $cacheKey = new EntityCacheKey($this->class->rootEntityName, $identifier); - $cacheEntry = $this->region->get($cacheKey); - $class = $this->class; - - if ($cacheEntry !== null) { - if ($cacheEntry->class !== $this->class->name) { - $class = $this->metadataFactory->getMetadataFor($cacheEntry->class); - } - - $cachedEntity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity); - - if ($cachedEntity !== null) { - $this->cacheLogger?->entityCacheHit($this->regionName, $cacheKey); - - return $cachedEntity; - } - } - - $entity = $this->persister->loadById($identifier, $entity); - - if ($entity === null) { - return null; - } - - $class = $this->class; - $className = DefaultProxyClassNameResolver::getClass($entity); - - if ($className !== $this->class->name) { - $class = $this->metadataFactory->getMetadataFor($className); - } - - $cacheEntry = $this->hydrator->buildCacheEntry($class, $cacheKey, $entity); - $cached = $this->region->put($cacheKey, $cacheEntry); - - if ($cached && ($this->joinedAssociations === null || $this->joinedAssociations)) { - $this->storeJoinedAssociations($entity); - } - - if ($cached) { - $this->cacheLogger?->entityCachePut($this->regionName, $cacheKey); - } - - $this->cacheLogger?->entityCacheMiss($this->regionName, $cacheKey); - - return $entity; - } - - public function count(array|Criteria $criteria = []): int - { - return $this->persister->count($criteria); - } - - /** - * {@inheritDoc} - */ - public function loadCriteria(Criteria $criteria): array - { - $orderBy = $criteria->orderings(); - $limit = $criteria->getMaxResults(); - $offset = $criteria->getFirstResult(); - $query = $this->persister->getSelectSQL($criteria); - $hash = $this->getHash($query, $criteria, $orderBy, $limit, $offset); - $rsm = $this->getResultSetMapping(); - $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); - $queryCache = $this->cache->getQueryCache($this->regionName); - $cacheResult = $queryCache->get($queryKey, $rsm); - - if ($cacheResult !== null) { - $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); - - return $cacheResult; - } - - $result = $this->persister->loadCriteria($criteria); - $cached = $queryCache->put($queryKey, $rsm, $result); - - if ($result) { - $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); - } - - if ($cached) { - $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); - } - - return $result; - } - - /** - * {@inheritDoc} - */ - public function loadManyToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - PersistentCollection $collection, - ): array { - $persister = $this->uow->getCollectionPersister($assoc); - $hasCache = ($persister instanceof CachedPersister); - - if (! $hasCache) { - return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection); - } - - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = $this->buildCollectionCacheKey($assoc, $ownerId); - $list = $persister->loadCollectionCache($collection, $key); - - if ($list !== null) { - $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key); - - return $list; - } - - $list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection); - - $persister->storeCollectionCache($key, $list); - - $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key); - - return $list; - } - - public function loadOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - PersistentCollection $collection, - ): mixed { - $persister = $this->uow->getCollectionPersister($assoc); - $hasCache = ($persister instanceof CachedPersister); - - if (! $hasCache) { - return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection); - } - - $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); - $key = $this->buildCollectionCacheKey($assoc, $ownerId); - $list = $persister->loadCollectionCache($collection, $key); - - if ($list !== null) { - $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key); - - return $list; - } - - $list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection); - - $persister->storeCollectionCache($key, $list); - - $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key); - - return $list; - } - - /** - * {@inheritDoc} - */ - public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null - { - return $this->persister->loadOneToOneEntity($assoc, $sourceEntity, $identifier); - } - - /** - * {@inheritDoc} - */ - public function lock(array $criteria, LockMode|int $lockMode): void - { - $this->persister->lock($criteria, $lockMode); - } - - /** - * {@inheritDoc} - */ - public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void - { - $this->persister->refresh($id, $entity, $lockMode); - } - - /** @param array $ownerId */ - protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId): CollectionCacheKey - { - $metadata = $this->metadataFactory->getMetadataFor($association->sourceEntity); - assert($metadata instanceof ClassMetadata); - - return new CollectionCacheKey($metadata->rootEntityName, $association->fieldName, $ownerId); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php deleted file mode 100644 index 5fba56f..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php +++ /dev/null @@ -1,20 +0,0 @@ -queuedCache['insert'])) { - foreach ($this->queuedCache['insert'] as $entity) { - $isChanged = $this->updateCache($entity, $isChanged); - } - } - - if (isset($this->queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $entity) { - $isChanged = $this->updateCache($entity, $isChanged); - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $key) { - $this->region->evict($key); - - $isChanged = true; - } - } - - if ($isChanged) { - $this->timestampRegion->update($this->timestampKey); - } - - $this->queuedCache = []; - } - - public function afterTransactionRolledBack(): void - { - $this->queuedCache = []; - } - - public function delete(object $entity): bool - { - $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); - $deleted = $this->persister->delete($entity); - - if ($deleted) { - $this->region->evict($key); - } - - $this->queuedCache['delete'][] = $key; - - return $deleted; - } - - public function update(object $entity): void - { - $this->persister->update($entity); - - $this->queuedCache['update'][] = $entity; - } - - private function updateCache(object $entity, bool $isChanged): bool - { - $class = $this->metadataFactory->getMetadataFor($entity::class); - $key = new EntityCacheKey($class->rootEntityName, $this->uow->getEntityIdentifier($entity)); - $entry = $this->hydrator->buildCacheEntry($class, $key, $entity); - $cached = $this->region->put($key, $entry); - $isChanged = $isChanged || $cached; - - if ($cached) { - $this->cacheLogger?->entityCachePut($this->regionName, $key); - } - - return $isChanged; - } -} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php deleted file mode 100644 index 4cd1784..0000000 --- a/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php +++ /dev/null @@ -1,19 +0,0 @@ -queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $item) { - $this->region->evict($item['key']); - - $isChanged = true; - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $item) { - $this->region->evict($item['key']); - - $isChanged = true; - } - } - - if ($isChanged) { - $this->timestampRegion->update($this->timestampKey); - } - - $this->queuedCache = []; - } - - public function afterTransactionRolledBack(): void - { - if (isset($this->queuedCache['update'])) { - foreach ($this->queuedCache['update'] as $item) { - $this->region->evict($item['key']); - } - } - - if (isset($this->queuedCache['delete'])) { - foreach ($this->queuedCache['delete'] as $item) { - $this->region->evict($item['key']); - } - } - - $this->queuedCache = []; - } - - public function delete(object $entity): bool - { - $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); - $lock = $this->region->lock($key); - $deleted = $this->persister->delete($entity); - - if ($deleted) { - $this->region->evict($key); - } - - if ($lock === null) { - return $deleted; - } - - $this->queuedCache['delete'][] = [ - 'lock' => $lock, - 'key' => $key, - ]; - - return $deleted; - } - - public function update(object $entity): void - { - $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); - $lock = $this->region->lock($key); - - $this->persister->update($entity); - - if ($lock === null) { - return; - } - - $this->queuedCache['update'][] = [ - 'lock' => $lock, - 'key' => $key, - ]; - } -} diff --git a/vendor/doctrine/orm/src/Cache/QueryCache.php b/vendor/doctrine/orm/src/Cache/QueryCache.php deleted file mode 100644 index e697680..0000000 --- a/vendor/doctrine/orm/src/Cache/QueryCache.php +++ /dev/null @@ -1,28 +0,0 @@ - $result List of entity identifiers */ - public function __construct( - public readonly array $result, - float|null $time = null, - ) { - $this->time = $time ?: microtime(true); - } - - /** @param array $values */ - public static function __set_state(array $values): self - { - return new self($values['result'], $values['time']); - } -} diff --git a/vendor/doctrine/orm/src/Cache/QueryCacheKey.php b/vendor/doctrine/orm/src/Cache/QueryCacheKey.php deleted file mode 100644 index 2372e5a..0000000 --- a/vendor/doctrine/orm/src/Cache/QueryCacheKey.php +++ /dev/null @@ -1,23 +0,0 @@ -name; - } - - public function contains(CacheKey $key): bool - { - return $this->cacheItemPool->hasItem($this->getCacheEntryKey($key)); - } - - public function get(CacheKey $key): CacheEntry|null - { - $item = $this->cacheItemPool->getItem($this->getCacheEntryKey($key)); - $entry = $item->isHit() ? $item->get() : null; - - if (! $entry instanceof CacheEntry) { - return null; - } - - return $entry; - } - - public function getMultiple(CollectionCacheEntry $collection): array|null - { - $keys = array_map( - $this->getCacheEntryKey(...), - $collection->identifiers, - ); - /** @var iterable $items */ - $items = $this->cacheItemPool->getItems($keys); - if ($items instanceof Traversable) { - $items = iterator_to_array($items); - } - - $result = []; - foreach ($keys as $arrayKey => $cacheKey) { - if (! isset($items[$cacheKey]) || ! $items[$cacheKey]->isHit()) { - return null; - } - - $entry = $items[$cacheKey]->get(); - if (! $entry instanceof CacheEntry) { - return null; - } - - $result[$arrayKey] = $entry; - } - - return $result; - } - - public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool - { - $item = $this->cacheItemPool - ->getItem($this->getCacheEntryKey($key)) - ->set($entry); - - if ($this->lifetime > 0) { - $item->expiresAfter($this->lifetime); - } - - return $this->cacheItemPool->save($item); - } - - public function evict(CacheKey $key): bool - { - return $this->cacheItemPool->deleteItem($this->getCacheEntryKey($key)); - } - - public function evictAll(): bool - { - return $this->cacheItemPool->clear(self::REGION_PREFIX . $this->name); - } - - private function getCacheEntryKey(CacheKey $key): string - { - return self::REGION_PREFIX . $this->name . self::REGION_KEY_SEPARATOR . strtr($key->hash, '{}()/\@:', '________'); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Region/FileLockRegion.php b/vendor/doctrine/orm/src/Cache/Region/FileLockRegion.php deleted file mode 100644 index bedd6a6..0000000 --- a/vendor/doctrine/orm/src/Cache/Region/FileLockRegion.php +++ /dev/null @@ -1,194 +0,0 @@ -getLockFileName($key); - - if (! is_file($filename)) { - return false; - } - - $time = $this->getLockTime($filename); - $content = $this->getLockContent($filename); - - if ($content === false || $time === false) { - @unlink($filename); - - return false; - } - - if ($lock && $content === $lock->value) { - return false; - } - - // outdated lock - if ($time + $this->lockLifetime <= time()) { - @unlink($filename); - - return false; - } - - return true; - } - - private function getLockFileName(CacheKey $key): string - { - return $this->directory . DIRECTORY_SEPARATOR . $key->hash . '.' . self::LOCK_EXTENSION; - } - - private function getLockContent(string $filename): string|false - { - return @file_get_contents($filename); - } - - private function getLockTime(string $filename): int|false - { - return @fileatime($filename); - } - - public function getName(): string - { - return $this->region->getName(); - } - - public function contains(CacheKey $key): bool - { - if ($this->isLocked($key)) { - return false; - } - - return $this->region->contains($key); - } - - public function get(CacheKey $key): CacheEntry|null - { - if ($this->isLocked($key)) { - return null; - } - - return $this->region->get($key); - } - - public function getMultiple(CollectionCacheEntry $collection): array|null - { - if (array_filter(array_map($this->isLocked(...), $collection->identifiers))) { - return null; - } - - return $this->region->getMultiple($collection); - } - - public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool - { - if ($this->isLocked($key, $lock)) { - return false; - } - - return $this->region->put($key, $entry); - } - - public function evict(CacheKey $key): bool - { - if ($this->isLocked($key)) { - @unlink($this->getLockFileName($key)); - } - - return $this->region->evict($key); - } - - public function evictAll(): bool - { - // The check below is necessary because on some platforms glob returns false - // when nothing matched (even though no errors occurred) - $filenames = glob(sprintf('%s/*.%s', $this->directory, self::LOCK_EXTENSION)) ?: []; - - foreach ($filenames as $filename) { - @unlink($filename); - } - - return $this->region->evictAll(); - } - - public function lock(CacheKey $key): Lock|null - { - if ($this->isLocked($key)) { - return null; - } - - $lock = Lock::createLockRead(); - $filename = $this->getLockFileName($key); - - if (@file_put_contents($filename, $lock->value, LOCK_EX) === false) { - return null; - } - - chmod($filename, 0664); - - return $lock; - } - - public function unlock(CacheKey $key, Lock $lock): bool - { - if ($this->isLocked($key, $lock)) { - return false; - } - - return @unlink($this->getLockFileName($key)); - } -} diff --git a/vendor/doctrine/orm/src/Cache/Region/UpdateTimestampCache.php b/vendor/doctrine/orm/src/Cache/Region/UpdateTimestampCache.php deleted file mode 100644 index aa75a90..0000000 --- a/vendor/doctrine/orm/src/Cache/Region/UpdateTimestampCache.php +++ /dev/null @@ -1,20 +0,0 @@ -put($key, new TimestampCacheEntry()); - } -} diff --git a/vendor/doctrine/orm/src/Cache/RegionsConfiguration.php b/vendor/doctrine/orm/src/Cache/RegionsConfiguration.php deleted file mode 100644 index a852831..0000000 --- a/vendor/doctrine/orm/src/Cache/RegionsConfiguration.php +++ /dev/null @@ -1,63 +0,0 @@ - */ - private array $lifetimes = []; - - /** @var array */ - private array $lockLifetimes = []; - - public function __construct( - private int $defaultLifetime = 3600, - private int $defaultLockLifetime = 60, - ) { - } - - public function getDefaultLifetime(): int - { - return $this->defaultLifetime; - } - - public function setDefaultLifetime(int $defaultLifetime): void - { - $this->defaultLifetime = $defaultLifetime; - } - - public function getDefaultLockLifetime(): int - { - return $this->defaultLockLifetime; - } - - public function setDefaultLockLifetime(int $defaultLockLifetime): void - { - $this->defaultLockLifetime = $defaultLockLifetime; - } - - public function getLifetime(string $regionName): int - { - return $this->lifetimes[$regionName] ?? $this->defaultLifetime; - } - - public function setLifetime(string $name, int $lifetime): void - { - $this->lifetimes[$name] = $lifetime; - } - - public function getLockLifetime(string $regionName): int - { - return $this->lockLifetimes[$regionName] ?? $this->defaultLockLifetime; - } - - public function setLockLifetime(string $name, int $lifetime): void - { - $this->lockLifetimes[$name] = $lifetime; - } -} diff --git a/vendor/doctrine/orm/src/Cache/TimestampCacheEntry.php b/vendor/doctrine/orm/src/Cache/TimestampCacheEntry.php deleted file mode 100644 index 60c9175..0000000 --- a/vendor/doctrine/orm/src/Cache/TimestampCacheEntry.php +++ /dev/null @@ -1,29 +0,0 @@ -time = $time ?? microtime(true); - } - - /** - * Creates a new TimestampCacheEntry - * - * This method allow Doctrine\Common\Cache\PhpFileCache compatibility - * - * @param array $values array containing property values - */ - public static function __set_state(array $values): TimestampCacheEntry - { - return new self($values['time']); - } -} diff --git a/vendor/doctrine/orm/src/Cache/TimestampCacheKey.php b/vendor/doctrine/orm/src/Cache/TimestampCacheKey.php deleted file mode 100644 index 5aef4c5..0000000 --- a/vendor/doctrine/orm/src/Cache/TimestampCacheKey.php +++ /dev/null @@ -1,17 +0,0 @@ -regionUpdated($key, $entry)) { - return false; - } - - if ($key->lifetime === 0) { - return true; - } - - return $entry->time + $key->lifetime > microtime(true); - } - - private function regionUpdated(QueryCacheKey $key, QueryCacheEntry $entry): bool - { - if ($key->timestampKey === null) { - return false; - } - - $timestamp = $this->timestampRegion->get($key->timestampKey); - - return $timestamp && $timestamp->time > $entry->time; - } -} diff --git a/vendor/doctrine/orm/src/Cache/TimestampRegion.php b/vendor/doctrine/orm/src/Cache/TimestampRegion.php deleted file mode 100644 index b74fa8d..0000000 --- a/vendor/doctrine/orm/src/Cache/TimestampRegion.php +++ /dev/null @@ -1,18 +0,0 @@ -, ClassMetadata::GENERATOR_TYPE_*> */ - private $identityGenerationPreferences = []; - - /** @psalm-param array, ClassMetadata::GENERATOR_TYPE_*> $value */ - public function setIdentityGenerationPreferences(array $value): void - { - $this->identityGenerationPreferences = $value; - } - - /** @psalm-return array, ClassMetadata::GENERATOR_TYPE_*> $value */ - public function getIdentityGenerationPreferences(): array - { - return $this->identityGenerationPreferences; - } - - /** - * Sets the directory where Doctrine generates any necessary proxy class files. - */ - public function setProxyDir(string $dir): void - { - $this->attributes['proxyDir'] = $dir; - } - - /** - * Gets the directory where Doctrine generates any necessary proxy class files. - */ - public function getProxyDir(): string|null - { - return $this->attributes['proxyDir'] ?? null; - } - - /** - * Gets the strategy for automatically generating proxy classes. - * - * @return ProxyFactory::AUTOGENERATE_* - */ - public function getAutoGenerateProxyClasses(): int - { - return $this->attributes['autoGenerateProxyClasses'] ?? ProxyFactory::AUTOGENERATE_ALWAYS; - } - - /** - * Sets the strategy for automatically generating proxy classes. - * - * @param bool|ProxyFactory::AUTOGENERATE_* $autoGenerate True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER. - */ - public function setAutoGenerateProxyClasses(bool|int $autoGenerate): void - { - $this->attributes['autoGenerateProxyClasses'] = (int) $autoGenerate; - } - - /** - * Gets the namespace where proxy classes reside. - */ - public function getProxyNamespace(): string|null - { - return $this->attributes['proxyNamespace'] ?? null; - } - - /** - * Sets the namespace where proxy classes reside. - */ - public function setProxyNamespace(string $ns): void - { - $this->attributes['proxyNamespace'] = $ns; - } - - /** - * Sets the cache driver implementation that is used for metadata caching. - * - * @todo Force parameter to be a Closure to ensure lazy evaluation - * (as soon as a metadata cache is in effect, the driver never needs to initialize). - */ - public function setMetadataDriverImpl(MappingDriver $driverImpl): void - { - $this->attributes['metadataDriverImpl'] = $driverImpl; - } - - /** - * Sets the entity alias map. - * - * @psalm-param array $entityNamespaces - */ - public function setEntityNamespaces(array $entityNamespaces): void - { - $this->attributes['entityNamespaces'] = $entityNamespaces; - } - - /** - * Retrieves the list of registered entity namespace aliases. - * - * @psalm-return array - */ - public function getEntityNamespaces(): array - { - return $this->attributes['entityNamespaces']; - } - - /** - * Gets the cache driver implementation that is used for the mapping metadata. - */ - public function getMetadataDriverImpl(): MappingDriver|null - { - return $this->attributes['metadataDriverImpl'] ?? null; - } - - /** - * Gets the cache driver implementation that is used for the query cache (SQL cache). - */ - public function getQueryCache(): CacheItemPoolInterface|null - { - return $this->attributes['queryCache'] ?? null; - } - - /** - * Sets the cache driver implementation that is used for the query cache (SQL cache). - */ - public function setQueryCache(CacheItemPoolInterface $cache): void - { - $this->attributes['queryCache'] = $cache; - } - - public function getHydrationCache(): CacheItemPoolInterface|null - { - return $this->attributes['hydrationCache'] ?? null; - } - - public function setHydrationCache(CacheItemPoolInterface $cache): void - { - $this->attributes['hydrationCache'] = $cache; - } - - public function getMetadataCache(): CacheItemPoolInterface|null - { - return $this->attributes['metadataCache'] ?? null; - } - - public function setMetadataCache(CacheItemPoolInterface $cache): void - { - $this->attributes['metadataCache'] = $cache; - } - - /** - * Registers a custom DQL function that produces a string value. - * Such a function can then be used in any DQL statement in any place where string - * functions are allowed. - * - * DQL function names are case-insensitive. - * - * @param class-string|callable $className Class name or a callable that returns the function. - * @psalm-param class-string|callable(string):FunctionNode $className - */ - public function addCustomStringFunction(string $name, string|callable $className): void - { - $this->attributes['customStringFunctions'][strtolower($name)] = $className; - } - - /** - * Gets the implementation class name of a registered custom string DQL function. - * - * @psalm-return class-string|callable(string):FunctionNode|null - */ - public function getCustomStringFunction(string $name): string|callable|null - { - $name = strtolower($name); - - return $this->attributes['customStringFunctions'][$name] ?? null; - } - - /** - * Sets a map of custom DQL string functions. - * - * Keys must be function names and values the FQCN of the implementing class. - * The function names will be case-insensitive in DQL. - * - * Any previously added string functions are discarded. - * - * @psalm-param array|callable(string):FunctionNode> $functions The map of custom - * DQL string functions. - */ - public function setCustomStringFunctions(array $functions): void - { - foreach ($functions as $name => $className) { - $this->addCustomStringFunction($name, $className); - } - } - - /** - * Registers a custom DQL function that produces a numeric value. - * Such a function can then be used in any DQL statement in any place where numeric - * functions are allowed. - * - * DQL function names are case-insensitive. - * - * @param class-string|callable $className Class name or a callable that returns the function. - * @psalm-param class-string|callable(string):FunctionNode $className - */ - public function addCustomNumericFunction(string $name, string|callable $className): void - { - $this->attributes['customNumericFunctions'][strtolower($name)] = $className; - } - - /** - * Gets the implementation class name of a registered custom numeric DQL function. - * - * @psalm-return ?class-string|callable(string):FunctionNode - */ - public function getCustomNumericFunction(string $name): string|callable|null - { - $name = strtolower($name); - - return $this->attributes['customNumericFunctions'][$name] ?? null; - } - - /** - * Sets a map of custom DQL numeric functions. - * - * Keys must be function names and values the FQCN of the implementing class. - * The function names will be case-insensitive in DQL. - * - * Any previously added numeric functions are discarded. - * - * @psalm-param array $functions The map of custom - * DQL numeric functions. - */ - public function setCustomNumericFunctions(array $functions): void - { - foreach ($functions as $name => $className) { - $this->addCustomNumericFunction($name, $className); - } - } - - /** - * Registers a custom DQL function that produces a date/time value. - * Such a function can then be used in any DQL statement in any place where date/time - * functions are allowed. - * - * DQL function names are case-insensitive. - * - * @param string|callable $className Class name or a callable that returns the function. - * @psalm-param class-string|callable(string):FunctionNode $className - */ - public function addCustomDatetimeFunction(string $name, string|callable $className): void - { - $this->attributes['customDatetimeFunctions'][strtolower($name)] = $className; - } - - /** - * Gets the implementation class name of a registered custom date/time DQL function. - * - * @psalm-return class-string|callable|null - */ - public function getCustomDatetimeFunction(string $name): string|callable|null - { - $name = strtolower($name); - - return $this->attributes['customDatetimeFunctions'][$name] ?? null; - } - - /** - * Sets a map of custom DQL date/time functions. - * - * Keys must be function names and values the FQCN of the implementing class. - * The function names will be case-insensitive in DQL. - * - * Any previously added date/time functions are discarded. - * - * @param array $functions The map of custom DQL date/time functions. - * @psalm-param array|callable(string):FunctionNode> $functions - */ - public function setCustomDatetimeFunctions(array $functions): void - { - foreach ($functions as $name => $className) { - $this->addCustomDatetimeFunction($name, $className); - } - } - - /** - * Sets a TypedFieldMapper for php typed fields to DBAL types auto-completion. - */ - public function setTypedFieldMapper(TypedFieldMapper|null $typedFieldMapper): void - { - $this->attributes['typedFieldMapper'] = $typedFieldMapper; - } - - /** - * Gets a TypedFieldMapper for php typed fields to DBAL types auto-completion. - */ - public function getTypedFieldMapper(): TypedFieldMapper|null - { - return $this->attributes['typedFieldMapper'] ?? null; - } - - /** - * Sets the custom hydrator modes in one pass. - * - * @param array> $modes An array of ($modeName => $hydrator). - */ - public function setCustomHydrationModes(array $modes): void - { - $this->attributes['customHydrationModes'] = []; - - foreach ($modes as $modeName => $hydrator) { - $this->addCustomHydrationMode($modeName, $hydrator); - } - } - - /** - * Gets the hydrator class for the given hydration mode name. - * - * @psalm-return class-string|null - */ - public function getCustomHydrationMode(string $modeName): string|null - { - return $this->attributes['customHydrationModes'][$modeName] ?? null; - } - - /** - * Adds a custom hydration mode. - * - * @psalm-param class-string $hydrator - */ - public function addCustomHydrationMode(string $modeName, string $hydrator): void - { - $this->attributes['customHydrationModes'][$modeName] = $hydrator; - } - - /** - * Sets a class metadata factory. - * - * @psalm-param class-string $cmfName - */ - public function setClassMetadataFactoryName(string $cmfName): void - { - $this->attributes['classMetadataFactoryName'] = $cmfName; - } - - /** @psalm-return class-string */ - public function getClassMetadataFactoryName(): string - { - if (! isset($this->attributes['classMetadataFactoryName'])) { - $this->attributes['classMetadataFactoryName'] = ClassMetadataFactory::class; - } - - return $this->attributes['classMetadataFactoryName']; - } - - /** - * Adds a filter to the list of possible filters. - * - * @param string $className The class name of the filter. - * @psalm-param class-string $className - */ - public function addFilter(string $name, string $className): void - { - $this->attributes['filters'][$name] = $className; - } - - /** - * Gets the class name for a given filter name. - * - * @return string|null The class name of the filter, or null if it is not - * defined. - * @psalm-return class-string|null - */ - public function getFilterClassName(string $name): string|null - { - return $this->attributes['filters'][$name] ?? null; - } - - /** - * Sets default repository class. - * - * @psalm-param class-string $className - * - * @throws InvalidEntityRepository If $classname is not an ObjectRepository. - */ - public function setDefaultRepositoryClassName(string $className): void - { - if (! class_exists($className) || ! is_a($className, EntityRepository::class, true)) { - throw InvalidEntityRepository::fromClassName($className); - } - - $this->attributes['defaultRepositoryClassName'] = $className; - } - - /** - * Get default repository class. - * - * @psalm-return class-string - */ - public function getDefaultRepositoryClassName(): string - { - return $this->attributes['defaultRepositoryClassName'] ?? EntityRepository::class; - } - - /** - * Sets naming strategy. - */ - public function setNamingStrategy(NamingStrategy $namingStrategy): void - { - $this->attributes['namingStrategy'] = $namingStrategy; - } - - /** - * Gets naming strategy.. - */ - public function getNamingStrategy(): NamingStrategy - { - if (! isset($this->attributes['namingStrategy'])) { - $this->attributes['namingStrategy'] = new DefaultNamingStrategy(); - } - - return $this->attributes['namingStrategy']; - } - - /** - * Sets quote strategy. - */ - public function setQuoteStrategy(QuoteStrategy $quoteStrategy): void - { - $this->attributes['quoteStrategy'] = $quoteStrategy; - } - - /** - * Gets quote strategy. - */ - public function getQuoteStrategy(): QuoteStrategy - { - if (! isset($this->attributes['quoteStrategy'])) { - $this->attributes['quoteStrategy'] = new DefaultQuoteStrategy(); - } - - return $this->attributes['quoteStrategy']; - } - - /** - * Set the entity listener resolver. - */ - public function setEntityListenerResolver(EntityListenerResolver $resolver): void - { - $this->attributes['entityListenerResolver'] = $resolver; - } - - /** - * Get the entity listener resolver. - */ - public function getEntityListenerResolver(): EntityListenerResolver - { - if (! isset($this->attributes['entityListenerResolver'])) { - $this->attributes['entityListenerResolver'] = new DefaultEntityListenerResolver(); - } - - return $this->attributes['entityListenerResolver']; - } - - /** - * Set the entity repository factory. - */ - public function setRepositoryFactory(RepositoryFactory $repositoryFactory): void - { - $this->attributes['repositoryFactory'] = $repositoryFactory; - } - - /** - * Get the entity repository factory. - */ - public function getRepositoryFactory(): RepositoryFactory - { - return $this->attributes['repositoryFactory'] ?? new DefaultRepositoryFactory(); - } - - public function isSecondLevelCacheEnabled(): bool - { - return $this->attributes['isSecondLevelCacheEnabled'] ?? false; - } - - public function setSecondLevelCacheEnabled(bool $flag = true): void - { - $this->attributes['isSecondLevelCacheEnabled'] = $flag; - } - - public function setSecondLevelCacheConfiguration(CacheConfiguration $cacheConfig): void - { - $this->attributes['secondLevelCacheConfiguration'] = $cacheConfig; - } - - public function getSecondLevelCacheConfiguration(): CacheConfiguration|null - { - if (! isset($this->attributes['secondLevelCacheConfiguration']) && $this->isSecondLevelCacheEnabled()) { - $this->attributes['secondLevelCacheConfiguration'] = new CacheConfiguration(); - } - - return $this->attributes['secondLevelCacheConfiguration'] ?? null; - } - - /** - * Returns query hints, which will be applied to every query in application - * - * @psalm-return array - */ - public function getDefaultQueryHints(): array - { - return $this->attributes['defaultQueryHints'] ?? []; - } - - /** - * Sets array of query hints, which will be applied to every query in application - * - * @psalm-param array $defaultQueryHints - */ - public function setDefaultQueryHints(array $defaultQueryHints): void - { - $this->attributes['defaultQueryHints'] = $defaultQueryHints; - } - - /** - * Gets the value of a default query hint. If the hint name is not recognized, FALSE is returned. - * - * @return mixed The value of the hint or FALSE, if the hint name is not recognized. - */ - public function getDefaultQueryHint(string $name): mixed - { - return $this->attributes['defaultQueryHints'][$name] ?? false; - } - - /** - * Sets a default query hint. If the hint name is not recognized, it is silently ignored. - */ - public function setDefaultQueryHint(string $name, mixed $value): void - { - $this->attributes['defaultQueryHints'][$name] = $value; - } - - /** - * Gets a list of entity class names to be ignored by the SchemaTool - * - * @return list - */ - public function getSchemaIgnoreClasses(): array - { - return $this->attributes['schemaIgnoreClasses'] ?? []; - } - - /** - * Sets a list of entity class names to be ignored by the SchemaTool - * - * @param list $schemaIgnoreClasses List of entity class names - */ - public function setSchemaIgnoreClasses(array $schemaIgnoreClasses): void - { - $this->attributes['schemaIgnoreClasses'] = $schemaIgnoreClasses; - } - - /** - * To be deprecated in 3.1.0 - * - * @return true - */ - public function isLazyGhostObjectEnabled(): bool - { - return true; - } - - /** To be deprecated in 3.1.0 */ - public function setLazyGhostObjectEnabled(bool $flag): void - { - if (! $flag) { - throw new LogicException(<<<'EXCEPTION' - The lazy ghost object feature cannot be disabled anymore. - Please remove the call to setLazyGhostObjectEnabled(false). - EXCEPTION); - } - } - - /** To be deprecated in 3.1.0 */ - public function setRejectIdCollisionInIdentityMap(bool $flag): void - { - if (! $flag) { - throw new LogicException(<<<'EXCEPTION' - Rejecting ID collisions in the identity map cannot be disabled anymore. - Please remove the call to setRejectIdCollisionInIdentityMap(false). - EXCEPTION); - } - } - - /** - * To be deprecated in 3.1.0 - * - * @return true - */ - public function isRejectIdCollisionInIdentityMapEnabled(): bool - { - return true; - } - - public function setEagerFetchBatchSize(int $batchSize = 100): void - { - $this->attributes['fetchModeSubselectBatchSize'] = $batchSize; - } - - public function getEagerFetchBatchSize(): int - { - return $this->attributes['fetchModeSubselectBatchSize'] ?? 100; - } -} diff --git a/vendor/doctrine/orm/src/Decorator/EntityManagerDecorator.php b/vendor/doctrine/orm/src/Decorator/EntityManagerDecorator.php deleted file mode 100644 index 6f1b041..0000000 --- a/vendor/doctrine/orm/src/Decorator/EntityManagerDecorator.php +++ /dev/null @@ -1,174 +0,0 @@ - - */ -abstract class EntityManagerDecorator extends ObjectManagerDecorator implements EntityManagerInterface -{ - public function __construct(EntityManagerInterface $wrapped) - { - $this->wrapped = $wrapped; - } - - public function getRepository(string $className): EntityRepository - { - return $this->wrapped->getRepository($className); - } - - public function getMetadataFactory(): ClassMetadataFactory - { - return $this->wrapped->getMetadataFactory(); - } - - public function getClassMetadata(string $className): ClassMetadata - { - return $this->wrapped->getClassMetadata($className); - } - - public function getConnection(): Connection - { - return $this->wrapped->getConnection(); - } - - public function getExpressionBuilder(): Expr - { - return $this->wrapped->getExpressionBuilder(); - } - - public function beginTransaction(): void - { - $this->wrapped->beginTransaction(); - } - - public function wrapInTransaction(callable $func): mixed - { - return $this->wrapped->wrapInTransaction($func); - } - - public function commit(): void - { - $this->wrapped->commit(); - } - - public function rollback(): void - { - $this->wrapped->rollback(); - } - - public function createQuery(string $dql = ''): Query - { - return $this->wrapped->createQuery($dql); - } - - public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery - { - return $this->wrapped->createNativeQuery($sql, $rsm); - } - - public function createQueryBuilder(): QueryBuilder - { - return $this->wrapped->createQueryBuilder(); - } - - public function getReference(string $entityName, mixed $id): object|null - { - return $this->wrapped->getReference($entityName, $id); - } - - public function close(): void - { - $this->wrapped->close(); - } - - public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void - { - $this->wrapped->lock($entity, $lockMode, $lockVersion); - } - - public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null - { - return $this->wrapped->find($className, $id, $lockMode, $lockVersion); - } - - public function refresh(object $object, LockMode|int|null $lockMode = null): void - { - $this->wrapped->refresh($object, $lockMode); - } - - public function getEventManager(): EventManager - { - return $this->wrapped->getEventManager(); - } - - public function getConfiguration(): Configuration - { - return $this->wrapped->getConfiguration(); - } - - public function isOpen(): bool - { - return $this->wrapped->isOpen(); - } - - public function getUnitOfWork(): UnitOfWork - { - return $this->wrapped->getUnitOfWork(); - } - - public function newHydrator(string|int $hydrationMode): AbstractHydrator - { - return $this->wrapped->newHydrator($hydrationMode); - } - - public function getProxyFactory(): ProxyFactory - { - return $this->wrapped->getProxyFactory(); - } - - public function getFilters(): FilterCollection - { - return $this->wrapped->getFilters(); - } - - public function isFiltersStateClean(): bool - { - return $this->wrapped->isFiltersStateClean(); - } - - public function hasFilters(): bool - { - return $this->wrapped->hasFilters(); - } - - public function getCache(): Cache|null - { - return $this->wrapped->getCache(); - } -} diff --git a/vendor/doctrine/orm/src/EntityManager.php b/vendor/doctrine/orm/src/EntityManager.php deleted file mode 100644 index 8045ac2..0000000 --- a/vendor/doctrine/orm/src/EntityManager.php +++ /dev/null @@ -1,626 +0,0 @@ - 'pdo_sqlite', 'memory' => true], $config); - * $entityManager = new EntityManager($connection, $config); - * - * For more information see - * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/configuration.html} - * - * You should never attempt to inherit from the EntityManager: Inheritance - * is not a valid extension point for the EntityManager. Instead you - * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator} - * and wrap your entity manager in a decorator. - * - * @final - */ -class EntityManager implements EntityManagerInterface -{ - /** - * The metadata factory, used to retrieve the ORM metadata of entity classes. - */ - private ClassMetadataFactory $metadataFactory; - - /** - * The UnitOfWork used to coordinate object-level transactions. - */ - private UnitOfWork $unitOfWork; - - /** - * The event manager that is the central point of the event system. - */ - private EventManager $eventManager; - - /** - * The proxy factory used to create dynamic proxies. - */ - private ProxyFactory $proxyFactory; - - /** - * The repository factory used to create dynamic repositories. - */ - private RepositoryFactory $repositoryFactory; - - /** - * The expression builder instance used to generate query expressions. - */ - private Expr|null $expressionBuilder = null; - - /** - * Whether the EntityManager is closed or not. - */ - private bool $closed = false; - - /** - * Collection of query filters. - */ - private FilterCollection|null $filterCollection = null; - - /** - * The second level cache regions API. - */ - private Cache|null $cache = null; - - /** - * Creates a new EntityManager that operates on the given database connection - * and uses the given Configuration and EventManager implementations. - * - * @param Connection $conn The database connection used by the EntityManager. - */ - public function __construct( - private Connection $conn, - private Configuration $config, - EventManager|null $eventManager = null, - ) { - if (! $config->getMetadataDriverImpl()) { - throw MissingMappingDriverImplementation::create(); - } - - $this->eventManager = $eventManager - ?? (method_exists($conn, 'getEventManager') - ? $conn->getEventManager() - : new EventManager() - ); - - $metadataFactoryClassName = $config->getClassMetadataFactoryName(); - - $this->metadataFactory = new $metadataFactoryClassName(); - $this->metadataFactory->setEntityManager($this); - - $this->configureMetadataCache(); - - $this->repositoryFactory = $config->getRepositoryFactory(); - $this->unitOfWork = new UnitOfWork($this); - $this->proxyFactory = new ProxyFactory( - $this, - $config->getProxyDir(), - $config->getProxyNamespace(), - $config->getAutoGenerateProxyClasses(), - ); - - if ($config->isSecondLevelCacheEnabled()) { - $cacheConfig = $config->getSecondLevelCacheConfiguration(); - $cacheFactory = $cacheConfig->getCacheFactory(); - $this->cache = $cacheFactory->createCache($this); - } - } - - public function getConnection(): Connection - { - return $this->conn; - } - - public function getMetadataFactory(): ClassMetadataFactory - { - return $this->metadataFactory; - } - - public function getExpressionBuilder(): Expr - { - return $this->expressionBuilder ??= new Expr(); - } - - public function beginTransaction(): void - { - $this->conn->beginTransaction(); - } - - public function getCache(): Cache|null - { - return $this->cache; - } - - public function wrapInTransaction(callable $func): mixed - { - $this->conn->beginTransaction(); - - try { - $return = $func($this); - - $this->flush(); - $this->conn->commit(); - - return $return; - } catch (Throwable $e) { - $this->close(); - $this->conn->rollBack(); - - throw $e; - } - } - - public function commit(): void - { - $this->conn->commit(); - } - - public function rollback(): void - { - $this->conn->rollBack(); - } - - /** - * Returns the ORM metadata descriptor for a class. - * - * Internal note: Performance-sensitive method. - * - * {@inheritDoc} - */ - public function getClassMetadata(string $className): Mapping\ClassMetadata - { - return $this->metadataFactory->getMetadataFor($className); - } - - public function createQuery(string $dql = ''): Query - { - $query = new Query($this); - - if (! empty($dql)) { - $query->setDQL($dql); - } - - return $query; - } - - public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery - { - $query = new NativeQuery($this); - - $query->setSQL($sql); - $query->setResultSetMapping($rsm); - - return $query; - } - - public function createQueryBuilder(): QueryBuilder - { - return new QueryBuilder($this); - } - - /** - * Flushes all changes to objects that have been queued up to now to the database. - * This effectively synchronizes the in-memory state of managed objects with the - * database. - * - * If an entity is explicitly passed to this method only this entity and - * the cascade-persist semantics + scheduled inserts/removals are synchronized. - * - * @throws OptimisticLockException If a version check on an entity that - * makes use of optimistic locking fails. - * @throws ORMException - */ - public function flush(): void - { - $this->errorIfClosed(); - $this->unitOfWork->commit(); - } - - /** - * {@inheritDoc} - */ - public function find($className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null - { - $class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\')); - - if ($lockMode !== null) { - $this->checkLockRequirements($lockMode, $class); - } - - if (! is_array($id)) { - if ($class->isIdentifierComposite) { - throw ORMInvalidArgumentException::invalidCompositeIdentifier(); - } - - $id = [$class->identifier[0] => $id]; - } - - foreach ($id as $i => $value) { - if (is_object($value)) { - $className = DefaultProxyClassNameResolver::getClass($value); - if ($this->metadataFactory->hasMetadataFor($className)) { - $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); - - if ($id[$i] === null) { - throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($className); - } - } - } - } - - $sortedId = []; - - foreach ($class->identifier as $identifier) { - if (! isset($id[$identifier])) { - throw MissingIdentifierField::fromFieldAndClass($identifier, $class->name); - } - - if ($id[$identifier] instanceof BackedEnum) { - $sortedId[$identifier] = $id[$identifier]->value; - } else { - $sortedId[$identifier] = $id[$identifier]; - } - - unset($id[$identifier]); - } - - if ($id) { - throw UnrecognizedIdentifierFields::fromClassAndFieldNames($class->name, array_keys($id)); - } - - $unitOfWork = $this->getUnitOfWork(); - - $entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName); - - // Check identity map first - if ($entity !== false) { - if (! ($entity instanceof $class->name)) { - return null; - } - - switch (true) { - case $lockMode === LockMode::OPTIMISTIC: - $this->lock($entity, $lockMode, $lockVersion); - break; - - case $lockMode === LockMode::NONE: - case $lockMode === LockMode::PESSIMISTIC_READ: - case $lockMode === LockMode::PESSIMISTIC_WRITE: - $persister = $unitOfWork->getEntityPersister($class->name); - $persister->refresh($sortedId, $entity, $lockMode); - break; - } - - return $entity; // Hit! - } - - $persister = $unitOfWork->getEntityPersister($class->name); - - switch (true) { - case $lockMode === LockMode::OPTIMISTIC: - $entity = $persister->load($sortedId); - - if ($entity !== null) { - $unitOfWork->lock($entity, $lockMode, $lockVersion); - } - - return $entity; - - case $lockMode === LockMode::PESSIMISTIC_READ: - case $lockMode === LockMode::PESSIMISTIC_WRITE: - return $persister->load($sortedId, null, null, [], $lockMode); - - default: - return $persister->loadById($sortedId); - } - } - - public function getReference(string $entityName, mixed $id): object|null - { - $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); - - if (! is_array($id)) { - $id = [$class->identifier[0] => $id]; - } - - $sortedId = []; - - foreach ($class->identifier as $identifier) { - if (! isset($id[$identifier])) { - throw MissingIdentifierField::fromFieldAndClass($identifier, $class->name); - } - - $sortedId[$identifier] = $id[$identifier]; - unset($id[$identifier]); - } - - if ($id) { - throw UnrecognizedIdentifierFields::fromClassAndFieldNames($class->name, array_keys($id)); - } - - $entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName); - - // Check identity map first, if its already in there just return it. - if ($entity !== false) { - return $entity instanceof $class->name ? $entity : null; - } - - if ($class->subClasses) { - return $this->find($entityName, $sortedId); - } - - $entity = $this->proxyFactory->getProxy($class->name, $sortedId); - - $this->unitOfWork->registerManaged($entity, $sortedId, []); - - return $entity; - } - - /** - * Clears the EntityManager. All entities that are currently managed - * by this EntityManager become detached. - */ - public function clear(): void - { - $this->unitOfWork->clear(); - } - - public function close(): void - { - $this->clear(); - - $this->closed = true; - } - - /** - * Tells the EntityManager to make an instance managed and persistent. - * - * The entity will be entered into the database at or before transaction - * commit or as a result of the flush operation. - * - * NOTE: The persist operation always considers entities that are not yet known to - * this EntityManager as NEW. Do not pass detached entities to the persist operation. - * - * @throws ORMInvalidArgumentException - * @throws ORMException - */ - public function persist(object $object): void - { - $this->errorIfClosed(); - - $this->unitOfWork->persist($object); - } - - /** - * Removes an entity instance. - * - * A removed entity will be removed from the database at or before transaction commit - * or as a result of the flush operation. - * - * @throws ORMInvalidArgumentException - * @throws ORMException - */ - public function remove(object $object): void - { - $this->errorIfClosed(); - - $this->unitOfWork->remove($object); - } - - public function refresh(object $object, LockMode|int|null $lockMode = null): void - { - $this->errorIfClosed(); - - $this->unitOfWork->refresh($object, $lockMode); - } - - /** - * Detaches an entity from the EntityManager, causing a managed entity to - * become detached. Unflushed changes made to the entity if any - * (including removal of the entity), will not be synchronized to the database. - * Entities which previously referenced the detached entity will continue to - * reference it. - * - * @throws ORMInvalidArgumentException - */ - public function detach(object $object): void - { - $this->unitOfWork->detach($object); - } - - public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void - { - $this->unitOfWork->lock($entity, $lockMode, $lockVersion); - } - - /** - * Gets the repository for an entity class. - * - * @psalm-param class-string $className - * - * @psalm-return EntityRepository - * - * @template T of object - */ - public function getRepository(string $className): EntityRepository - { - return $this->repositoryFactory->getRepository($this, $className); - } - - /** - * Determines whether an entity instance is managed in this EntityManager. - * - * @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise. - */ - public function contains(object $object): bool - { - return $this->unitOfWork->isScheduledForInsert($object) - || $this->unitOfWork->isInIdentityMap($object) - && ! $this->unitOfWork->isScheduledForDelete($object); - } - - public function getEventManager(): EventManager - { - return $this->eventManager; - } - - public function getConfiguration(): Configuration - { - return $this->config; - } - - /** - * Throws an exception if the EntityManager is closed or currently not active. - * - * @throws EntityManagerClosed If the EntityManager is closed. - */ - private function errorIfClosed(): void - { - if ($this->closed) { - throw EntityManagerClosed::create(); - } - } - - public function isOpen(): bool - { - return ! $this->closed; - } - - public function getUnitOfWork(): UnitOfWork - { - return $this->unitOfWork; - } - - public function newHydrator(string|int $hydrationMode): AbstractHydrator - { - return match ($hydrationMode) { - Query::HYDRATE_OBJECT => new Internal\Hydration\ObjectHydrator($this), - Query::HYDRATE_ARRAY => new Internal\Hydration\ArrayHydrator($this), - Query::HYDRATE_SCALAR => new Internal\Hydration\ScalarHydrator($this), - Query::HYDRATE_SINGLE_SCALAR => new Internal\Hydration\SingleScalarHydrator($this), - Query::HYDRATE_SIMPLEOBJECT => new Internal\Hydration\SimpleObjectHydrator($this), - Query::HYDRATE_SCALAR_COLUMN => new Internal\Hydration\ScalarColumnHydrator($this), - default => $this->createCustomHydrator((string) $hydrationMode), - }; - } - - public function getProxyFactory(): ProxyFactory - { - return $this->proxyFactory; - } - - public function initializeObject(object $obj): void - { - $this->unitOfWork->initializeObject($obj); - } - - /** - * {@inheritDoc} - */ - public function isUninitializedObject($obj): bool - { - return $this->unitOfWork->isUninitializedObject($obj); - } - - public function getFilters(): FilterCollection - { - return $this->filterCollection ??= new FilterCollection($this); - } - - public function isFiltersStateClean(): bool - { - return $this->filterCollection === null || $this->filterCollection->isClean(); - } - - public function hasFilters(): bool - { - return $this->filterCollection !== null; - } - - /** - * @psalm-param LockMode::* $lockMode - * - * @throws OptimisticLockException - * @throws TransactionRequiredException - */ - private function checkLockRequirements(LockMode|int $lockMode, ClassMetadata $class): void - { - switch ($lockMode) { - case LockMode::OPTIMISTIC: - if (! $class->isVersioned) { - throw OptimisticLockException::notVersioned($class->name); - } - - break; - case LockMode::PESSIMISTIC_READ: - case LockMode::PESSIMISTIC_WRITE: - if (! $this->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } - } - } - - private function configureMetadataCache(): void - { - $metadataCache = $this->config->getMetadataCache(); - if (! $metadataCache) { - return; - } - - $this->metadataFactory->setCache($metadataCache); - } - - private function createCustomHydrator(string $hydrationMode): AbstractHydrator - { - $class = $this->config->getCustomHydrationMode($hydrationMode); - - if ($class !== null) { - return new $class($this); - } - - throw InvalidHydrationMode::fromMode($hydrationMode); - } -} diff --git a/vendor/doctrine/orm/src/EntityManagerInterface.php b/vendor/doctrine/orm/src/EntityManagerInterface.php deleted file mode 100644 index cf3102b..0000000 --- a/vendor/doctrine/orm/src/EntityManagerInterface.php +++ /dev/null @@ -1,242 +0,0 @@ - $className - * - * @psalm-return EntityRepository - * - * @template T of object - */ - public function getRepository(string $className): EntityRepository; - - /** - * Returns the cache API for managing the second level cache regions or NULL if the cache is not enabled. - */ - public function getCache(): Cache|null; - - /** - * Gets the database connection object used by the EntityManager. - */ - public function getConnection(): Connection; - - public function getMetadataFactory(): ClassMetadataFactory; - - /** - * Gets an ExpressionBuilder used for object-oriented construction of query expressions. - * - * Example: - * - * - * $qb = $em->createQueryBuilder(); - * $expr = $em->getExpressionBuilder(); - * $qb->select('u')->from('User', 'u') - * ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2))); - * - */ - public function getExpressionBuilder(): Expr; - - /** - * Starts a transaction on the underlying database connection. - */ - public function beginTransaction(): void; - - /** - * Executes a function in a transaction. - * - * The function gets passed this EntityManager instance as an (optional) parameter. - * - * {@link flush} is invoked prior to transaction commit. - * - * If an exception occurs during execution of the function or flushing or transaction commit, - * the transaction is rolled back, the EntityManager closed and the exception re-thrown. - * - * @psalm-param callable(self): T $func The function to execute transactionally. - * - * @return mixed The value returned from the closure. - * @psalm-return T - * - * @template T - */ - public function wrapInTransaction(callable $func): mixed; - - /** - * Commits a transaction on the underlying database connection. - */ - public function commit(): void; - - /** - * Performs a rollback on the underlying database connection. - */ - public function rollback(): void; - - /** - * Creates a new Query object. - * - * @param string $dql The DQL string. - */ - public function createQuery(string $dql = ''): Query; - - /** - * Creates a native SQL query. - */ - public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery; - - /** - * Create a QueryBuilder instance - */ - public function createQueryBuilder(): QueryBuilder; - - /** - * Finds an Entity by its identifier. - * - * @param string $className The class name of the entity to find. - * @param mixed $id The identity of the entity to find. - * @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants - * or NULL if no specific lock mode should be used - * during the search. - * @param int|null $lockVersion The version of the entity to find when using - * optimistic locking. - * @psalm-param class-string $className - * @psalm-param LockMode::*|null $lockMode - * - * @return object|null The entity instance or NULL if the entity can not be found. - * @psalm-return T|null - * - * @throws OptimisticLockException - * @throws ORMInvalidArgumentException - * @throws TransactionRequiredException - * @throws ORMException - * - * @template T of object - */ - public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null; - - /** - * Refreshes the persistent state of an object from the database, - * overriding any local changes that have not yet been persisted. - * - * @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants - * or NULL if no specific lock mode should be used - * during the search. - * @psalm-param LockMode::*|null $lockMode - * - * @throws ORMInvalidArgumentException - * @throws ORMException - * @throws TransactionRequiredException - */ - public function refresh(object $object, LockMode|int|null $lockMode = null): void; - - /** - * Gets a reference to the entity identified by the given type and identifier - * without actually loading it, if the entity is not yet loaded. - * - * @param string $entityName The name of the entity type. - * @param mixed $id The entity identifier. - * @psalm-param class-string $entityName - * - * @psalm-return T|null - * - * @throws ORMException - * - * @template T of object - */ - public function getReference(string $entityName, mixed $id): object|null; - - /** - * Closes the EntityManager. All entities that are currently managed - * by this EntityManager become detached. The EntityManager may no longer - * be used after it is closed. - */ - public function close(): void; - - /** - * Acquire a lock on the given entity. - * - * @psalm-param LockMode::* $lockMode - * - * @throws OptimisticLockException - * @throws PessimisticLockException - */ - public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void; - - /** - * Gets the EventManager used by the EntityManager. - */ - public function getEventManager(): EventManager; - - /** - * Gets the Configuration used by the EntityManager. - */ - public function getConfiguration(): Configuration; - - /** - * Check if the Entity manager is open or closed. - */ - public function isOpen(): bool; - - /** - * Gets the UnitOfWork used by the EntityManager to coordinate operations. - */ - public function getUnitOfWork(): UnitOfWork; - - /** - * Create a new instance for the given hydration mode. - * - * @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode - * - * @throws ORMException - */ - public function newHydrator(string|int $hydrationMode): AbstractHydrator; - - /** - * Gets the proxy factory used by the EntityManager to create entity proxies. - */ - public function getProxyFactory(): ProxyFactory; - - /** - * Gets the enabled filters. - */ - public function getFilters(): FilterCollection; - - /** - * Checks whether the state of the filter collection is clean. - */ - public function isFiltersStateClean(): bool; - - /** - * Checks whether the Entity Manager has filters. - */ - public function hasFilters(): bool; - - /** - * {@inheritDoc} - * - * @psalm-param string|class-string $className - * - * @psalm-return ($className is class-string ? Mapping\ClassMetadata : Mapping\ClassMetadata) - * - * @psalm-template T of object - */ - public function getClassMetadata(string $className): Mapping\ClassMetadata; -} diff --git a/vendor/doctrine/orm/src/EntityNotFoundException.php b/vendor/doctrine/orm/src/EntityNotFoundException.php deleted file mode 100644 index 142dc8a..0000000 --- a/vendor/doctrine/orm/src/EntityNotFoundException.php +++ /dev/null @@ -1,46 +0,0 @@ - $value) { - $ids[] = $key . '(' . $value . ')'; - } - - return new self( - 'Entity of type \'' . $className . '\'' . ($ids ? ' for IDs ' . implode(', ', $ids) : '') . ' was not found', - ); - } - - /** - * Instance for which no identifier can be found - */ - public static function noIdentifierFound(string $className): self - { - return new self(sprintf( - 'Unable to find "%s" entity identifier associated with the UnitOfWork', - $className, - )); - } -} diff --git a/vendor/doctrine/orm/src/EntityRepository.php b/vendor/doctrine/orm/src/EntityRepository.php deleted file mode 100644 index a53c528..0000000 --- a/vendor/doctrine/orm/src/EntityRepository.php +++ /dev/null @@ -1,236 +0,0 @@ - - * @template-implements ObjectRepository - */ -class EntityRepository implements ObjectRepository, Selectable -{ - /** @psalm-var class-string */ - private readonly string $entityName; - private static Inflector|null $inflector = null; - - /** @psalm-param ClassMetadata $class */ - public function __construct( - private readonly EntityManagerInterface $em, - private readonly ClassMetadata $class, - ) { - $this->entityName = $class->name; - } - - /** - * Creates a new QueryBuilder instance that is prepopulated for this entity name. - */ - public function createQueryBuilder(string $alias, string|null $indexBy = null): QueryBuilder - { - return $this->em->createQueryBuilder() - ->select($alias) - ->from($this->entityName, $alias, $indexBy); - } - - /** - * Creates a new result set mapping builder for this entity. - * - * The column naming strategy is "INCREMENT". - */ - public function createResultSetMappingBuilder(string $alias): ResultSetMappingBuilder - { - $rsm = new ResultSetMappingBuilder($this->em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT); - $rsm->addRootEntityFromClassMetadata($this->entityName, $alias); - - return $rsm; - } - - /** - * Finds an entity by its primary key / identifier. - * - * @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants - * or NULL if no specific lock mode should be used - * during the search. - * @psalm-param LockMode::*|null $lockMode - * - * @return object|null The entity instance or NULL if the entity can not be found. - * @psalm-return ?T - */ - public function find(mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null - { - return $this->em->find($this->entityName, $id, $lockMode, $lockVersion); - } - - /** - * Finds all entities in the repository. - * - * @psalm-return list The entities. - */ - public function findAll(): array - { - return $this->findBy([]); - } - - /** - * Finds entities by a set of criteria. - * - * {@inheritDoc} - * - * @psalm-return list - */ - public function findBy(array $criteria, array|null $orderBy = null, int|null $limit = null, int|null $offset = null): array - { - $persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName); - - return $persister->loadAll($criteria, $orderBy, $limit, $offset); - } - - /** - * Finds a single entity by a set of criteria. - * - * @psalm-param array $criteria - * @psalm-param array|null $orderBy - * - * @psalm-return T|null - */ - public function findOneBy(array $criteria, array|null $orderBy = null): object|null - { - $persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName); - - return $persister->load($criteria, null, null, [], null, 1, $orderBy); - } - - /** - * Counts entities by a set of criteria. - * - * @psalm-param array $criteria - * - * @return int The cardinality of the objects that match the given criteria. - * - * @todo Add this method to `ObjectRepository` interface in the next major release - */ - public function count(array $criteria = []): int - { - return $this->em->getUnitOfWork()->getEntityPersister($this->entityName)->count($criteria); - } - - /** - * Adds support for magic method calls. - * - * @param mixed[] $arguments - * @psalm-param list $arguments - * - * @throws BadMethodCallException If the method called is invalid. - */ - public function __call(string $method, array $arguments): mixed - { - if (str_starts_with($method, 'findBy')) { - return $this->resolveMagicCall('findBy', substr($method, 6), $arguments); - } - - if (str_starts_with($method, 'findOneBy')) { - return $this->resolveMagicCall('findOneBy', substr($method, 9), $arguments); - } - - if (str_starts_with($method, 'countBy')) { - return $this->resolveMagicCall('count', substr($method, 7), $arguments); - } - - throw new BadMethodCallException(sprintf( - 'Undefined method "%s". The method name must start with ' . - 'either findBy, findOneBy or countBy!', - $method, - )); - } - - /** @psalm-return class-string */ - protected function getEntityName(): string - { - return $this->entityName; - } - - public function getClassName(): string - { - return $this->getEntityName(); - } - - protected function getEntityManager(): EntityManagerInterface - { - return $this->em; - } - - /** @psalm-return ClassMetadata */ - protected function getClassMetadata(): ClassMetadata - { - return $this->class; - } - - /** - * Select all elements from a selectable that match the expression and - * return a new collection containing these elements. - * - * @psalm-return AbstractLazyCollection&Selectable - */ - public function matching(Criteria $criteria): AbstractLazyCollection&Selectable - { - $persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName); - - return new LazyCriteriaCollection($persister, $criteria); - } - - /** - * Resolves a magic method call to the proper existent method at `EntityRepository`. - * - * @param string $method The method to call - * @param string $by The property name used as condition - * @psalm-param list $arguments The arguments to pass at method call - * - * @throws InvalidMagicMethodCall If the method called is invalid or the - * requested field/association does not exist. - */ - private function resolveMagicCall(string $method, string $by, array $arguments): mixed - { - if (! $arguments) { - throw InvalidMagicMethodCall::onMissingParameter($method . $by); - } - - self::$inflector ??= InflectorFactory::create()->build(); - - $fieldName = lcfirst(self::$inflector->classify($by)); - - if (! ($this->class->hasField($fieldName) || $this->class->hasAssociation($fieldName))) { - throw InvalidMagicMethodCall::becauseFieldNotFoundIn( - $this->entityName, - $fieldName, - $method . $by, - ); - } - - return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments, 1)); - } -} diff --git a/vendor/doctrine/orm/src/Event/ListenersInvoker.php b/vendor/doctrine/orm/src/Event/ListenersInvoker.php deleted file mode 100644 index c0c327e..0000000 --- a/vendor/doctrine/orm/src/Event/ListenersInvoker.php +++ /dev/null @@ -1,98 +0,0 @@ -eventManager = $em->getEventManager(); - $this->resolver = $em->getConfiguration()->getEntityListenerResolver(); - } - - /** - * Get the subscribed event systems - * - * @param ClassMetadata $metadata The entity metadata. - * @param string $eventName The entity lifecycle event. - * - * @psalm-return int-mask-of Bitmask of subscribed event systems. - */ - public function getSubscribedSystems(ClassMetadata $metadata, string $eventName): int - { - $invoke = self::INVOKE_NONE; - - if (isset($metadata->lifecycleCallbacks[$eventName])) { - $invoke |= self::INVOKE_CALLBACKS; - } - - if (isset($metadata->entityListeners[$eventName])) { - $invoke |= self::INVOKE_LISTENERS; - } - - if ($this->eventManager->hasListeners($eventName)) { - $invoke |= self::INVOKE_MANAGER; - } - - return $invoke; - } - - /** - * Dispatches the lifecycle event of the given entity. - * - * @param ClassMetadata $metadata The entity metadata. - * @param string $eventName The entity lifecycle event. - * @param object $entity The Entity on which the event occurred. - * @param EventArgs $event The Event args. - * @psalm-param int-mask-of $invoke Bitmask to invoke listeners. - */ - public function invoke( - ClassMetadata $metadata, - string $eventName, - object $entity, - EventArgs $event, - int $invoke, - ): void { - if ($invoke & self::INVOKE_CALLBACKS) { - foreach ($metadata->lifecycleCallbacks[$eventName] as $callback) { - $entity->$callback($event); - } - } - - if ($invoke & self::INVOKE_LISTENERS) { - foreach ($metadata->entityListeners[$eventName] as $listener) { - $class = $listener['class']; - $method = $listener['method']; - $instance = $this->resolver->resolve($class); - - $instance->$method($entity, $event); - } - } - - if ($invoke & self::INVOKE_MANAGER) { - $this->eventManager->dispatchEvent($eventName, $event); - } - } -} diff --git a/vendor/doctrine/orm/src/Event/LoadClassMetadataEventArgs.php b/vendor/doctrine/orm/src/Event/LoadClassMetadataEventArgs.php deleted file mode 100644 index b450616..0000000 --- a/vendor/doctrine/orm/src/Event/LoadClassMetadataEventArgs.php +++ /dev/null @@ -1,25 +0,0 @@ -, EntityManagerInterface> - */ -class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs -{ - /** - * Retrieve associated EntityManager. - */ - public function getEntityManager(): EntityManagerInterface - { - return $this->getObjectManager(); - } -} diff --git a/vendor/doctrine/orm/src/Event/OnClassMetadataNotFoundEventArgs.php b/vendor/doctrine/orm/src/Event/OnClassMetadataNotFoundEventArgs.php deleted file mode 100644 index 762c083..0000000 --- a/vendor/doctrine/orm/src/Event/OnClassMetadataNotFoundEventArgs.php +++ /dev/null @@ -1,49 +0,0 @@ - - */ -class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs -{ - private ClassMetadata|null $foundMetadata = null; - - /** @param EntityManagerInterface $objectManager */ - public function __construct( - private readonly string $className, - ObjectManager $objectManager, - ) { - parent::__construct($objectManager); - } - - public function setFoundMetadata(ClassMetadata|null $classMetadata): void - { - $this->foundMetadata = $classMetadata; - } - - public function getFoundMetadata(): ClassMetadata|null - { - return $this->foundMetadata; - } - - /** - * Retrieve class name for which a failed metadata fetch attempt was executed - */ - public function getClassName(): string - { - return $this->className; - } -} diff --git a/vendor/doctrine/orm/src/Event/OnClearEventArgs.php b/vendor/doctrine/orm/src/Event/OnClearEventArgs.php deleted file mode 100644 index 29a42f2..0000000 --- a/vendor/doctrine/orm/src/Event/OnClearEventArgs.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class OnClearEventArgs extends BaseOnClearEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/OnFlushEventArgs.php b/vendor/doctrine/orm/src/Event/OnFlushEventArgs.php deleted file mode 100644 index b0594ca..0000000 --- a/vendor/doctrine/orm/src/Event/OnFlushEventArgs.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class OnFlushEventArgs extends ManagerEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PostFlushEventArgs.php b/vendor/doctrine/orm/src/Event/PostFlushEventArgs.php deleted file mode 100644 index ca41ba8..0000000 --- a/vendor/doctrine/orm/src/Event/PostFlushEventArgs.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class PostFlushEventArgs extends ManagerEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PostLoadEventArgs.php b/vendor/doctrine/orm/src/Event/PostLoadEventArgs.php deleted file mode 100644 index 8344e68..0000000 --- a/vendor/doctrine/orm/src/Event/PostLoadEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PostLoadEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PostPersistEventArgs.php b/vendor/doctrine/orm/src/Event/PostPersistEventArgs.php deleted file mode 100644 index 926ac1c..0000000 --- a/vendor/doctrine/orm/src/Event/PostPersistEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PostPersistEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PostRemoveEventArgs.php b/vendor/doctrine/orm/src/Event/PostRemoveEventArgs.php deleted file mode 100644 index 8bf857e..0000000 --- a/vendor/doctrine/orm/src/Event/PostRemoveEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PostRemoveEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PostUpdateEventArgs.php b/vendor/doctrine/orm/src/Event/PostUpdateEventArgs.php deleted file mode 100644 index c9ff004..0000000 --- a/vendor/doctrine/orm/src/Event/PostUpdateEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PostUpdateEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PreFlushEventArgs.php b/vendor/doctrine/orm/src/Event/PreFlushEventArgs.php deleted file mode 100644 index 671535c..0000000 --- a/vendor/doctrine/orm/src/Event/PreFlushEventArgs.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class PreFlushEventArgs extends ManagerEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PrePersistEventArgs.php b/vendor/doctrine/orm/src/Event/PrePersistEventArgs.php deleted file mode 100644 index e70c3cf..0000000 --- a/vendor/doctrine/orm/src/Event/PrePersistEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PrePersistEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PreRemoveEventArgs.php b/vendor/doctrine/orm/src/Event/PreRemoveEventArgs.php deleted file mode 100644 index 3af0d02..0000000 --- a/vendor/doctrine/orm/src/Event/PreRemoveEventArgs.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class PreRemoveEventArgs extends LifecycleEventArgs -{ -} diff --git a/vendor/doctrine/orm/src/Event/PreUpdateEventArgs.php b/vendor/doctrine/orm/src/Event/PreUpdateEventArgs.php deleted file mode 100644 index 090487b..0000000 --- a/vendor/doctrine/orm/src/Event/PreUpdateEventArgs.php +++ /dev/null @@ -1,100 +0,0 @@ - - */ -class PreUpdateEventArgs extends LifecycleEventArgs -{ - /** @var array */ - private array $entityChangeSet; - - /** - * @param mixed[][] $changeSet - * @psalm-param array $changeSet - */ - public function __construct(object $entity, EntityManagerInterface $em, array &$changeSet) - { - parent::__construct($entity, $em); - - $this->entityChangeSet = &$changeSet; - } - - /** - * Retrieves entity changeset. - * - * @return mixed[][] - * @psalm-return array - */ - public function getEntityChangeSet(): array - { - return $this->entityChangeSet; - } - - /** - * Checks if field has a changeset. - */ - public function hasChangedField(string $field): bool - { - return isset($this->entityChangeSet[$field]); - } - - /** - * Gets the old value of the changeset of the changed field. - */ - public function getOldValue(string $field): mixed - { - $this->assertValidField($field); - - return $this->entityChangeSet[$field][0]; - } - - /** - * Gets the new value of the changeset of the changed field. - */ - public function getNewValue(string $field): mixed - { - $this->assertValidField($field); - - return $this->entityChangeSet[$field][1]; - } - - /** - * Sets the new value of this field. - */ - public function setNewValue(string $field, mixed $value): void - { - $this->assertValidField($field); - - $this->entityChangeSet[$field][1] = $value; - } - - /** - * Asserts the field exists in changeset. - * - * @throws InvalidArgumentException - */ - private function assertValidField(string $field): void - { - if (! isset($this->entityChangeSet[$field])) { - throw new InvalidArgumentException(sprintf( - 'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.', - $field, - get_debug_type($this->getObject()), - )); - } - } -} diff --git a/vendor/doctrine/orm/src/Events.php b/vendor/doctrine/orm/src/Events.php deleted file mode 100644 index 517917c..0000000 --- a/vendor/doctrine/orm/src/Events.php +++ /dev/null @@ -1,125 +0,0 @@ -getClassMetadata($entity::class); - $idFields = $class->getIdentifierFieldNames(); - $identifier = []; - - foreach ($idFields as $idField) { - $value = $class->getFieldValue($entity, $idField); - - if (! isset($value)) { - throw EntityMissingAssignedId::forField($entity, $idField); - } - - if (isset($class->associationMappings[$idField])) { - // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. - $value = $em->getUnitOfWork()->getSingleIdentifierValue($value); - } - - $identifier[$idField] = $value; - } - - return $identifier; - } -} diff --git a/vendor/doctrine/orm/src/Id/BigIntegerIdentityGenerator.php b/vendor/doctrine/orm/src/Id/BigIntegerIdentityGenerator.php deleted file mode 100644 index 762a7cb..0000000 --- a/vendor/doctrine/orm/src/Id/BigIntegerIdentityGenerator.php +++ /dev/null @@ -1,25 +0,0 @@ -getConnection()->lastInsertId(); - } - - public function isPostInsertGenerator(): bool - { - return true; - } -} diff --git a/vendor/doctrine/orm/src/Id/IdentityGenerator.php b/vendor/doctrine/orm/src/Id/IdentityGenerator.php deleted file mode 100644 index 4610f66..0000000 --- a/vendor/doctrine/orm/src/Id/IdentityGenerator.php +++ /dev/null @@ -1,25 +0,0 @@ -getConnection()->lastInsertId(); - } - - public function isPostInsertGenerator(): bool - { - return true; - } -} diff --git a/vendor/doctrine/orm/src/Id/SequenceGenerator.php b/vendor/doctrine/orm/src/Id/SequenceGenerator.php deleted file mode 100644 index 659bb58..0000000 --- a/vendor/doctrine/orm/src/Id/SequenceGenerator.php +++ /dev/null @@ -1,112 +0,0 @@ -maxValue === null || $this->nextValue === $this->maxValue) { - // Allocate new values - $connection = $em->getConnection(); - $sql = $connection->getDatabasePlatform()->getSequenceNextValSQL($this->sequenceName); - - if ($connection instanceof PrimaryReadReplicaConnection) { - $connection->ensureConnectedToPrimary(); - } - - $this->nextValue = (int) $connection->fetchOne($sql); - $this->maxValue = $this->nextValue + $this->allocationSize; - } - - return $this->nextValue++; - } - - /** - * Gets the maximum value of the currently allocated bag of values. - */ - public function getCurrentMaxValue(): int|null - { - return $this->maxValue; - } - - /** - * Gets the next value that will be returned by generate(). - */ - public function getNextValue(): int - { - return $this->nextValue; - } - - /** @deprecated without replacement. */ - final public function serialize(): string - { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11468', - '%s() is deprecated, use __serialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.', - __METHOD__, - self::class, - ); - - return serialize($this->__serialize()); - } - - /** @return array */ - public function __serialize(): array - { - return [ - 'allocationSize' => $this->allocationSize, - 'sequenceName' => $this->sequenceName, - ]; - } - - /** @deprecated without replacement. */ - final public function unserialize(string $serialized): void - { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11468', - '%s() is deprecated, use __unserialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.', - __METHOD__, - self::class, - ); - - $this->__unserialize(unserialize($serialized)); - } - - /** @param array $data */ - public function __unserialize(array $data): void - { - $this->sequenceName = $data['sequenceName']; - $this->allocationSize = $data['allocationSize']; - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/AbstractHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/AbstractHydrator.php deleted file mode 100644 index d8bffe4..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/AbstractHydrator.php +++ /dev/null @@ -1,556 +0,0 @@ -> - */ - protected array $metadataCache = []; - - /** - * The cache used during row-by-row hydration. - * - * @var array - */ - protected array $cache = []; - - /** - * The statement that provides the data to hydrate. - */ - protected Result|null $stmt = null; - - /** - * The query hints. - * - * @var array - */ - protected array $hints = []; - - /** - * Initializes a new instance of a class derived from AbstractHydrator. - */ - public function __construct(protected EntityManagerInterface $em) - { - $this->platform = $em->getConnection()->getDatabasePlatform(); - $this->uow = $em->getUnitOfWork(); - } - - /** - * Initiates a row-by-row hydration. - * - * @psalm-param array $hints - * - * @return Generator - * - * @final - */ - final public function toIterable(Result $stmt, ResultSetMapping $resultSetMapping, array $hints = []): Generator - { - $this->stmt = $stmt; - $this->rsm = $resultSetMapping; - $this->hints = $hints; - - $evm = $this->em->getEventManager(); - - $evm->addEventListener([Events::onClear], $this); - - $this->prepare(); - - try { - while (true) { - $row = $this->statement()->fetchAssociative(); - - if ($row === false) { - break; - } - - $result = []; - - $this->hydrateRowData($row, $result); - - $this->cleanupAfterRowIteration(); - if (count($result) === 1) { - if (count($resultSetMapping->indexByMap) === 0) { - yield end($result); - } else { - yield from $result; - } - } else { - yield $result; - } - } - } finally { - $this->cleanup(); - } - } - - final protected function statement(): Result - { - if ($this->stmt === null) { - throw new LogicException('Uninitialized _stmt property'); - } - - return $this->stmt; - } - - final protected function resultSetMapping(): ResultSetMapping - { - if ($this->rsm === null) { - throw new LogicException('Uninitialized _rsm property'); - } - - return $this->rsm; - } - - /** - * Hydrates all rows returned by the passed statement instance at once. - * - * @psalm-param array $hints - */ - public function hydrateAll(Result $stmt, ResultSetMapping $resultSetMapping, array $hints = []): mixed - { - $this->stmt = $stmt; - $this->rsm = $resultSetMapping; - $this->hints = $hints; - - $this->em->getEventManager()->addEventListener([Events::onClear], $this); - $this->prepare(); - - try { - $result = $this->hydrateAllData(); - } finally { - $this->cleanup(); - } - - return $result; - } - - /** - * When executed in a hydrate() loop we have to clear internal state to - * decrease memory consumption. - */ - public function onClear(mixed $eventArgs): void - { - } - - /** - * Executes one-time preparation tasks, once each time hydration is started - * through {@link hydrateAll} or {@link toIterable()}. - */ - protected function prepare(): void - { - } - - /** - * Executes one-time cleanup tasks at the end of a hydration that was initiated - * through {@link hydrateAll} or {@link toIterable()}. - */ - protected function cleanup(): void - { - $this->statement()->free(); - - $this->stmt = null; - $this->rsm = null; - $this->cache = []; - $this->metadataCache = []; - - $this - ->em - ->getEventManager() - ->removeEventListener([Events::onClear], $this); - } - - protected function cleanupAfterRowIteration(): void - { - } - - /** - * Hydrates a single row from the current statement instance. - * - * Template method. - * - * @param mixed[] $row The row data. - * @param mixed[] $result The result to fill. - * - * @throws HydrationException - */ - protected function hydrateRowData(array $row, array &$result): void - { - throw new HydrationException('hydrateRowData() not implemented by this hydrator.'); - } - - /** - * Hydrates all rows from the current statement instance at once. - */ - abstract protected function hydrateAllData(): mixed; - - /** - * Processes a row of the result set. - * - * Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY). - * Puts the elements of a result row into a new array, grouped by the dql alias - * they belong to. The column names in the result set are mapped to their - * field names during this procedure as well as any necessary conversions on - * the values applied. Scalar values are kept in a specific key 'scalars'. - * - * @param mixed[] $data SQL Result Row. - * @psalm-param array $id Dql-Alias => ID-Hash. - * @psalm-param array $nonemptyComponents Does this DQL-Alias has at least one non NULL value? - * - * @return array> An array with all the fields - * (name => value) of the data - * row, grouped by their - * component alias. - * @psalm-return array{ - * data: array, - * newObjects?: array, - * scalars?: array - * } - */ - protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents): array - { - $rowData = ['data' => []]; - - foreach ($data as $key => $value) { - $cacheKeyInfo = $this->hydrateColumnInfo($key); - if ($cacheKeyInfo === null) { - continue; - } - - $fieldName = $cacheKeyInfo['fieldName']; - - switch (true) { - case isset($cacheKeyInfo['isNewObjectParameter']): - $argIndex = $cacheKeyInfo['argIndex']; - $objIndex = $cacheKeyInfo['objIndex']; - $type = $cacheKeyInfo['type']; - $value = $type->convertToPHPValue($value, $this->platform); - - if ($value !== null && isset($cacheKeyInfo['enumType'])) { - $value = $this->buildEnum($value, $cacheKeyInfo['enumType']); - } - - $rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class']; - $rowData['newObjects'][$objIndex]['args'][$argIndex] = $value; - break; - - case isset($cacheKeyInfo['isScalar']): - $type = $cacheKeyInfo['type']; - $value = $type->convertToPHPValue($value, $this->platform); - - if ($value !== null && isset($cacheKeyInfo['enumType'])) { - $value = $this->buildEnum($value, $cacheKeyInfo['enumType']); - } - - $rowData['scalars'][$fieldName] = $value; - - break; - - //case (isset($cacheKeyInfo['isMetaColumn'])): - default: - $dqlAlias = $cacheKeyInfo['dqlAlias']; - $type = $cacheKeyInfo['type']; - - // If there are field name collisions in the child class, then we need - // to only hydrate if we are looking at the correct discriminator value - if ( - isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']]) - && ! in_array((string) $data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'], true) - ) { - break; - } - - // in an inheritance hierarchy the same field could be defined several times. - // We overwrite this value so long we don't have a non-null value, that value we keep. - // Per definition it cannot be that a field is defined several times and has several values. - if (isset($rowData['data'][$dqlAlias][$fieldName])) { - break; - } - - $rowData['data'][$dqlAlias][$fieldName] = $type - ? $type->convertToPHPValue($value, $this->platform) - : $value; - - if ($rowData['data'][$dqlAlias][$fieldName] !== null && isset($cacheKeyInfo['enumType'])) { - $rowData['data'][$dqlAlias][$fieldName] = $this->buildEnum($rowData['data'][$dqlAlias][$fieldName], $cacheKeyInfo['enumType']); - } - - if ($cacheKeyInfo['isIdentifier'] && $value !== null) { - $id[$dqlAlias] .= '|' . $value; - $nonemptyComponents[$dqlAlias] = true; - } - - break; - } - } - - return $rowData; - } - - /** - * Processes a row of the result set. - * - * Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that - * simply converts column names to field names and properly converts the - * values according to their types. The resulting row has the same number - * of elements as before. - * - * @param mixed[] $data - * @psalm-param array $data - * - * @return mixed[] The processed row. - * @psalm-return array - */ - protected function gatherScalarRowData(array &$data): array - { - $rowData = []; - - foreach ($data as $key => $value) { - $cacheKeyInfo = $this->hydrateColumnInfo($key); - if ($cacheKeyInfo === null) { - continue; - } - - $fieldName = $cacheKeyInfo['fieldName']; - - // WARNING: BC break! We know this is the desired behavior to type convert values, but this - // erroneous behavior exists since 2.0 and we're forced to keep compatibility. - if (! isset($cacheKeyInfo['isScalar'])) { - $type = $cacheKeyInfo['type']; - $value = $type ? $type->convertToPHPValue($value, $this->platform) : $value; - - $fieldName = $cacheKeyInfo['dqlAlias'] . '_' . $fieldName; - } - - $rowData[$fieldName] = $value; - } - - return $rowData; - } - - /** - * Retrieve column information from ResultSetMapping. - * - * @param string $key Column name - * - * @return mixed[]|null - * @psalm-return array|null - */ - protected function hydrateColumnInfo(string $key): array|null - { - if (isset($this->cache[$key])) { - return $this->cache[$key]; - } - - switch (true) { - // NOTE: Most of the times it's a field mapping, so keep it first!!! - case isset($this->rsm->fieldMappings[$key]): - $classMetadata = $this->getClassMetadata($this->rsm->declaringClasses[$key]); - $fieldName = $this->rsm->fieldMappings[$key]; - $fieldMapping = $classMetadata->fieldMappings[$fieldName]; - $ownerMap = $this->rsm->columnOwnerMap[$key]; - $columnInfo = [ - 'isIdentifier' => in_array($fieldName, $classMetadata->identifier, true), - 'fieldName' => $fieldName, - 'type' => Type::getType($fieldMapping->type), - 'dqlAlias' => $ownerMap, - 'enumType' => $this->rsm->enumMappings[$key] ?? null, - ]; - - // the current discriminator value must be saved in order to disambiguate fields hydration, - // should there be field name collisions - if ($classMetadata->parentClasses && isset($this->rsm->discriminatorColumns[$ownerMap])) { - return $this->cache[$key] = array_merge( - $columnInfo, - [ - 'discriminatorColumn' => $this->rsm->discriminatorColumns[$ownerMap], - 'discriminatorValue' => $classMetadata->discriminatorValue, - 'discriminatorValues' => $this->getDiscriminatorValues($classMetadata), - ], - ); - } - - return $this->cache[$key] = $columnInfo; - - case isset($this->rsm->newObjectMappings[$key]): - // WARNING: A NEW object is also a scalar, so it must be declared before! - $mapping = $this->rsm->newObjectMappings[$key]; - - return $this->cache[$key] = [ - 'isScalar' => true, - 'isNewObjectParameter' => true, - 'fieldName' => $this->rsm->scalarMappings[$key], - 'type' => Type::getType($this->rsm->typeMappings[$key]), - 'argIndex' => $mapping['argIndex'], - 'objIndex' => $mapping['objIndex'], - 'class' => new ReflectionClass($mapping['className']), - 'enumType' => $this->rsm->enumMappings[$key] ?? null, - ]; - - case isset($this->rsm->scalarMappings[$key], $this->hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]): - return $this->cache[$key] = [ - 'fieldName' => $this->rsm->scalarMappings[$key], - 'type' => Type::getType($this->rsm->typeMappings[$key]), - 'dqlAlias' => '', - 'enumType' => $this->rsm->enumMappings[$key] ?? null, - ]; - - case isset($this->rsm->scalarMappings[$key]): - return $this->cache[$key] = [ - 'isScalar' => true, - 'fieldName' => $this->rsm->scalarMappings[$key], - 'type' => Type::getType($this->rsm->typeMappings[$key]), - 'enumType' => $this->rsm->enumMappings[$key] ?? null, - ]; - - case isset($this->rsm->metaMappings[$key]): - // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). - $fieldName = $this->rsm->metaMappings[$key]; - $dqlAlias = $this->rsm->columnOwnerMap[$key]; - $type = isset($this->rsm->typeMappings[$key]) - ? Type::getType($this->rsm->typeMappings[$key]) - : null; - - // Cache metadata fetch - $this->getClassMetadata($this->rsm->aliasMap[$dqlAlias]); - - return $this->cache[$key] = [ - 'isIdentifier' => isset($this->rsm->isIdentifierColumn[$dqlAlias][$key]), - 'isMetaColumn' => true, - 'fieldName' => $fieldName, - 'type' => $type, - 'dqlAlias' => $dqlAlias, - 'enumType' => $this->rsm->enumMappings[$key] ?? null, - ]; - } - - // this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2 - // maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping. - return null; - } - - /** - * @return string[] - * @psalm-return non-empty-list - */ - private function getDiscriminatorValues(ClassMetadata $classMetadata): array - { - $values = array_map( - fn (string $subClass): string => (string) $this->getClassMetadata($subClass)->discriminatorValue, - $classMetadata->subClasses, - ); - - $values[] = (string) $classMetadata->discriminatorValue; - - return $values; - } - - /** - * Retrieve ClassMetadata associated to entity class name. - */ - protected function getClassMetadata(string $className): ClassMetadata - { - if (! isset($this->metadataCache[$className])) { - $this->metadataCache[$className] = $this->em->getClassMetadata($className); - } - - return $this->metadataCache[$className]; - } - - /** - * Register entity as managed in UnitOfWork. - * - * @param mixed[] $data - * - * @todo The "$id" generation is the same of UnitOfWork#createEntity. Remove this duplication somehow - */ - protected function registerManaged(ClassMetadata $class, object $entity, array $data): void - { - if ($class->isIdentifierComposite) { - $id = []; - - foreach ($class->identifier as $fieldName) { - $id[$fieldName] = isset($class->associationMappings[$fieldName]) && $class->associationMappings[$fieldName]->isToOneOwningSide() - ? $data[$class->associationMappings[$fieldName]->joinColumns[0]->name] - : $data[$fieldName]; - } - } else { - $fieldName = $class->identifier[0]; - $id = [ - $fieldName => isset($class->associationMappings[$fieldName]) && $class->associationMappings[$fieldName]->isToOneOwningSide() - ? $data[$class->associationMappings[$fieldName]->joinColumns[0]->name] - : $data[$fieldName], - ]; - } - - $this->em->getUnitOfWork()->registerManaged($entity, $id, $data); - } - - /** - * @param class-string $enumType - * - * @return BackedEnum|array - */ - final protected function buildEnum(mixed $value, string $enumType): BackedEnum|array - { - if (is_array($value)) { - return array_map( - static fn ($value) => $enumType::from($value), - $value, - ); - } - - return $enumType::from($value); - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/ArrayHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/ArrayHydrator.php deleted file mode 100644 index 7115c16..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/ArrayHydrator.php +++ /dev/null @@ -1,270 +0,0 @@ - */ - private array $rootAliases = []; - - private bool $isSimpleQuery = false; - - /** @var mixed[] */ - private array $identifierMap = []; - - /** @var mixed[] */ - private array $resultPointers = []; - - /** @var array */ - private array $idTemplate = []; - - private int $resultCounter = 0; - - protected function prepare(): void - { - $this->isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1; - - foreach ($this->resultSetMapping()->aliasMap as $dqlAlias => $className) { - $this->identifierMap[$dqlAlias] = []; - $this->resultPointers[$dqlAlias] = []; - $this->idTemplate[$dqlAlias] = ''; - } - } - - /** - * {@inheritDoc} - */ - protected function hydrateAllData(): array - { - $result = []; - - while ($data = $this->statement()->fetchAssociative()) { - $this->hydrateRowData($data, $result); - } - - return $result; - } - - /** - * {@inheritDoc} - */ - protected function hydrateRowData(array $row, array &$result): void - { - // 1) Initialize - $id = $this->idTemplate; // initialize the id-memory - $nonemptyComponents = []; - $rowData = $this->gatherRowData($row, $id, $nonemptyComponents); - - // 2) Now hydrate the data found in the current row. - foreach ($rowData['data'] as $dqlAlias => $data) { - $index = false; - - if (isset($this->resultSetMapping()->parentAliasMap[$dqlAlias])) { - // It's a joined result - - $parent = $this->resultSetMapping()->parentAliasMap[$dqlAlias]; - $path = $parent . '.' . $dqlAlias; - - // missing parent data, skipping as RIGHT JOIN hydration is not supported. - if (! isset($nonemptyComponents[$parent])) { - continue; - } - - // Get a reference to the right element in the result tree. - // This element will get the associated element attached. - if ($this->resultSetMapping()->isMixed && isset($this->rootAliases[$parent])) { - $first = reset($this->resultPointers); - // TODO: Exception if $key === null ? - $baseElement =& $this->resultPointers[$parent][key($first)]; - } elseif (isset($this->resultPointers[$parent])) { - $baseElement =& $this->resultPointers[$parent]; - } else { - unset($this->resultPointers[$dqlAlias]); // Ticket #1228 - - continue; - } - - $relationAlias = $this->resultSetMapping()->relationMap[$dqlAlias]; - $parentClass = $this->metadataCache[$this->resultSetMapping()->aliasMap[$parent]]; - $relation = $parentClass->associationMappings[$relationAlias]; - - // Check the type of the relation (many or single-valued) - if (! $relation->isToOne()) { - $oneToOne = false; - - if (! isset($baseElement[$relationAlias])) { - $baseElement[$relationAlias] = []; - } - - if (isset($nonemptyComponents[$dqlAlias])) { - $indexExists = isset($this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); - $index = $indexExists ? $this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; - $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; - - if (! $indexExists || ! $indexIsValid) { - $element = $data; - - if (isset($this->resultSetMapping()->indexByMap[$dqlAlias])) { - $baseElement[$relationAlias][$row[$this->resultSetMapping()->indexByMap[$dqlAlias]]] = $element; - } else { - $baseElement[$relationAlias][] = $element; - } - - $this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = array_key_last($baseElement[$relationAlias]); - } - } - } else { - $oneToOne = true; - - if ( - ! isset($nonemptyComponents[$dqlAlias]) && - ( ! isset($baseElement[$relationAlias])) - ) { - $baseElement[$relationAlias] = null; - } elseif (! isset($baseElement[$relationAlias])) { - $baseElement[$relationAlias] = $data; - } - } - - $coll =& $baseElement[$relationAlias]; - - if (is_array($coll)) { - $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); - } - } else { - // It's a root result element - - $this->rootAliases[$dqlAlias] = true; // Mark as root - $entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0; - - // if this row has a NULL value for the root result id then make it a null result. - if (! isset($nonemptyComponents[$dqlAlias])) { - $result[] = $this->resultSetMapping()->isMixed - ? [$entityKey => null] - : null; - - $resultKey = $this->resultCounter; - ++$this->resultCounter; - - continue; - } - - // Check for an existing element - if ($this->isSimpleQuery || ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) { - $element = $this->resultSetMapping()->isMixed - ? [$entityKey => $data] - : $data; - - if (isset($this->resultSetMapping()->indexByMap[$dqlAlias])) { - $resultKey = $row[$this->resultSetMapping()->indexByMap[$dqlAlias]]; - $result[$resultKey] = $element; - } else { - $resultKey = $this->resultCounter; - $result[] = $element; - - ++$this->resultCounter; - } - - $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey; - } else { - $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]]; - $resultKey = $index; - } - - $this->updateResultPointer($result, $index, $dqlAlias, false); - } - } - - if (! isset($resultKey)) { - $this->resultCounter++; - } - - // Append scalar values to mixed result sets - if (isset($rowData['scalars'])) { - if (! isset($resultKey)) { - // this only ever happens when no object is fetched (scalar result only) - $resultKey = isset($this->resultSetMapping()->indexByMap['scalars']) - ? $row[$this->resultSetMapping()->indexByMap['scalars']] - : $this->resultCounter - 1; - } - - foreach ($rowData['scalars'] as $name => $value) { - $result[$resultKey][$name] = $value; - } - } - - // Append new object to mixed result sets - if (isset($rowData['newObjects'])) { - if (! isset($resultKey)) { - $resultKey = $this->resultCounter - 1; - } - - $scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0); - - foreach ($rowData['newObjects'] as $objIndex => $newObject) { - $class = $newObject['class']; - $args = $newObject['args']; - $obj = $class->newInstanceArgs($args); - - if (count($args) === $scalarCount || ($scalarCount === 0 && count($rowData['newObjects']) === 1)) { - $result[$resultKey] = $obj; - - continue; - } - - $result[$resultKey][$objIndex] = $obj; - } - } - } - - /** - * Updates the result pointer for an Entity. The result pointers point to the - * last seen instance of each Entity type. This is used for graph construction. - * - * @param mixed[]|null $coll The element. - * @param string|int|false $index Index of the element in the collection. - * @param bool $oneToOne Whether it is a single-valued association or not. - */ - private function updateResultPointer( - array|null &$coll, - string|int|false $index, - string $dqlAlias, - bool $oneToOne, - ): void { - if ($coll === null) { - unset($this->resultPointers[$dqlAlias]); // Ticket #1228 - - return; - } - - if ($oneToOne) { - $this->resultPointers[$dqlAlias] =& $coll; - - return; - } - - if ($index !== false) { - $this->resultPointers[$dqlAlias] =& $coll[$index]; - - return; - } - - if (! $coll) { - return; - } - - $this->resultPointers[$dqlAlias] =& $coll[array_key_last($coll)]; - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/HydrationException.php b/vendor/doctrine/orm/src/Internal/Hydration/HydrationException.php deleted file mode 100644 index 710114f..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/HydrationException.php +++ /dev/null @@ -1,67 +0,0 @@ - $discrValues */ - public static function invalidDiscriminatorValue(string $discrValue, array $discrValues): self - { - return new self(sprintf( - 'The discriminator value "%s" is invalid. It must be one of "%s".', - $discrValue, - implode('", "', $discrValues), - )); - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/ObjectHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/ObjectHydrator.php deleted file mode 100644 index d0fc101..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/ObjectHydrator.php +++ /dev/null @@ -1,586 +0,0 @@ - */ - private array $uninitializedCollections = []; - - /** @var mixed[] */ - private array $existingCollections = []; - - protected function prepare(): void - { - if (! isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) { - $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true; - } - - foreach ($this->resultSetMapping()->aliasMap as $dqlAlias => $className) { - $this->identifierMap[$dqlAlias] = []; - $this->idTemplate[$dqlAlias] = ''; - - // Remember which associations are "fetch joined", so that we know where to inject - // collection stubs or proxies and where not. - if (! isset($this->resultSetMapping()->relationMap[$dqlAlias])) { - continue; - } - - $parent = $this->resultSetMapping()->parentAliasMap[$dqlAlias]; - - if (! isset($this->resultSetMapping()->aliasMap[$parent])) { - throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent); - } - - $sourceClassName = $this->resultSetMapping()->aliasMap[$parent]; - $sourceClass = $this->getClassMetadata($sourceClassName); - $assoc = $sourceClass->associationMappings[$this->resultSetMapping()->relationMap[$dqlAlias]]; - - $this->hints['fetched'][$parent][$assoc->fieldName] = true; - - if ($assoc->isManyToMany()) { - continue; - } - - // Mark any non-collection opposite sides as fetched, too. - if (! $assoc->isOwningSide()) { - $this->hints['fetched'][$dqlAlias][$assoc->mappedBy] = true; - - continue; - } - - // handle fetch-joined owning side bi-directional one-to-one associations - if ($assoc->inversedBy !== null) { - $class = $this->getClassMetadata($className); - $inverseAssoc = $class->associationMappings[$assoc->inversedBy]; - - if (! $inverseAssoc->isToOne()) { - continue; - } - - $this->hints['fetched'][$dqlAlias][$inverseAssoc->fieldName] = true; - } - } - } - - protected function cleanup(): void - { - $eagerLoad = isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD]) && $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true; - - parent::cleanup(); - - $this->identifierMap = - $this->initializedCollections = - $this->uninitializedCollections = - $this->existingCollections = - $this->resultPointers = []; - - if ($eagerLoad) { - $this->uow->triggerEagerLoads(); - } - - $this->uow->hydrationComplete(); - } - - protected function cleanupAfterRowIteration(): void - { - $this->identifierMap = - $this->initializedCollections = - $this->uninitializedCollections = - $this->existingCollections = - $this->resultPointers = []; - } - - /** - * {@inheritDoc} - */ - protected function hydrateAllData(): array - { - $result = []; - - while ($row = $this->statement()->fetchAssociative()) { - $this->hydrateRowData($row, $result); - } - - // Take snapshots from all newly initialized collections - foreach ($this->initializedCollections as $coll) { - $coll->takeSnapshot(); - } - - foreach ($this->uninitializedCollections as $coll) { - if (! $coll->isInitialized()) { - $coll->setInitialized(true); - } - } - - return $result; - } - - /** - * Initializes a related collection. - * - * @param string $fieldName The name of the field on the entity that holds the collection. - * @param string $parentDqlAlias Alias of the parent fetch joining this collection. - */ - private function initRelatedCollection( - object $entity, - ClassMetadata $class, - string $fieldName, - string $parentDqlAlias, - ): PersistentCollection { - $oid = spl_object_id($entity); - $relation = $class->associationMappings[$fieldName]; - $value = $class->reflFields[$fieldName]->getValue($entity); - - if ($value === null || is_array($value)) { - $value = new ArrayCollection((array) $value); - } - - if (! $value instanceof PersistentCollection) { - assert($relation->isToMany()); - $value = new PersistentCollection( - $this->em, - $this->metadataCache[$relation->targetEntity], - $value, - ); - $value->setOwner($entity, $relation); - - $class->reflFields[$fieldName]->setValue($entity, $value); - $this->uow->setOriginalEntityProperty($oid, $fieldName, $value); - - $this->initializedCollections[$oid . $fieldName] = $value; - } elseif ( - isset($this->hints[Query::HINT_REFRESH]) || - isset($this->hints['fetched'][$parentDqlAlias][$fieldName]) && - ! $value->isInitialized() - ) { - // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED! - $value->setDirty(false); - $value->setInitialized(true); - $value->unwrap()->clear(); - - $this->initializedCollections[$oid . $fieldName] = $value; - } else { - // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN! - $this->existingCollections[$oid . $fieldName] = $value; - } - - return $value; - } - - /** - * Gets an entity instance. - * - * @param string $dqlAlias The DQL alias of the entity's class. - * @psalm-param array $data The instance data. - * - * @throws HydrationException - */ - private function getEntity(array $data, string $dqlAlias): object - { - $className = $this->resultSetMapping()->aliasMap[$dqlAlias]; - - if (isset($this->resultSetMapping()->discriminatorColumns[$dqlAlias])) { - $fieldName = $this->resultSetMapping()->discriminatorColumns[$dqlAlias]; - - if (! isset($this->resultSetMapping()->metaMappings[$fieldName])) { - throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias); - } - - $discrColumn = $this->resultSetMapping()->metaMappings[$fieldName]; - - if (! isset($data[$discrColumn])) { - throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias); - } - - if ($data[$discrColumn] === '') { - throw HydrationException::emptyDiscriminatorValue($dqlAlias); - } - - $discrMap = $this->metadataCache[$className]->discriminatorMap; - $discriminatorValue = $data[$discrColumn]; - if ($discriminatorValue instanceof BackedEnum) { - $discriminatorValue = $discriminatorValue->value; - } - - $discriminatorValue = (string) $discriminatorValue; - - if (! isset($discrMap[$discriminatorValue])) { - throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap)); - } - - $className = $discrMap[$discriminatorValue]; - - unset($data[$discrColumn]); - } - - if (isset($this->hints[Query::HINT_REFRESH_ENTITY], $this->rootAliases[$dqlAlias])) { - $this->registerManaged($this->metadataCache[$className], $this->hints[Query::HINT_REFRESH_ENTITY], $data); - } - - $this->hints['fetchAlias'] = $dqlAlias; - - return $this->uow->createEntity($className, $data, $this->hints); - } - - /** - * @psalm-param class-string $className - * @psalm-param array $data - */ - private function getEntityFromIdentityMap(string $className, array $data): object|bool - { - // TODO: Abstract this code and UnitOfWork::createEntity() equivalent? - $class = $this->metadataCache[$className]; - - if ($class->isIdentifierComposite) { - $idHash = UnitOfWork::getIdHashByIdentifier( - array_map( - /** @return mixed */ - static fn (string $fieldName) => isset($class->associationMappings[$fieldName]) && assert($class->associationMappings[$fieldName]->isToOneOwningSide()) - ? $data[$class->associationMappings[$fieldName]->joinColumns[0]->name] - : $data[$fieldName], - $class->identifier, - ), - ); - - return $this->uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName); - } elseif (isset($class->associationMappings[$class->identifier[0]])) { - $association = $class->associationMappings[$class->identifier[0]]; - assert($association->isToOneOwningSide()); - - return $this->uow->tryGetByIdHash($data[$association->joinColumns[0]->name], $class->rootEntityName); - } - - return $this->uow->tryGetByIdHash($data[$class->identifier[0]], $class->rootEntityName); - } - - /** - * Hydrates a single row in an SQL result set. - * - * @internal - * First, the data of the row is split into chunks where each chunk contains data - * that belongs to a particular component/class. Afterwards, all these chunks - * are processed, one after the other. For each chunk of class data only one of the - * following code paths is executed: - * Path A: The data chunk belongs to a joined/associated object and the association - * is collection-valued. - * Path B: The data chunk belongs to a joined/associated object and the association - * is single-valued. - * Path C: The data chunk belongs to a root result element/object that appears in the topmost - * level of the hydrated result. A typical example are the objects of the type - * specified by the FROM clause in a DQL query. - * - * @param mixed[] $row The data of the row to process. - * @param mixed[] $result The result array to fill. - */ - protected function hydrateRowData(array $row, array &$result): void - { - // Initialize - $id = $this->idTemplate; // initialize the id-memory - $nonemptyComponents = []; - // Split the row data into chunks of class data. - $rowData = $this->gatherRowData($row, $id, $nonemptyComponents); - - // reset result pointers for each data row - $this->resultPointers = []; - - // Hydrate the data chunks - foreach ($rowData['data'] as $dqlAlias => $data) { - $entityName = $this->resultSetMapping()->aliasMap[$dqlAlias]; - - if (isset($this->resultSetMapping()->parentAliasMap[$dqlAlias])) { - // It's a joined result - - $parentAlias = $this->resultSetMapping()->parentAliasMap[$dqlAlias]; - // we need the $path to save into the identifier map which entities were already - // seen for this parent-child relationship - $path = $parentAlias . '.' . $dqlAlias; - - // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs - if (! isset($nonemptyComponents[$parentAlias])) { - // TODO: Add special case code where we hydrate the right join objects into identity map at least - continue; - } - - $parentClass = $this->metadataCache[$this->resultSetMapping()->aliasMap[$parentAlias]]; - $relationField = $this->resultSetMapping()->relationMap[$dqlAlias]; - $relation = $parentClass->associationMappings[$relationField]; - $reflField = $parentClass->reflFields[$relationField]; - - // Get a reference to the parent object to which the joined element belongs. - if ($this->resultSetMapping()->isMixed && isset($this->rootAliases[$parentAlias])) { - $objectClass = $this->resultPointers[$parentAlias]; - $parentObject = $objectClass[key($objectClass)]; - } elseif (isset($this->resultPointers[$parentAlias])) { - $parentObject = $this->resultPointers[$parentAlias]; - } else { - // Parent object of relation not found, mark as not-fetched again - if (isset($nonemptyComponents[$dqlAlias])) { - $element = $this->getEntity($data, $dqlAlias); - - // Update result pointer and provide initial fetch data for parent - $this->resultPointers[$dqlAlias] = $element; - $rowData['data'][$parentAlias][$relationField] = $element; - } else { - $element = null; - } - - // Mark as not-fetched again - unset($this->hints['fetched'][$parentAlias][$relationField]); - continue; - } - - $oid = spl_object_id($parentObject); - - // Check the type of the relation (many or single-valued) - if (! $relation->isToOne()) { - // PATH A: Collection-valued association - $reflFieldValue = $reflField->getValue($parentObject); - - if (isset($nonemptyComponents[$dqlAlias])) { - $collKey = $oid . $relationField; - if (isset($this->initializedCollections[$collKey])) { - $reflFieldValue = $this->initializedCollections[$collKey]; - } elseif (! isset($this->existingCollections[$collKey])) { - $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias); - } - - $indexExists = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]); - $index = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false; - $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false; - - if (! $indexExists || ! $indexIsValid) { - if (isset($this->existingCollections[$collKey])) { - // Collection exists, only look for the element in the identity map. - $element = $this->getEntityFromIdentityMap($entityName, $data); - if ($element) { - $this->resultPointers[$dqlAlias] = $element; - } else { - unset($this->resultPointers[$dqlAlias]); - } - } else { - $element = $this->getEntity($data, $dqlAlias); - - if (isset($this->resultSetMapping()->indexByMap[$dqlAlias])) { - $indexValue = $row[$this->resultSetMapping()->indexByMap[$dqlAlias]]; - $reflFieldValue->hydrateSet($indexValue, $element); - $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue; - } else { - if (! $reflFieldValue->contains($element)) { - $reflFieldValue->hydrateAdd($element); - $reflFieldValue->last(); - } - - $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key(); - } - - // Update result pointer - $this->resultPointers[$dqlAlias] = $element; - } - } else { - // Update result pointer - $this->resultPointers[$dqlAlias] = $reflFieldValue[$index]; - } - } elseif (! $reflFieldValue) { - $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias); - } elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false && ! isset($this->uninitializedCollections[$oid . $relationField])) { - $this->uninitializedCollections[$oid . $relationField] = $reflFieldValue; - } - } else { - // PATH B: Single-valued association - $reflFieldValue = $reflField->getValue($parentObject); - - if (! $reflFieldValue || isset($this->hints[Query::HINT_REFRESH]) || $this->uow->isUninitializedObject($reflFieldValue)) { - // we only need to take action if this value is null, - // we refresh the entity or its an uninitialized proxy. - if (isset($nonemptyComponents[$dqlAlias])) { - $element = $this->getEntity($data, $dqlAlias); - $reflField->setValue($parentObject, $element); - $this->uow->setOriginalEntityProperty($oid, $relationField, $element); - $targetClass = $this->metadataCache[$relation->targetEntity]; - - if ($relation->isOwningSide()) { - // TODO: Just check hints['fetched'] here? - // If there is an inverse mapping on the target class its bidirectional - if ($relation->inversedBy !== null) { - $inverseAssoc = $targetClass->associationMappings[$relation->inversedBy]; - if ($inverseAssoc->isToOne()) { - $targetClass->reflFields[$inverseAssoc->fieldName]->setValue($element, $parentObject); - $this->uow->setOriginalEntityProperty(spl_object_id($element), $inverseAssoc->fieldName, $parentObject); - } - } - } else { - // For sure bidirectional, as there is no inverse side in unidirectional mappings - $targetClass->reflFields[$relation->mappedBy]->setValue($element, $parentObject); - $this->uow->setOriginalEntityProperty(spl_object_id($element), $relation->mappedBy, $parentObject); - } - - // Update result pointer - $this->resultPointers[$dqlAlias] = $element; - } else { - $this->uow->setOriginalEntityProperty($oid, $relationField, null); - $reflField->setValue($parentObject, null); - } - // else leave $reflFieldValue null for single-valued associations - } else { - // Update result pointer - $this->resultPointers[$dqlAlias] = $reflFieldValue; - } - } - } else { - // PATH C: Its a root result element - $this->rootAliases[$dqlAlias] = true; // Mark as root alias - $entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0; - - // if this row has a NULL value for the root result id then make it a null result. - if (! isset($nonemptyComponents[$dqlAlias])) { - if ($this->resultSetMapping()->isMixed) { - $result[] = [$entityKey => null]; - } else { - $result[] = null; - } - - $resultKey = $this->resultCounter; - ++$this->resultCounter; - continue; - } - - // check for existing result from the iterations before - if (! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) { - $element = $this->getEntity($data, $dqlAlias); - - if ($this->resultSetMapping()->isMixed) { - $element = [$entityKey => $element]; - } - - if (isset($this->resultSetMapping()->indexByMap[$dqlAlias])) { - $resultKey = $row[$this->resultSetMapping()->indexByMap[$dqlAlias]]; - - if (isset($this->hints['collection'])) { - $this->hints['collection']->hydrateSet($resultKey, $element); - } - - $result[$resultKey] = $element; - } else { - $resultKey = $this->resultCounter; - ++$this->resultCounter; - - if (isset($this->hints['collection'])) { - $this->hints['collection']->hydrateAdd($element); - } - - $result[] = $element; - } - - $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey; - - // Update result pointer - $this->resultPointers[$dqlAlias] = $element; - } else { - // Update result pointer - $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]]; - $this->resultPointers[$dqlAlias] = $result[$index]; - $resultKey = $index; - } - } - - if (isset($this->hints[Query::HINT_INTERNAL_ITERATION]) && $this->hints[Query::HINT_INTERNAL_ITERATION]) { - $this->uow->hydrationComplete(); - } - } - - if (! isset($resultKey)) { - $this->resultCounter++; - } - - // Append scalar values to mixed result sets - if (isset($rowData['scalars'])) { - if (! isset($resultKey)) { - $resultKey = isset($this->resultSetMapping()->indexByMap['scalars']) - ? $row[$this->resultSetMapping()->indexByMap['scalars']] - : $this->resultCounter - 1; - } - - foreach ($rowData['scalars'] as $name => $value) { - $result[$resultKey][$name] = $value; - } - } - - // Append new object to mixed result sets - if (isset($rowData['newObjects'])) { - if (! isset($resultKey)) { - $resultKey = $this->resultCounter - 1; - } - - $scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0); - - foreach ($rowData['newObjects'] as $objIndex => $newObject) { - $class = $newObject['class']; - $args = $newObject['args']; - $obj = $class->newInstanceArgs($args); - - if ($scalarCount === 0 && count($rowData['newObjects']) === 1) { - $result[$resultKey] = $obj; - - continue; - } - - $result[$resultKey][$objIndex] = $obj; - } - } - } - - /** - * When executed in a hydrate() loop we may have to clear internal state to - * decrease memory consumption. - */ - public function onClear(mixed $eventArgs): void - { - parent::onClear($eventArgs); - - $aliases = array_keys($this->identifierMap); - - $this->identifierMap = array_fill_keys($aliases, []); - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/ScalarColumnHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/ScalarColumnHydrator.php deleted file mode 100644 index 0f10fb4..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/ScalarColumnHydrator.php +++ /dev/null @@ -1,34 +0,0 @@ -resultSetMapping()->fieldMappings) > 1) { - throw MultipleSelectorsFoundException::create($this->resultSetMapping()->fieldMappings); - } - - $result = $this->statement()->fetchAllNumeric(); - - return array_column($result, 0); - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/ScalarHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/ScalarHydrator.php deleted file mode 100644 index 15f3e7e..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/ScalarHydrator.php +++ /dev/null @@ -1,35 +0,0 @@ -statement()->fetchAssociative()) { - $this->hydrateRowData($data, $result); - } - - return $result; - } - - /** - * {@inheritDoc} - */ - protected function hydrateRowData(array $row, array &$result): void - { - $result[] = $this->gatherScalarRowData($row); - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/SimpleObjectHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/SimpleObjectHydrator.php deleted file mode 100644 index eab7b9b..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/SimpleObjectHydrator.php +++ /dev/null @@ -1,176 +0,0 @@ -resultSetMapping()->aliasMap) !== 1) { - throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.'); - } - - if ($this->resultSetMapping()->scalarMappings) { - throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.'); - } - - $this->class = $this->getClassMetadata(reset($this->resultSetMapping()->aliasMap)); - } - - protected function cleanup(): void - { - parent::cleanup(); - - $this->uow->triggerEagerLoads(); - $this->uow->hydrationComplete(); - } - - /** - * {@inheritDoc} - */ - protected function hydrateAllData(): array - { - $result = []; - - while ($row = $this->statement()->fetchAssociative()) { - $this->hydrateRowData($row, $result); - } - - $this->em->getUnitOfWork()->triggerEagerLoads(); - - return $result; - } - - /** - * {@inheritDoc} - */ - protected function hydrateRowData(array $row, array &$result): void - { - assert($this->class !== null); - $entityName = $this->class->name; - $data = []; - $discrColumnValue = null; - - // We need to find the correct entity class name if we have inheritance in resultset - if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { - $discrColumn = $this->class->getDiscriminatorColumn(); - $discrColumnName = $this->getSQLResultCasing($this->platform, $discrColumn->name); - - // Find mapped discriminator column from the result set. - $metaMappingDiscrColumnName = array_search($discrColumnName, $this->resultSetMapping()->metaMappings, true); - if ($metaMappingDiscrColumnName) { - $discrColumnName = $metaMappingDiscrColumnName; - } - - if (! isset($row[$discrColumnName])) { - throw HydrationException::missingDiscriminatorColumn( - $entityName, - $discrColumnName, - key($this->resultSetMapping()->aliasMap), - ); - } - - if ($row[$discrColumnName] === '') { - throw HydrationException::emptyDiscriminatorValue(key( - $this->resultSetMapping()->aliasMap, - )); - } - - $discrMap = $this->class->discriminatorMap; - - if (! isset($discrMap[$row[$discrColumnName]])) { - throw HydrationException::invalidDiscriminatorValue($row[$discrColumnName], array_keys($discrMap)); - } - - $entityName = $discrMap[$row[$discrColumnName]]; - $discrColumnValue = $row[$discrColumnName]; - - unset($row[$discrColumnName]); - } - - foreach ($row as $column => $value) { - // An ObjectHydrator should be used instead of SimpleObjectHydrator - if (isset($this->resultSetMapping()->relationMap[$column])) { - throw new Exception(sprintf('Unable to retrieve association information for column "%s"', $column)); - } - - $cacheKeyInfo = $this->hydrateColumnInfo($column); - - if (! $cacheKeyInfo) { - continue; - } - - // If we have inheritance in resultset, make sure the field belongs to the correct class - if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array((string) $discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) { - continue; - } - - // Check if value is null before conversion (because some types convert null to something else) - $valueIsNull = $value === null; - - // Convert field to a valid PHP value - if (isset($cacheKeyInfo['type'])) { - $type = $cacheKeyInfo['type']; - $value = $type->convertToPHPValue($value, $this->platform); - } - - if ($value !== null && isset($cacheKeyInfo['enumType'])) { - $originalValue = $value; - try { - $value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']); - } catch (ValueError $e) { - throw MappingException::invalidEnumValue( - $entityName, - $cacheKeyInfo['fieldName'], - (string) $originalValue, - $cacheKeyInfo['enumType'], - $e, - ); - } - } - - $fieldName = $cacheKeyInfo['fieldName']; - - // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator) - if (! isset($data[$fieldName]) || ! $valueIsNull) { - $data[$fieldName] = $value; - } - } - - if (isset($this->hints[Query::HINT_REFRESH_ENTITY])) { - $this->registerManaged($this->class, $this->hints[Query::HINT_REFRESH_ENTITY], $data); - } - - $uow = $this->em->getUnitOfWork(); - $entity = $uow->createEntity($entityName, $data, $this->hints); - - $result[] = $entity; - - if (isset($this->hints[Query::HINT_INTERNAL_ITERATION]) && $this->hints[Query::HINT_INTERNAL_ITERATION]) { - $this->uow->hydrationComplete(); - } - } -} diff --git a/vendor/doctrine/orm/src/Internal/Hydration/SingleScalarHydrator.php b/vendor/doctrine/orm/src/Internal/Hydration/SingleScalarHydrator.php deleted file mode 100644 index 2787bbc..0000000 --- a/vendor/doctrine/orm/src/Internal/Hydration/SingleScalarHydrator.php +++ /dev/null @@ -1,40 +0,0 @@ -statement()->fetchAllAssociative(); - $numRows = count($data); - - if ($numRows === 0) { - throw new NoResultException(); - } - - if ($numRows > 1) { - throw new NonUniqueResultException('The query returned multiple rows. Change the query or use a different result function like getScalarResult().'); - } - - $result = $this->gatherScalarRowData($data[key($data)]); - - if (count($result) > 1) { - throw new NonUniqueResultException('The query returned a row containing multiple columns. Change the query or use a different result function like getScalarResult().'); - } - - return array_shift($result); - } -} diff --git a/vendor/doctrine/orm/src/Internal/HydrationCompleteHandler.php b/vendor/doctrine/orm/src/Internal/HydrationCompleteHandler.php deleted file mode 100644 index e0fe342..0000000 --- a/vendor/doctrine/orm/src/Internal/HydrationCompleteHandler.php +++ /dev/null @@ -1,64 +0,0 @@ -listenersInvoker->getSubscribedSystems($class, Events::postLoad); - - if ($invoke === ListenersInvoker::INVOKE_NONE) { - return; - } - - $this->deferredPostLoadInvocations[] = [$class, $invoke, $entity]; - } - - /** - * This method should be called after any hydration cycle completed. - * - * Method fires all deferred invocations of postLoad events - */ - public function hydrationComplete(): void - { - $toInvoke = $this->deferredPostLoadInvocations; - $this->deferredPostLoadInvocations = []; - - foreach ($toInvoke as $classAndEntity) { - [$class, $invoke, $entity] = $classAndEntity; - - $this->listenersInvoker->invoke( - $class, - Events::postLoad, - $entity, - new PostLoadEventArgs($entity, $this->em), - $invoke, - ); - } - } -} diff --git a/vendor/doctrine/orm/src/Internal/NoUnknownNamedArguments.php b/vendor/doctrine/orm/src/Internal/NoUnknownNamedArguments.php deleted file mode 100644 index 7584744..0000000 --- a/vendor/doctrine/orm/src/Internal/NoUnknownNamedArguments.php +++ /dev/null @@ -1,55 +0,0 @@ - $parameter - */ - private static function validateVariadicParameter(array $parameter): void - { - if (array_is_list($parameter)) { - return; - } - - [, $trace] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - assert(isset($trace['class'])); - - $additionalArguments = array_values(array_filter( - array_keys($parameter), - is_string(...), - )); - - throw new BadMethodCallException(sprintf( - 'Invalid call to %s::%s(), unknown named arguments: %s', - $trace['class'], - $trace['function'], - implode(', ', $additionalArguments), - )); - } -} diff --git a/vendor/doctrine/orm/src/Internal/QueryType.php b/vendor/doctrine/orm/src/Internal/QueryType.php deleted file mode 100644 index b5e60c7..0000000 --- a/vendor/doctrine/orm/src/Internal/QueryType.php +++ /dev/null @@ -1,13 +0,0 @@ - - */ - private array $nodes = []; - - /** - * DFS state for the different nodes, indexed by node object id and using one of - * this class' constants as value. - * - * @var array - */ - private array $states = []; - - /** - * Edges between the nodes. The first-level key is the object id of the outgoing - * node; the second array maps the destination node by object id as key. - * - * @var array> - */ - private array $edges = []; - - /** - * DFS numbers, by object ID - * - * @var array - */ - private array $dfs = []; - - /** - * lowlink numbers, by object ID - * - * @var array - */ - private array $lowlink = []; - - private int $maxdfs = 0; - - /** - * Nodes representing the SCC another node is in, indexed by lookup-node object ID - * - * @var array - */ - private array $representingNodes = []; - - /** - * Stack with OIDs of nodes visited in the current state of the DFS - * - * @var list - */ - private array $stack = []; - - public function addNode(object $node): void - { - $id = spl_object_id($node); - $this->nodes[$id] = $node; - $this->states[$id] = self::NOT_VISITED; - $this->edges[$id] = []; - } - - public function hasNode(object $node): bool - { - return isset($this->nodes[spl_object_id($node)]); - } - - /** - * Adds a new edge between two nodes to the graph - */ - public function addEdge(object $from, object $to): void - { - $fromId = spl_object_id($from); - $toId = spl_object_id($to); - - $this->edges[$fromId][$toId] = true; - } - - public function findStronglyConnectedComponents(): void - { - foreach (array_keys($this->nodes) as $oid) { - if ($this->states[$oid] === self::NOT_VISITED) { - $this->tarjan($oid); - } - } - } - - private function tarjan(int $oid): void - { - $this->dfs[$oid] = $this->lowlink[$oid] = $this->maxdfs++; - $this->states[$oid] = self::IN_PROGRESS; - array_push($this->stack, $oid); - - foreach ($this->edges[$oid] as $adjacentId => $ignored) { - if ($this->states[$adjacentId] === self::NOT_VISITED) { - $this->tarjan($adjacentId); - $this->lowlink[$oid] = min($this->lowlink[$oid], $this->lowlink[$adjacentId]); - } elseif ($this->states[$adjacentId] === self::IN_PROGRESS) { - $this->lowlink[$oid] = min($this->lowlink[$oid], $this->dfs[$adjacentId]); - } - } - - $lowlink = $this->lowlink[$oid]; - if ($lowlink === $this->dfs[$oid]) { - $representingNode = null; - do { - $unwindOid = array_pop($this->stack); - - if (! $representingNode) { - $representingNode = $this->nodes[$unwindOid]; - } - - $this->representingNodes[$unwindOid] = $representingNode; - $this->states[$unwindOid] = self::VISITED; - } while ($unwindOid !== $oid); - } - } - - public function getNodeRepresentingStronglyConnectedComponent(object $node): object - { - $oid = spl_object_id($node); - - if (! isset($this->representingNodes[$oid])) { - throw new InvalidArgumentException('unknown node'); - } - - return $this->representingNodes[$oid]; - } -} diff --git a/vendor/doctrine/orm/src/Internal/TopologicalSort.php b/vendor/doctrine/orm/src/Internal/TopologicalSort.php deleted file mode 100644 index 808bc0f..0000000 --- a/vendor/doctrine/orm/src/Internal/TopologicalSort.php +++ /dev/null @@ -1,155 +0,0 @@ - - */ - private array $nodes = []; - - /** - * DFS state for the different nodes, indexed by node object id and using one of - * this class' constants as value. - * - * @var array - */ - private array $states = []; - - /** - * Edges between the nodes. The first-level key is the object id of the outgoing - * node; the second array maps the destination node by object id as key. The final - * boolean value indicates whether the edge is optional or not. - * - * @var array> - */ - private array $edges = []; - - /** - * Builds up the result during the DFS. - * - * @var list - */ - private array $sortResult = []; - - public function addNode(object $node): void - { - $id = spl_object_id($node); - $this->nodes[$id] = $node; - $this->states[$id] = self::NOT_VISITED; - $this->edges[$id] = []; - } - - public function hasNode(object $node): bool - { - return isset($this->nodes[spl_object_id($node)]); - } - - /** - * Adds a new edge between two nodes to the graph - * - * @param bool $optional This indicates whether the edge may be ignored during the topological sort if it is necessary to break cycles. - */ - public function addEdge(object $from, object $to, bool $optional): void - { - $fromId = spl_object_id($from); - $toId = spl_object_id($to); - - if (isset($this->edges[$fromId][$toId]) && $this->edges[$fromId][$toId] === false) { - return; // we already know about this dependency, and it is not optional - } - - $this->edges[$fromId][$toId] = $optional; - } - - /** - * Returns a topological sort of all nodes. When we have an edge A->B between two nodes - * A and B, then B will be listed before A in the result. Visually speaking, when ordering - * the nodes in the result order from left to right, all edges point to the left. - * - * @return list - */ - public function sort(): array - { - foreach (array_keys($this->nodes) as $oid) { - if ($this->states[$oid] === self::NOT_VISITED) { - $this->visit($oid); - } - } - - return $this->sortResult; - } - - private function visit(int $oid): void - { - if ($this->states[$oid] === self::IN_PROGRESS) { - // This node is already on the current DFS stack. We've found a cycle! - throw new CycleDetectedException($this->nodes[$oid]); - } - - if ($this->states[$oid] === self::VISITED) { - // We've reached a node that we've already seen, including all - // other nodes that are reachable from here. We're done here, return. - return; - } - - $this->states[$oid] = self::IN_PROGRESS; - - // Continue the DFS downwards the edge list - foreach ($this->edges[$oid] as $adjacentId => $optional) { - try { - $this->visit($adjacentId); - } catch (CycleDetectedException $exception) { - if ($exception->isCycleCollected()) { - // There is a complete cycle downstream of the current node. We cannot - // do anything about that anymore. - throw $exception; - } - - if ($optional) { - // The current edge is part of a cycle, but it is optional and the closest - // such edge while backtracking. Break the cycle here by skipping the edge - // and continuing with the next one. - continue; - } - - // We have found a cycle and cannot break it at $edge. Best we can do - // is to backtrack from the current vertex, hoping that somewhere up the - // stack this can be salvaged. - $this->states[$oid] = self::NOT_VISITED; - $exception->addToCycle($this->nodes[$oid]); - - throw $exception; - } - } - - // We have traversed all edges and visited all other nodes reachable from here. - // So we're done with this vertex as well. - - $this->states[$oid] = self::VISITED; - $this->sortResult[] = $this->nodes[$oid]; - } -} diff --git a/vendor/doctrine/orm/src/Internal/TopologicalSort/CycleDetectedException.php b/vendor/doctrine/orm/src/Internal/TopologicalSort/CycleDetectedException.php deleted file mode 100644 index 3af5329..0000000 --- a/vendor/doctrine/orm/src/Internal/TopologicalSort/CycleDetectedException.php +++ /dev/null @@ -1,47 +0,0 @@ - */ - private array $cycle; - - /** - * Do we have the complete cycle collected? - */ - private bool $cycleCollected = false; - - public function __construct(private readonly object $startNode) - { - parent::__construct('A cycle has been detected, so a topological sort is not possible. The getCycle() method provides the list of nodes that form the cycle.'); - - $this->cycle = [$startNode]; - } - - /** @return list */ - public function getCycle(): array - { - return $this->cycle; - } - - public function addToCycle(object $node): void - { - array_unshift($this->cycle, $node); - - if ($node === $this->startNode) { - $this->cycleCollected = true; - } - } - - public function isCycleCollected(): bool - { - return $this->cycleCollected; - } -} diff --git a/vendor/doctrine/orm/src/LazyCriteriaCollection.php b/vendor/doctrine/orm/src/LazyCriteriaCollection.php deleted file mode 100644 index ca67914..0000000 --- a/vendor/doctrine/orm/src/LazyCriteriaCollection.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @implements Selectable - */ -class LazyCriteriaCollection extends AbstractLazyCollection implements Selectable -{ - private int|null $count = null; - - public function __construct( - protected EntityPersister $entityPersister, - protected Criteria $criteria, - ) { - } - - /** - * Do an efficient count on the collection - */ - public function count(): int - { - if ($this->isInitialized()) { - return $this->collection->count(); - } - - // Return cached result in case count query was already executed - if ($this->count !== null) { - return $this->count; - } - - return $this->count = $this->entityPersister->count($this->criteria); - } - - /** - * check if collection is empty without loading it - */ - public function isEmpty(): bool - { - if ($this->isInitialized()) { - return $this->collection->isEmpty(); - } - - return ! $this->count(); - } - - /** - * Do an optimized search of an element - * - * @param mixed $element The element to search for. - * - * @return bool TRUE if the collection contains $element, FALSE otherwise. - */ - public function contains(mixed $element): bool - { - if ($this->isInitialized()) { - return $this->collection->contains($element); - } - - return $this->entityPersister->exists($element, $this->criteria); - } - - /** @return ReadableCollection&Selectable */ - public function matching(Criteria $criteria): ReadableCollection&Selectable - { - $this->initialize(); - assert($this->collection instanceof Selectable); - - return $this->collection->matching($criteria); - } - - protected function doInitialize(): void - { - $elements = $this->entityPersister->loadCriteria($this->criteria); - $this->collection = new ArrayCollection($elements); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/AnsiQuoteStrategy.php b/vendor/doctrine/orm/src/Mapping/AnsiQuoteStrategy.php deleted file mode 100644 index 872d4d6..0000000 --- a/vendor/doctrine/orm/src/Mapping/AnsiQuoteStrategy.php +++ /dev/null @@ -1,76 +0,0 @@ -fieldMappings[$fieldName]->columnName; - } - - public function getTableName(ClassMetadata $class, AbstractPlatform $platform): string - { - return $class->table['name']; - } - - /** - * {@inheritDoc} - */ - public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform): string - { - return $definition['sequenceName']; - } - - public function getJoinColumnName(JoinColumnMapping $joinColumn, ClassMetadata $class, AbstractPlatform $platform): string - { - return $joinColumn->name; - } - - public function getReferencedJoinColumnName( - JoinColumnMapping $joinColumn, - ClassMetadata $class, - AbstractPlatform $platform, - ): string { - return $joinColumn->referencedColumnName; - } - - public function getJoinTableName( - ManyToManyOwningSideMapping $association, - ClassMetadata $class, - AbstractPlatform $platform, - ): string { - return $association->joinTable->name; - } - - /** - * {@inheritDoc} - */ - public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform): array - { - return $class->identifier; - } - - public function getColumnAlias( - string $columnName, - int $counter, - AbstractPlatform $platform, - ClassMetadata|null $class = null, - ): string { - return $this->getSQLResultCasing($platform, $columnName . '_' . $counter); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ArrayAccessImplementation.php b/vendor/doctrine/orm/src/Mapping/ArrayAccessImplementation.php deleted file mode 100644 index 3fd0988..0000000 --- a/vendor/doctrine/orm/src/Mapping/ArrayAccessImplementation.php +++ /dev/null @@ -1,70 +0,0 @@ -$offset); - } - - /** @param string $offset */ - public function offsetGet(mixed $offset): mixed - { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11211', - 'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.', - static::class, - ); - - if (! property_exists($this, $offset)) { - throw new InvalidArgumentException('Undefined property: ' . $offset); - } - - return $this->$offset; - } - - /** @param string $offset */ - public function offsetSet(mixed $offset, mixed $value): void - { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11211', - 'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.', - static::class, - ); - - $this->$offset = $value; - } - - /** @param string $offset */ - public function offsetUnset(mixed $offset): void - { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11211', - 'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.', - static::class, - ); - - $this->$offset = null; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/AssociationMapping.php b/vendor/doctrine/orm/src/Mapping/AssociationMapping.php deleted file mode 100644 index ce7bdb4..0000000 --- a/vendor/doctrine/orm/src/Mapping/AssociationMapping.php +++ /dev/null @@ -1,359 +0,0 @@ - */ -abstract class AssociationMapping implements ArrayAccess -{ - /** - * The names of persistence operations to cascade on the association. - * - * @var list<'persist'|'remove'|'detach'|'refresh'|'all'> - */ - public array $cascade = []; - - /** - * The fetching strategy to use for the association, usually defaults to FETCH_LAZY. - * - * @var ClassMetadata::FETCH_*|null - */ - public int|null $fetch = null; - - /** - * This is set when the association is inherited by this class from another - * (inheritance) parent entity class. The value is the FQCN of the - * topmost entity class that contains this association. (If there are - * transient classes in the class hierarchy, these are ignored, so the - * class property may in fact come from a class further up in the PHP class - * hierarchy.) To-many associations initially declared in mapped - * superclasses are not considered 'inherited' in the nearest - * entity subclasses. - * - * @var class-string|null - */ - public string|null $inherited = null; - - /** - * This is set when the association does not appear in the current class - * for the first time, but is initially declared in another parent - * entity or mapped superclass. The value is the FQCN of the - * topmost non-transient class that contains association information for - * this relationship. - * - * @var class-string|null - */ - public string|null $declared = null; - - public array|null $cache = null; - - public bool|null $id = null; - - public bool|null $isOnDeleteCascade = null; - - /** @var class-string|null */ - public string|null $originalClass = null; - - public string|null $originalField = null; - - public bool $orphanRemoval = false; - - public bool|null $unique = null; - - /** - * @param string $fieldName The name of the field in the entity - * the association is mapped to. - * @param class-string $sourceEntity The class name of the source entity. - * In the case of to-many associations - * initially present in mapped - * superclasses, the nearest - * entity subclasses will be - * considered the respective source - * entities. - * @param class-string $targetEntity The class name of the target entity. - * If it is fully-qualified it is used as - * is. If it is a simple, unqualified - * class name the namespace is assumed to - * be the same as the namespace of the - * source entity. - */ - final public function __construct( - public readonly string $fieldName, - public string $sourceEntity, - public readonly string $targetEntity, - ) { - } - - /** - * @param mixed[] $mappingArray - * @psalm-param array{ - * fieldName: string, - * sourceEntity: class-string, - * targetEntity: class-string, - * cascade?: list<'persist'|'remove'|'detach'|'refresh'|'all'>, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): static - { - unset($mappingArray['isOwningSide'], $mappingArray['type']); - $mapping = new static( - $mappingArray['fieldName'], - $mappingArray['sourceEntity'], - $mappingArray['targetEntity'], - ); - unset($mappingArray['fieldName'], $mappingArray['sourceEntity'], $mappingArray['targetEntity']); - - foreach ($mappingArray as $key => $value) { - if ($key === 'joinTable') { - assert($mapping instanceof ManyToManyAssociationMapping); - - if ($value === [] || $value === null) { - continue; - } - - assert($mapping instanceof ManyToManyOwningSideMapping); - - $mapping->joinTable = JoinTableMapping::fromMappingArray($value); - - continue; - } - - if (property_exists($mapping, $key)) { - $mapping->$key = $value; - } else { - throw new OutOfRangeException('Unknown property ' . $key . ' on class ' . static::class); - } - } - - return $mapping; - } - - /** - * @psalm-assert-if-true OwningSideMapping $this - * @psalm-assert-if-false InverseSideMapping $this - */ - final public function isOwningSide(): bool - { - return $this instanceof OwningSideMapping; - } - - /** @psalm-assert-if-true ToOneAssociationMapping $this */ - final public function isToOne(): bool - { - return $this instanceof ToOneAssociationMapping; - } - - /** @psalm-assert-if-true ToManyAssociationMapping $this */ - final public function isToMany(): bool - { - return $this instanceof ToManyAssociationMapping; - } - - /** @psalm-assert-if-true OneToOneOwningSideMapping $this */ - final public function isOneToOneOwningSide(): bool - { - return $this->isOneToOne() && $this->isOwningSide(); - } - - /** @psalm-assert-if-true OneToOneOwningSideMapping|ManyToOneAssociationMapping $this */ - final public function isToOneOwningSide(): bool - { - return $this->isToOne() && $this->isOwningSide(); - } - - /** @psalm-assert-if-true ManyToManyOwningSideMapping $this */ - final public function isManyToManyOwningSide(): bool - { - return $this instanceof ManyToManyOwningSideMapping; - } - - /** @psalm-assert-if-true OneToOneAssociationMapping $this */ - final public function isOneToOne(): bool - { - return $this instanceof OneToOneAssociationMapping; - } - - /** @psalm-assert-if-true OneToManyAssociationMapping $this */ - final public function isOneToMany(): bool - { - return $this instanceof OneToManyAssociationMapping; - } - - /** @psalm-assert-if-true ManyToOneAssociationMapping $this */ - final public function isManyToOne(): bool - { - return $this instanceof ManyToOneAssociationMapping; - } - - /** @psalm-assert-if-true ManyToManyAssociationMapping $this */ - final public function isManyToMany(): bool - { - return $this instanceof ManyToManyAssociationMapping; - } - - /** @psalm-assert-if-true ToManyAssociationMapping $this */ - final public function isOrdered(): bool - { - return $this->isToMany() && $this->orderBy() !== []; - } - - /** @psalm-assert-if-true ToManyAssociationMapping $this */ - public function isIndexed(): bool - { - return false; - } - - final public function type(): int - { - return match (true) { - $this instanceof OneToOneAssociationMapping => ClassMetadata::ONE_TO_ONE, - $this instanceof OneToManyAssociationMapping => ClassMetadata::ONE_TO_MANY, - $this instanceof ManyToOneAssociationMapping => ClassMetadata::MANY_TO_ONE, - $this instanceof ManyToManyAssociationMapping => ClassMetadata::MANY_TO_MANY, - default => throw new Exception('Cannot determine type for ' . static::class), - }; - } - - /** @param string $offset */ - public function offsetExists(mixed $offset): bool - { - return isset($this->$offset) || in_array($offset, ['isOwningSide', 'type'], true); - } - - final public function offsetGet(mixed $offset): mixed - { - return match ($offset) { - 'isOwningSide' => $this->isOwningSide(), - 'type' => $this->type(), - 'isCascadeRemove' => $this->isCascadeRemove(), - 'isCascadePersist' => $this->isCascadePersist(), - 'isCascadeRefresh' => $this->isCascadeRefresh(), - 'isCascadeDetach' => $this->isCascadeDetach(), - default => property_exists($this, $offset) ? $this->$offset : throw new OutOfRangeException(sprintf( - 'Unknown property "%s" on class %s', - $offset, - static::class, - )), - }; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - assert($offset !== null); - if (! property_exists($this, $offset)) { - throw new OutOfRangeException(sprintf( - 'Unknown property "%s" on class %s', - $offset, - static::class, - )); - } - - if ($offset === 'joinTable') { - $value = JoinTableMapping::fromMappingArray($value); - } - - $this->$offset = $value; - } - - /** @param string $offset */ - public function offsetUnset(mixed $offset): void - { - if (! property_exists($this, $offset)) { - throw new OutOfRangeException(sprintf( - 'Unknown property "%s" on class %s', - $offset, - static::class, - )); - } - - $this->$offset = null; - } - - final public function isCascadeRemove(): bool - { - return in_array('remove', $this->cascade, true); - } - - final public function isCascadePersist(): bool - { - return in_array('persist', $this->cascade, true); - } - - final public function isCascadeRefresh(): bool - { - return in_array('refresh', $this->cascade, true); - } - - final public function isCascadeDetach(): bool - { - return in_array('detach', $this->cascade, true); - } - - /** @return array */ - public function toArray(): array - { - $array = (array) $this; - - $array['isOwningSide'] = $this->isOwningSide(); - $array['type'] = $this->type(); - - return $array; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = ['fieldName', 'sourceEntity', 'targetEntity']; - - if (count($this->cascade) > 0) { - $serialized[] = 'cascade'; - } - - foreach ( - [ - 'fetch', - 'inherited', - 'declared', - 'cache', - 'originalClass', - 'originalField', - ] as $stringOrArrayProperty - ) { - if ($this->$stringOrArrayProperty !== null) { - $serialized[] = $stringOrArrayProperty; - } - } - - foreach (['id', 'orphanRemoval', 'isOnDeleteCascade', 'unique'] as $boolProperty) { - if ($this->$boolProperty) { - $serialized[] = $boolProperty; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/AssociationOverride.php b/vendor/doctrine/orm/src/Mapping/AssociationOverride.php deleted file mode 100644 index e0ebc07..0000000 --- a/vendor/doctrine/orm/src/Mapping/AssociationOverride.php +++ /dev/null @@ -1,51 +0,0 @@ -|null - */ - public readonly array|null $joinColumns; - - /** - * The join column that is being mapped to the persistent attribute. - * - * @var array|null - */ - public readonly array|null $inverseJoinColumns; - - /** - * @param string $name The name of the relationship property whose mapping is being overridden. - * @param JoinColumn|array $joinColumns - * @param JoinColumn|array $inverseJoinColumns - * @param JoinTable|null $joinTable The join table that maps the relationship. - * @param string|null $inversedBy The name of the association-field on the inverse-side. - * @psalm-param 'LAZY'|'EAGER'|'EXTRA_LAZY'|null $fetch - */ - public function __construct( - public readonly string $name, - array|JoinColumn|null $joinColumns = null, - array|JoinColumn|null $inverseJoinColumns = null, - public readonly JoinTable|null $joinTable = null, - public readonly string|null $inversedBy = null, - public readonly string|null $fetch = null, - ) { - if ($joinColumns instanceof JoinColumn) { - $joinColumns = [$joinColumns]; - } - - if ($inverseJoinColumns instanceof JoinColumn) { - $inverseJoinColumns = [$inverseJoinColumns]; - } - - $this->joinColumns = $joinColumns; - $this->inverseJoinColumns = $inverseJoinColumns; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/AssociationOverrides.php b/vendor/doctrine/orm/src/Mapping/AssociationOverrides.php deleted file mode 100644 index 9fc6807..0000000 --- a/vendor/doctrine/orm/src/Mapping/AssociationOverrides.php +++ /dev/null @@ -1,38 +0,0 @@ - - */ - public readonly array $overrides; - - /** @param array|AssociationOverride $overrides */ - public function __construct(array|AssociationOverride $overrides) - { - if (! is_array($overrides)) { - $overrides = [$overrides]; - } - - foreach ($overrides as $override) { - if (! ($override instanceof AssociationOverride)) { - throw MappingException::invalidOverrideType('AssociationOverride', $override); - } - } - - $this->overrides = array_values($overrides); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/AttributeOverride.php b/vendor/doctrine/orm/src/Mapping/AttributeOverride.php deleted file mode 100644 index 8f0e70c..0000000 --- a/vendor/doctrine/orm/src/Mapping/AttributeOverride.php +++ /dev/null @@ -1,15 +0,0 @@ - - */ - public readonly array $overrides; - - /** @param array|AttributeOverride $overrides */ - public function __construct(array|AttributeOverride $overrides) - { - if (! is_array($overrides)) { - $overrides = [$overrides]; - } - - foreach ($overrides as $override) { - if (! ($override instanceof AttributeOverride)) { - throw MappingException::invalidOverrideType('AttributeOverride', $override); - } - } - - $this->overrides = array_values($overrides); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/AssociationBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/AssociationBuilder.php deleted file mode 100644 index ea9e13c..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/AssociationBuilder.php +++ /dev/null @@ -1,171 +0,0 @@ -mapping['mappedBy'] = $fieldName; - - return $this; - } - - /** @return $this */ - public function inversedBy(string $fieldName): static - { - $this->mapping['inversedBy'] = $fieldName; - - return $this; - } - - /** @return $this */ - public function cascadeAll(): static - { - $this->mapping['cascade'] = ['ALL']; - - return $this; - } - - /** @return $this */ - public function cascadePersist(): static - { - $this->mapping['cascade'][] = 'persist'; - - return $this; - } - - /** @return $this */ - public function cascadeRemove(): static - { - $this->mapping['cascade'][] = 'remove'; - - return $this; - } - - /** @return $this */ - public function cascadeDetach(): static - { - $this->mapping['cascade'][] = 'detach'; - - return $this; - } - - /** @return $this */ - public function cascadeRefresh(): static - { - $this->mapping['cascade'][] = 'refresh'; - - return $this; - } - - /** @return $this */ - public function fetchExtraLazy(): static - { - $this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY; - - return $this; - } - - /** @return $this */ - public function fetchEager(): static - { - $this->mapping['fetch'] = ClassMetadata::FETCH_EAGER; - - return $this; - } - - /** @return $this */ - public function fetchLazy(): static - { - $this->mapping['fetch'] = ClassMetadata::FETCH_LAZY; - - return $this; - } - - /** - * Add Join Columns. - * - * @return $this - */ - public function addJoinColumn( - string $columnName, - string $referencedColumnName, - bool $nullable = true, - bool $unique = false, - string|null $onDelete = null, - string|null $columnDef = null, - ): static { - $this->joinColumns[] = [ - 'name' => $columnName, - 'referencedColumnName' => $referencedColumnName, - 'nullable' => $nullable, - 'unique' => $unique, - 'onDelete' => $onDelete, - 'columnDefinition' => $columnDef, - ]; - - return $this; - } - - /** - * Sets field as primary key. - * - * @return $this - */ - public function makePrimaryKey(): static - { - $this->mapping['id'] = true; - - return $this; - } - - /** - * Removes orphan entities when detached from their parent. - * - * @return $this - */ - public function orphanRemoval(): static - { - $this->mapping['orphanRemoval'] = true; - - return $this; - } - - /** @throws InvalidArgumentException */ - public function build(): ClassMetadataBuilder - { - $mapping = $this->mapping; - if ($this->joinColumns) { - $mapping['joinColumns'] = $this->joinColumns; - } - - $cm = $this->builder->getClassMetadata(); - if ($this->type === ClassMetadata::MANY_TO_ONE) { - $cm->mapManyToOne($mapping); - } elseif ($this->type === ClassMetadata::ONE_TO_ONE) { - $cm->mapOneToOne($mapping); - } else { - throw new InvalidArgumentException('Type should be a ToOne Association here'); - } - - return $this->builder; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/ClassMetadataBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/ClassMetadataBuilder.php deleted file mode 100644 index b9d3cc8..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/ClassMetadataBuilder.php +++ /dev/null @@ -1,426 +0,0 @@ -cm; - } - - /** - * Marks the class as mapped superclass. - * - * @return $this - */ - public function setMappedSuperClass(): static - { - $this->cm->isMappedSuperclass = true; - $this->cm->isEmbeddedClass = false; - - return $this; - } - - /** - * Marks the class as embeddable. - * - * @return $this - */ - public function setEmbeddable(): static - { - $this->cm->isEmbeddedClass = true; - $this->cm->isMappedSuperclass = false; - - return $this; - } - - /** - * Adds and embedded class - * - * @param class-string $class - * - * @return $this - */ - public function addEmbedded(string $fieldName, string $class, string|false|null $columnPrefix = null): static - { - $this->cm->mapEmbedded( - [ - 'fieldName' => $fieldName, - 'class' => $class, - 'columnPrefix' => $columnPrefix, - ], - ); - - return $this; - } - - /** - * Sets custom Repository class name. - * - * @return $this - */ - public function setCustomRepositoryClass(string $repositoryClassName): static - { - $this->cm->setCustomRepositoryClass($repositoryClassName); - - return $this; - } - - /** - * Marks class read only. - * - * @return $this - */ - public function setReadOnly(): static - { - $this->cm->markReadOnly(); - - return $this; - } - - /** - * Sets the table name. - * - * @return $this - */ - public function setTable(string $name): static - { - $this->cm->setPrimaryTable(['name' => $name]); - - return $this; - } - - /** - * Adds Index. - * - * @psalm-param list $columns - * - * @return $this - */ - public function addIndex(array $columns, string $name): static - { - if (! isset($this->cm->table['indexes'])) { - $this->cm->table['indexes'] = []; - } - - $this->cm->table['indexes'][$name] = ['columns' => $columns]; - - return $this; - } - - /** - * Adds Unique Constraint. - * - * @psalm-param list $columns - * - * @return $this - */ - public function addUniqueConstraint(array $columns, string $name): static - { - if (! isset($this->cm->table['uniqueConstraints'])) { - $this->cm->table['uniqueConstraints'] = []; - } - - $this->cm->table['uniqueConstraints'][$name] = ['columns' => $columns]; - - return $this; - } - - /** - * Sets class as root of a joined table inheritance hierarchy. - * - * @return $this - */ - public function setJoinedTableInheritance(): static - { - $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED); - - return $this; - } - - /** - * Sets class as root of a single table inheritance hierarchy. - * - * @return $this - */ - public function setSingleTableInheritance(): static - { - $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); - - return $this; - } - - /** - * Sets the discriminator column details. - * - * @psalm-param class-string|null $enumType - * @psalm-param array $options - * - * @return $this - */ - public function setDiscriminatorColumn( - string $name, - string $type = 'string', - int $length = 255, - string|null $columnDefinition = null, - string|null $enumType = null, - array $options = [], - ): static { - $this->cm->setDiscriminatorColumn( - [ - 'name' => $name, - 'type' => $type, - 'length' => $length, - 'columnDefinition' => $columnDefinition, - 'enumType' => $enumType, - 'options' => $options, - ], - ); - - return $this; - } - - /** - * Adds a subclass to this inheritance hierarchy. - * - * @return $this - */ - public function addDiscriminatorMapClass(string $name, string $class): static - { - $this->cm->addDiscriminatorMapClass($name, $class); - - return $this; - } - - /** - * Sets deferred explicit change tracking policy. - * - * @return $this - */ - public function setChangeTrackingPolicyDeferredExplicit(): static - { - $this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT); - - return $this; - } - - /** - * Adds lifecycle event. - * - * @return $this - */ - public function addLifecycleEvent(string $methodName, string $event): static - { - $this->cm->addLifecycleCallback($methodName, $event); - - return $this; - } - - /** - * Adds Field. - * - * @psalm-param array $mapping - * - * @return $this - */ - public function addField(string $name, string $type, array $mapping = []): static - { - $mapping['fieldName'] = $name; - $mapping['type'] = $type; - - $this->cm->mapField($mapping); - - return $this; - } - - /** - * Creates a field builder. - */ - public function createField(string $name, string $type): FieldBuilder - { - return new FieldBuilder( - $this, - [ - 'fieldName' => $name, - 'type' => $type, - ], - ); - } - - /** - * Creates an embedded builder. - */ - public function createEmbedded(string $fieldName, string $class): EmbeddedBuilder - { - return new EmbeddedBuilder( - $this, - [ - 'fieldName' => $fieldName, - 'class' => $class, - 'columnPrefix' => null, - ], - ); - } - - /** - * Adds a simple many to one association, optionally with the inversed by field. - */ - public function addManyToOne( - string $name, - string $targetEntity, - string|null $inversedBy = null, - ): ClassMetadataBuilder { - $builder = $this->createManyToOne($name, $targetEntity); - - if ($inversedBy !== null) { - $builder->inversedBy($inversedBy); - } - - return $builder->build(); - } - - /** - * Creates a ManyToOne Association Builder. - * - * Note: This method does not add the association, you have to call build() on the AssociationBuilder. - */ - public function createManyToOne(string $name, string $targetEntity): AssociationBuilder - { - return new AssociationBuilder( - $this, - [ - 'fieldName' => $name, - 'targetEntity' => $targetEntity, - ], - ClassMetadata::MANY_TO_ONE, - ); - } - - /** - * Creates a OneToOne Association Builder. - */ - public function createOneToOne(string $name, string $targetEntity): AssociationBuilder - { - return new AssociationBuilder( - $this, - [ - 'fieldName' => $name, - 'targetEntity' => $targetEntity, - ], - ClassMetadata::ONE_TO_ONE, - ); - } - - /** - * Adds simple inverse one-to-one association. - */ - public function addInverseOneToOne(string $name, string $targetEntity, string $mappedBy): ClassMetadataBuilder - { - $builder = $this->createOneToOne($name, $targetEntity); - $builder->mappedBy($mappedBy); - - return $builder->build(); - } - - /** - * Adds simple owning one-to-one association. - */ - public function addOwningOneToOne( - string $name, - string $targetEntity, - string|null $inversedBy = null, - ): ClassMetadataBuilder { - $builder = $this->createOneToOne($name, $targetEntity); - - if ($inversedBy !== null) { - $builder->inversedBy($inversedBy); - } - - return $builder->build(); - } - - /** - * Creates a ManyToMany Association Builder. - */ - public function createManyToMany(string $name, string $targetEntity): ManyToManyAssociationBuilder - { - return new ManyToManyAssociationBuilder( - $this, - [ - 'fieldName' => $name, - 'targetEntity' => $targetEntity, - ], - ClassMetadata::MANY_TO_MANY, - ); - } - - /** - * Adds a simple owning many to many association. - */ - public function addOwningManyToMany( - string $name, - string $targetEntity, - string|null $inversedBy = null, - ): ClassMetadataBuilder { - $builder = $this->createManyToMany($name, $targetEntity); - - if ($inversedBy !== null) { - $builder->inversedBy($inversedBy); - } - - return $builder->build(); - } - - /** - * Adds a simple inverse many to many association. - */ - public function addInverseManyToMany(string $name, string $targetEntity, string $mappedBy): ClassMetadataBuilder - { - $builder = $this->createManyToMany($name, $targetEntity); - $builder->mappedBy($mappedBy); - - return $builder->build(); - } - - /** - * Creates a one to many association builder. - */ - public function createOneToMany(string $name, string $targetEntity): OneToManyAssociationBuilder - { - return new OneToManyAssociationBuilder( - $this, - [ - 'fieldName' => $name, - 'targetEntity' => $targetEntity, - ], - ClassMetadata::ONE_TO_MANY, - ); - } - - /** - * Adds simple OneToMany association. - */ - public function addOneToMany(string $name, string $targetEntity, string $mappedBy): ClassMetadataBuilder - { - $builder = $this->createOneToMany($name, $targetEntity); - $builder->mappedBy($mappedBy); - - return $builder->build(); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/EmbeddedBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/EmbeddedBuilder.php deleted file mode 100644 index b9d2127..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/EmbeddedBuilder.php +++ /dev/null @@ -1,46 +0,0 @@ -mapping['columnPrefix'] = $columnPrefix; - - return $this; - } - - /** - * Finalizes this embeddable and attach it to the ClassMetadata. - * - * Without this call an EmbeddedBuilder has no effect on the ClassMetadata. - */ - public function build(): ClassMetadataBuilder - { - $cm = $this->builder->getClassMetadata(); - - $cm->mapEmbedded($this->mapping); - - return $this->builder; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/EntityListenerBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/EntityListenerBuilder.php deleted file mode 100644 index a0b14b9..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/EntityListenerBuilder.php +++ /dev/null @@ -1,55 +0,0 @@ - true, - Events::postRemove => true, - Events::prePersist => true, - Events::postPersist => true, - Events::preUpdate => true, - Events::postUpdate => true, - Events::postLoad => true, - Events::preFlush => true, - ]; - - /** - * Lookup the entity class to find methods that match to event lifecycle names - * - * @param ClassMetadata $metadata The entity metadata. - * @param string $className The listener class name. - * - * @throws MappingException When the listener class not found. - */ - public static function bindEntityListener(ClassMetadata $metadata, string $className): void - { - $class = $metadata->fullyQualifiedClassName($className); - - if (! class_exists($class)) { - throw MappingException::entityListenerClassNotFound($class, $className); - } - - foreach (get_class_methods($class) as $method) { - if (! isset(self::EVENTS[$method])) { - continue; - } - - $metadata->addEntityListener($method, $class, $method); - } - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/FieldBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/FieldBuilder.php deleted file mode 100644 index 8326ff5..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/FieldBuilder.php +++ /dev/null @@ -1,243 +0,0 @@ -mapping['length'] = $length; - - return $this; - } - - /** - * Sets nullable. - * - * @return $this - */ - public function nullable(bool $flag = true): static - { - $this->mapping['nullable'] = $flag; - - return $this; - } - - /** - * Sets Unique. - * - * @return $this - */ - public function unique(bool $flag = true): static - { - $this->mapping['unique'] = $flag; - - return $this; - } - - /** - * Sets column name. - * - * @return $this - */ - public function columnName(string $name): static - { - $this->mapping['columnName'] = $name; - - return $this; - } - - /** - * Sets Precision. - * - * @return $this - */ - public function precision(int $p): static - { - $this->mapping['precision'] = $p; - - return $this; - } - - /** - * Sets insertable. - * - * @return $this - */ - public function insertable(bool $flag = true): self - { - if (! $flag) { - $this->mapping['notInsertable'] = true; - } - - return $this; - } - - /** - * Sets updatable. - * - * @return $this - */ - public function updatable(bool $flag = true): self - { - if (! $flag) { - $this->mapping['notUpdatable'] = true; - } - - return $this; - } - - /** - * Sets scale. - * - * @return $this - */ - public function scale(int $s): static - { - $this->mapping['scale'] = $s; - - return $this; - } - - /** - * Sets field as primary key. - * - * @return $this - */ - public function makePrimaryKey(): static - { - $this->mapping['id'] = true; - - return $this; - } - - /** - * Sets an option. - * - * @return $this - */ - public function option(string $name, mixed $value): static - { - $this->mapping['options'][$name] = $value; - - return $this; - } - - /** @return $this */ - public function generatedValue(string $strategy = 'AUTO'): static - { - $this->generatedValue = $strategy; - - return $this; - } - - /** - * Sets field versioned. - * - * @return $this - */ - public function isVersionField(): static - { - $this->version = true; - - return $this; - } - - /** - * Sets Sequence Generator. - * - * @return $this - */ - public function setSequenceGenerator(string $sequenceName, int $allocationSize = 1, int $initialValue = 1): static - { - $this->sequenceDef = [ - 'sequenceName' => $sequenceName, - 'allocationSize' => $allocationSize, - 'initialValue' => $initialValue, - ]; - - return $this; - } - - /** - * Sets column definition. - * - * @return $this - */ - public function columnDefinition(string $def): static - { - $this->mapping['columnDefinition'] = $def; - - return $this; - } - - /** - * Set the FQCN of the custom ID generator. - * This class must extend \Doctrine\ORM\Id\AbstractIdGenerator. - * - * @return $this - */ - public function setCustomIdGenerator(string $customIdGenerator): static - { - $this->customIdGenerator = $customIdGenerator; - - return $this; - } - - /** - * Finalizes this field and attach it to the ClassMetadata. - * - * Without this call a FieldBuilder has no effect on the ClassMetadata. - */ - public function build(): ClassMetadataBuilder - { - $cm = $this->builder->getClassMetadata(); - if ($this->generatedValue) { - $cm->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $this->generatedValue)); - } - - if ($this->version) { - $cm->setVersionMapping($this->mapping); - } - - $cm->mapField($this->mapping); - if ($this->sequenceDef) { - $cm->setSequenceGeneratorDefinition($this->sequenceDef); - } - - if ($this->customIdGenerator) { - $cm->setCustomGeneratorDefinition(['class' => $this->customIdGenerator]); - } - - return $this->builder; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/ManyToManyAssociationBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/ManyToManyAssociationBuilder.php deleted file mode 100644 index b83a8ba..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/ManyToManyAssociationBuilder.php +++ /dev/null @@ -1,73 +0,0 @@ -joinTableName = $name; - - return $this; - } - - /** - * Adds Inverse Join Columns. - * - * @return $this - */ - public function addInverseJoinColumn( - string $columnName, - string $referencedColumnName, - bool $nullable = true, - bool $unique = false, - string|null $onDelete = null, - string|null $columnDef = null, - ): static { - $this->inverseJoinColumns[] = [ - 'name' => $columnName, - 'referencedColumnName' => $referencedColumnName, - 'nullable' => $nullable, - 'unique' => $unique, - 'onDelete' => $onDelete, - 'columnDefinition' => $columnDef, - ]; - - return $this; - } - - public function build(): ClassMetadataBuilder - { - $mapping = $this->mapping; - $mapping['joinTable'] = []; - if ($this->joinColumns) { - $mapping['joinTable']['joinColumns'] = $this->joinColumns; - } - - if ($this->inverseJoinColumns) { - $mapping['joinTable']['inverseJoinColumns'] = $this->inverseJoinColumns; - } - - if ($this->joinTableName) { - $mapping['joinTable']['name'] = $this->joinTableName; - } - - $cm = $this->builder->getClassMetadata(); - $cm->mapManyToMany($mapping); - - return $this->builder; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Builder/OneToManyAssociationBuilder.php b/vendor/doctrine/orm/src/Mapping/Builder/OneToManyAssociationBuilder.php deleted file mode 100644 index 077c558..0000000 --- a/vendor/doctrine/orm/src/Mapping/Builder/OneToManyAssociationBuilder.php +++ /dev/null @@ -1,46 +0,0 @@ - $fieldNames - * - * @return $this - */ - public function setOrderBy(array $fieldNames): static - { - $this->mapping['orderBy'] = $fieldNames; - - return $this; - } - - /** @return $this */ - public function setIndexBy(string $fieldName): static - { - $this->mapping['indexBy'] = $fieldName; - - return $this; - } - - public function build(): ClassMetadataBuilder - { - $mapping = $this->mapping; - if ($this->joinColumns) { - $mapping['joinColumns'] = $this->joinColumns; - } - - $cm = $this->builder->getClassMetadata(); - $cm->mapOneToMany($mapping); - - return $this->builder; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Cache.php b/vendor/doctrine/orm/src/Mapping/Cache.php deleted file mode 100644 index 3161ab3..0000000 --- a/vendor/doctrine/orm/src/Mapping/Cache.php +++ /dev/null @@ -1,19 +0,0 @@ - $typedFieldMappers */ - private readonly array $typedFieldMappers; - - public function __construct(TypedFieldMapper ...$typedFieldMappers) - { - self::validateVariadicParameter($typedFieldMappers); - - $this->typedFieldMappers = $typedFieldMappers; - } - - /** - * {@inheritDoc} - */ - public function validateAndComplete(array $mapping, ReflectionProperty $field): array - { - foreach ($this->typedFieldMappers as $typedFieldMapper) { - $mapping = $typedFieldMapper->validateAndComplete($mapping, $field); - } - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ChangeTrackingPolicy.php b/vendor/doctrine/orm/src/Mapping/ChangeTrackingPolicy.php deleted file mode 100644 index 7181d9f..0000000 --- a/vendor/doctrine/orm/src/Mapping/ChangeTrackingPolicy.php +++ /dev/null @@ -1,17 +0,0 @@ -ClassMetadata instance holds all the object-relational mapping metadata - * of an entity and its associations. - * - * Once populated, ClassMetadata instances are usually cached in a serialized form. - * - * IMPORTANT NOTE: - * - * The fields of this class are only public for 2 reasons: - * 1) To allow fast READ access. - * 2) To drastically reduce the size of a serialized instance (private/protected members - * get the whole class name, namespace inclusive, prepended to every property in - * the serialized representation). - * - * @psalm-type ConcreteAssociationMapping = OneToOneOwningSideMapping|OneToOneInverseSideMapping|ManyToOneAssociationMapping|OneToManyAssociationMapping|ManyToManyOwningSideMapping|ManyToManyInverseSideMapping - * @template-covariant T of object - * @template-implements PersistenceClassMetadata - */ -class ClassMetadata implements PersistenceClassMetadata, Stringable -{ - /* The inheritance mapping types */ - /** - * NONE means the class does not participate in an inheritance hierarchy - * and therefore does not need an inheritance mapping type. - */ - public const INHERITANCE_TYPE_NONE = 1; - - /** - * JOINED means the class will be persisted according to the rules of - * Class Table Inheritance. - */ - public const INHERITANCE_TYPE_JOINED = 2; - - /** - * SINGLE_TABLE means the class will be persisted according to the rules of - * Single Table Inheritance. - */ - public const INHERITANCE_TYPE_SINGLE_TABLE = 3; - - /* The Id generator types. */ - /** - * AUTO means the generator type will depend on what the used platform prefers. - * Offers full portability. - */ - public const GENERATOR_TYPE_AUTO = 1; - - /** - * SEQUENCE means a separate sequence object will be used. Platforms that do - * not have native sequence support may emulate it. Full portability is currently - * not guaranteed. - */ - public const GENERATOR_TYPE_SEQUENCE = 2; - - /** - * IDENTITY means an identity column is used for id generation. The database - * will fill in the id column on insertion. Platforms that do not support - * native identity columns may emulate them. Full portability is currently - * not guaranteed. - */ - public const GENERATOR_TYPE_IDENTITY = 4; - - /** - * NONE means the class does not have a generated id. That means the class - * must have a natural, manually assigned id. - */ - public const GENERATOR_TYPE_NONE = 5; - - /** - * CUSTOM means that customer will use own ID generator that supposedly work - */ - public const GENERATOR_TYPE_CUSTOM = 7; - - /** - * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time - * by doing a property-by-property comparison with the original data. This will - * be done for all entities that are in MANAGED state at commit-time. - * - * This is the default change tracking policy. - */ - public const CHANGETRACKING_DEFERRED_IMPLICIT = 1; - - /** - * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time - * by doing a property-by-property comparison with the original data. This will - * be done only for entities that were explicitly saved (through persist() or a cascade). - */ - public const CHANGETRACKING_DEFERRED_EXPLICIT = 2; - - /** - * Specifies that an association is to be fetched when it is first accessed. - */ - public const FETCH_LAZY = 2; - - /** - * Specifies that an association is to be fetched when the owner of the - * association is fetched. - */ - public const FETCH_EAGER = 3; - - /** - * Specifies that an association is to be fetched lazy (on first access) and that - * commands such as Collection#count, Collection#slice are issued directly against - * the database if the collection is not yet initialized. - */ - public const FETCH_EXTRA_LAZY = 4; - - /** - * Identifies a one-to-one association. - */ - public const ONE_TO_ONE = 1; - - /** - * Identifies a many-to-one association. - */ - public const MANY_TO_ONE = 2; - - /** - * Identifies a one-to-many association. - */ - public const ONE_TO_MANY = 4; - - /** - * Identifies a many-to-many association. - */ - public const MANY_TO_MANY = 8; - - /** - * Combined bitmask for to-one (single-valued) associations. - */ - public const TO_ONE = 3; - - /** - * Combined bitmask for to-many (collection-valued) associations. - */ - public const TO_MANY = 12; - - /** - * ReadOnly cache can do reads, inserts and deletes, cannot perform updates or employ any locks, - */ - public const CACHE_USAGE_READ_ONLY = 1; - - /** - * Nonstrict Read Write Cache doesn’t employ any locks but can do inserts, update and deletes. - */ - public const CACHE_USAGE_NONSTRICT_READ_WRITE = 2; - - /** - * Read Write Attempts to lock the entity before update/delete. - */ - public const CACHE_USAGE_READ_WRITE = 3; - - /** - * The value of this column is never generated by the database. - */ - public const GENERATED_NEVER = 0; - - /** - * The value of this column is generated by the database on INSERT, but not on UPDATE. - */ - public const GENERATED_INSERT = 1; - - /** - * The value of this column is generated by the database on both INSERT and UDPATE statements. - */ - public const GENERATED_ALWAYS = 2; - - /** - * READ-ONLY: The namespace the entity class is contained in. - * - * @todo Not really needed. Usage could be localized. - */ - public string|null $namespace = null; - - /** - * READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance - * hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same - * as {@link $name}. - * - * @psalm-var class-string - */ - public string $rootEntityName; - - /** - * READ-ONLY: The definition of custom generator. Only used for CUSTOM - * generator type - * - * The definition has the following structure: - * - * array( - * 'class' => 'ClassName', - * ) - * - * - * @todo Merge with tableGeneratorDefinition into generic generatorDefinition - * @var array|null - */ - public array|null $customGeneratorDefinition = null; - - /** - * The name of the custom repository class used for the entity class. - * (Optional). - * - * @psalm-var ?class-string - */ - public string|null $customRepositoryClassName = null; - - /** - * READ-ONLY: Whether this class describes the mapping of a mapped superclass. - */ - public bool $isMappedSuperclass = false; - - /** - * READ-ONLY: Whether this class describes the mapping of an embeddable class. - */ - public bool $isEmbeddedClass = false; - - /** - * READ-ONLY: The names of the parent entity classes (ancestors), starting with the - * nearest one and ending with the root entity class. - * - * @psalm-var list - */ - public array $parentClasses = []; - - /** - * READ-ONLY: For classes in inheritance mapping hierarchies, this field contains the names of all - * entity subclasses of this class. These may also be abstract classes. - * - * This list is used, for example, to enumerate all necessary tables in JTI when querying for root - * or subclass entities, or to gather all fields comprised in an entity inheritance tree. - * - * For classes that do not use STI/JTI, this list is empty. - * - * Implementation note: - * - * In PHP, there is no general way to discover all subclasses of a given class at runtime. For that - * reason, the list of classes given in the discriminator map at the root entity is considered - * authoritative. The discriminator map must contain all concrete classes that can - * appear in the particular inheritance hierarchy tree. Since there can be no instances of abstract - * entity classes, users are not required to list such classes with a discriminator value. - * - * The possibly remaining "gaps" for abstract entity classes are filled after the class metadata for the - * root entity has been loaded. - * - * For subclasses of such root entities, the list can be reused/passed downwards, it only needs to - * be filtered accordingly (only keep remaining subclasses) - * - * @psalm-var list - */ - public array $subClasses = []; - - /** - * READ-ONLY: The names of all embedded classes based on properties. - * - * @psalm-var array - */ - public array $embeddedClasses = []; - - /** - * READ-ONLY: The field names of all fields that are part of the identifier/primary key - * of the mapped entity class. - * - * @psalm-var list - */ - public array $identifier = []; - - /** - * READ-ONLY: The inheritance mapping type used by the class. - * - * @psalm-var self::INHERITANCE_TYPE_* - */ - public int $inheritanceType = self::INHERITANCE_TYPE_NONE; - - /** - * READ-ONLY: The Id generator type used by the class. - * - * @psalm-var self::GENERATOR_TYPE_* - */ - public int $generatorType = self::GENERATOR_TYPE_NONE; - - /** - * READ-ONLY: The field mappings of the class. - * Keys are field names and values are FieldMapping instances - * - * @var array - */ - public array $fieldMappings = []; - - /** - * READ-ONLY: An array of field names. Used to look up field names from column names. - * Keys are column names and values are field names. - * - * @psalm-var array - */ - public array $fieldNames = []; - - /** - * READ-ONLY: A map of field names to column names. Keys are field names and values column names. - * Used to look up column names from field names. - * This is the reverse lookup map of $_fieldNames. - * - * @deprecated 3.0 Remove this. - * - * @var mixed[] - */ - public array $columnNames = []; - - /** - * READ-ONLY: The discriminator value of this class. - * - * This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies - * where a discriminator column is used. - * - * @see discriminatorColumn - */ - public mixed $discriminatorValue = null; - - /** - * READ-ONLY: The discriminator map of all mapped classes in the hierarchy. - * - * This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies - * where a discriminator column is used. - * - * @see discriminatorColumn - * - * @var array - * - * @psalm-var array - */ - public array $discriminatorMap = []; - - /** - * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE - * inheritance mappings. - */ - public DiscriminatorColumnMapping|null $discriminatorColumn = null; - - /** - * READ-ONLY: The primary table definition. The definition is an array with the - * following entries: - * - * name => - * schema => - * indexes => array - * uniqueConstraints => array - * - * @var mixed[] - * @psalm-var array{ - * name: string, - * schema?: string, - * indexes?: array, - * uniqueConstraints?: array, - * options?: array, - * quoted?: bool - * } - */ - public array $table; - - /** - * READ-ONLY: The registered lifecycle callbacks for entities of this class. - * - * @psalm-var array> - */ - public array $lifecycleCallbacks = []; - - /** - * READ-ONLY: The registered entity listeners. - * - * @psalm-var array> - */ - public array $entityListeners = []; - - /** - * READ-ONLY: The association mappings of this class. - * - * A join table definition has the following structure: - *
-     * array(
-     *     'name' => ,
-     *      'joinColumns' => array(),
-     *      'inverseJoinColumns' => array()
-     * )
-     * 
- * - * @psalm-var array - */ - public array $associationMappings = []; - - /** - * READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite. - */ - public bool $isIdentifierComposite = false; - - /** - * READ-ONLY: Flag indicating whether the identifier/primary key contains at least one foreign key association. - * - * This flag is necessary because some code blocks require special treatment of this cases. - */ - public bool $containsForeignIdentifier = false; - - /** - * READ-ONLY: Flag indicating whether the identifier/primary key contains at least one ENUM type. - * - * This flag is necessary because some code blocks require special treatment of this cases. - */ - public bool $containsEnumIdentifier = false; - - /** - * READ-ONLY: The ID generator used for generating IDs for this class. - * - * @todo Remove! - */ - public AbstractIdGenerator $idGenerator; - - /** - * READ-ONLY: The definition of the sequence generator of this class. Only used for the - * SEQUENCE generation strategy. - * - * The definition has the following structure: - * - * array( - * 'sequenceName' => 'name', - * 'allocationSize' => '20', - * 'initialValue' => '1' - * ) - * - * - * @var array|null - * @psalm-var array{sequenceName: string, allocationSize: string, initialValue: string, quoted?: mixed}|null - * @todo Merge with tableGeneratorDefinition into generic generatorDefinition - */ - public array|null $sequenceGeneratorDefinition = null; - - /** - * READ-ONLY: The policy used for change-tracking on entities of this class. - */ - public int $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT; - - /** - * READ-ONLY: A Flag indicating whether one or more columns of this class - * have to be reloaded after insert / update operations. - */ - public bool $requiresFetchAfterChange = false; - - /** - * READ-ONLY: A flag for whether or not instances of this class are to be versioned - * with optimistic locking. - */ - public bool $isVersioned = false; - - /** - * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any). - */ - public string|null $versionField = null; - - /** @var mixed[]|null */ - public array|null $cache = null; - - /** - * The ReflectionClass instance of the mapped class. - * - * @var ReflectionClass|null - */ - public ReflectionClass|null $reflClass = null; - - /** - * Is this entity marked as "read-only"? - * - * That means it is never considered for change-tracking in the UnitOfWork. It is a very helpful performance - * optimization for entities that are immutable, either in your domain or through the relation database - * (coming from a view, or a history table for example). - */ - public bool $isReadOnly = false; - - /** - * NamingStrategy determining the default column and table names. - */ - protected NamingStrategy $namingStrategy; - - /** - * The ReflectionProperty instances of the mapped class. - * - * @var array - */ - public array $reflFields = []; - - private InstantiatorInterface|null $instantiator = null; - - private readonly TypedFieldMapper $typedFieldMapper; - - /** - * Initializes a new ClassMetadata instance that will hold the object-relational mapping - * metadata of the class with the given name. - * - * @param string $name The name of the entity class the new instance is used for. - * @psalm-param class-string $name - */ - public function __construct(public string $name, NamingStrategy|null $namingStrategy = null, TypedFieldMapper|null $typedFieldMapper = null) - { - $this->rootEntityName = $name; - $this->namingStrategy = $namingStrategy ?? new DefaultNamingStrategy(); - $this->instantiator = new Instantiator(); - $this->typedFieldMapper = $typedFieldMapper ?? new DefaultTypedFieldMapper(); - } - - /** - * Gets the ReflectionProperties of the mapped class. - * - * @return ReflectionProperty[]|null[] An array of ReflectionProperty instances. - * @psalm-return array - */ - public function getReflectionProperties(): array - { - return $this->reflFields; - } - - /** - * Gets a ReflectionProperty for a specific field of the mapped class. - */ - public function getReflectionProperty(string $name): ReflectionProperty|null - { - return $this->reflFields[$name]; - } - - /** - * Gets the ReflectionProperty for the single identifier field. - * - * @throws BadMethodCallException If the class has a composite identifier. - */ - public function getSingleIdReflectionProperty(): ReflectionProperty|null - { - if ($this->isIdentifierComposite) { - throw new BadMethodCallException('Class ' . $this->name . ' has a composite identifier.'); - } - - return $this->reflFields[$this->identifier[0]]; - } - - /** - * Extracts the identifier values of an entity of this class. - * - * For composite identifiers, the identifier values are returned as an array - * with the same order as the field order in {@link identifier}. - * - * @return array - */ - public function getIdentifierValues(object $entity): array - { - if ($this->isIdentifierComposite) { - $id = []; - - foreach ($this->identifier as $idField) { - $value = $this->reflFields[$idField]->getValue($entity); - - if ($value !== null) { - $id[$idField] = $value; - } - } - - return $id; - } - - $id = $this->identifier[0]; - $value = $this->reflFields[$id]->getValue($entity); - - if ($value === null) { - return []; - } - - return [$id => $value]; - } - - /** - * Populates the entity identifier of an entity. - * - * @psalm-param array $id - * - * @todo Rename to assignIdentifier() - */ - public function setIdentifierValues(object $entity, array $id): void - { - foreach ($id as $idField => $idValue) { - $this->reflFields[$idField]->setValue($entity, $idValue); - } - } - - /** - * Sets the specified field to the specified value on the given entity. - */ - public function setFieldValue(object $entity, string $field, mixed $value): void - { - $this->reflFields[$field]->setValue($entity, $value); - } - - /** - * Gets the specified field's value off the given entity. - */ - public function getFieldValue(object $entity, string $field): mixed - { - return $this->reflFields[$field]->getValue($entity); - } - - /** - * Creates a string representation of this instance. - * - * @return string The string representation of this instance. - * - * @todo Construct meaningful string representation. - */ - public function __toString(): string - { - return self::class . '@' . spl_object_id($this); - } - - /** - * Determines which fields get serialized. - * - * It is only serialized what is necessary for best unserialization performance. - * That means any metadata properties that are not set or empty or simply have - * their default value are NOT serialized. - * - * Parts that are also NOT serialized because they can not be properly unserialized: - * - reflClass (ReflectionClass) - * - reflFields (ReflectionProperty array) - * - * @return string[] The names of all the fields that should be serialized. - */ - public function __sleep(): array - { - // This metadata is always serialized/cached. - $serialized = [ - 'associationMappings', - 'columnNames', //TODO: 3.0 Remove this. Can use fieldMappings[$fieldName]['columnName'] - 'fieldMappings', - 'fieldNames', - 'embeddedClasses', - 'identifier', - 'isIdentifierComposite', // TODO: REMOVE - 'name', - 'namespace', // TODO: REMOVE - 'table', - 'rootEntityName', - 'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime. - ]; - - // The rest of the metadata is only serialized if necessary. - if ($this->changeTrackingPolicy !== self::CHANGETRACKING_DEFERRED_IMPLICIT) { - $serialized[] = 'changeTrackingPolicy'; - } - - if ($this->customRepositoryClassName) { - $serialized[] = 'customRepositoryClassName'; - } - - if ($this->inheritanceType !== self::INHERITANCE_TYPE_NONE) { - $serialized[] = 'inheritanceType'; - $serialized[] = 'discriminatorColumn'; - $serialized[] = 'discriminatorValue'; - $serialized[] = 'discriminatorMap'; - $serialized[] = 'parentClasses'; - $serialized[] = 'subClasses'; - } - - if ($this->generatorType !== self::GENERATOR_TYPE_NONE) { - $serialized[] = 'generatorType'; - if ($this->generatorType === self::GENERATOR_TYPE_SEQUENCE) { - $serialized[] = 'sequenceGeneratorDefinition'; - } - } - - if ($this->isMappedSuperclass) { - $serialized[] = 'isMappedSuperclass'; - } - - if ($this->isEmbeddedClass) { - $serialized[] = 'isEmbeddedClass'; - } - - if ($this->containsForeignIdentifier) { - $serialized[] = 'containsForeignIdentifier'; - } - - if ($this->containsEnumIdentifier) { - $serialized[] = 'containsEnumIdentifier'; - } - - if ($this->isVersioned) { - $serialized[] = 'isVersioned'; - $serialized[] = 'versionField'; - } - - if ($this->lifecycleCallbacks) { - $serialized[] = 'lifecycleCallbacks'; - } - - if ($this->entityListeners) { - $serialized[] = 'entityListeners'; - } - - if ($this->isReadOnly) { - $serialized[] = 'isReadOnly'; - } - - if ($this->customGeneratorDefinition) { - $serialized[] = 'customGeneratorDefinition'; - } - - if ($this->cache) { - $serialized[] = 'cache'; - } - - if ($this->requiresFetchAfterChange) { - $serialized[] = 'requiresFetchAfterChange'; - } - - return $serialized; - } - - /** - * Creates a new instance of the mapped class, without invoking the constructor. - */ - public function newInstance(): object - { - return $this->instantiator->instantiate($this->name); - } - - /** - * Restores some state that can not be serialized/unserialized. - */ - public function wakeupReflection(ReflectionService $reflService): void - { - // Restore ReflectionClass and properties - $this->reflClass = $reflService->getClass($this->name); - $this->instantiator = $this->instantiator ?: new Instantiator(); - - $parentReflFields = []; - - foreach ($this->embeddedClasses as $property => $embeddedClass) { - if (isset($embeddedClass->declaredField)) { - assert($embeddedClass->originalField !== null); - $childProperty = $this->getAccessibleProperty( - $reflService, - $this->embeddedClasses[$embeddedClass->declaredField]->class, - $embeddedClass->originalField, - ); - assert($childProperty !== null); - $parentReflFields[$property] = new ReflectionEmbeddedProperty( - $parentReflFields[$embeddedClass->declaredField], - $childProperty, - $this->embeddedClasses[$embeddedClass->declaredField]->class, - ); - - continue; - } - - $fieldRefl = $this->getAccessibleProperty( - $reflService, - $embeddedClass->declared ?? $this->name, - $property, - ); - - $parentReflFields[$property] = $fieldRefl; - $this->reflFields[$property] = $fieldRefl; - } - - foreach ($this->fieldMappings as $field => $mapping) { - if (isset($mapping->declaredField) && isset($parentReflFields[$mapping->declaredField])) { - assert($mapping->originalField !== null); - assert($mapping->originalClass !== null); - $childProperty = $this->getAccessibleProperty($reflService, $mapping->originalClass, $mapping->originalField); - assert($childProperty !== null); - - if (isset($mapping->enumType)) { - $childProperty = new EnumReflectionProperty( - $childProperty, - $mapping->enumType, - ); - } - - $this->reflFields[$field] = new ReflectionEmbeddedProperty( - $parentReflFields[$mapping->declaredField], - $childProperty, - $mapping->originalClass, - ); - continue; - } - - $this->reflFields[$field] = isset($mapping->declared) - ? $this->getAccessibleProperty($reflService, $mapping->declared, $field) - : $this->getAccessibleProperty($reflService, $this->name, $field); - - if (isset($mapping->enumType) && $this->reflFields[$field] !== null) { - $this->reflFields[$field] = new EnumReflectionProperty( - $this->reflFields[$field], - $mapping->enumType, - ); - } - } - - foreach ($this->associationMappings as $field => $mapping) { - $this->reflFields[$field] = isset($mapping->declared) - ? $this->getAccessibleProperty($reflService, $mapping->declared, $field) - : $this->getAccessibleProperty($reflService, $this->name, $field); - } - } - - /** - * Initializes a new ClassMetadata instance that will hold the object-relational mapping - * metadata of the class with the given name. - * - * @param ReflectionService $reflService The reflection service. - */ - public function initializeReflection(ReflectionService $reflService): void - { - $this->reflClass = $reflService->getClass($this->name); - $this->namespace = $reflService->getClassNamespace($this->name); - - if ($this->reflClass) { - $this->name = $this->rootEntityName = $this->reflClass->name; - } - - $this->table['name'] = $this->namingStrategy->classToTableName($this->name); - } - - /** - * Validates Identifier. - * - * @throws MappingException - */ - public function validateIdentifier(): void - { - if ($this->isMappedSuperclass || $this->isEmbeddedClass) { - return; - } - - // Verify & complete identifier mapping - if (! $this->identifier) { - throw MappingException::identifierRequired($this->name); - } - - if ($this->usesIdGenerator() && $this->isIdentifierComposite) { - throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name); - } - } - - /** - * Validates association targets actually exist. - * - * @throws MappingException - */ - public function validateAssociations(): void - { - foreach ($this->associationMappings as $mapping) { - if ( - ! class_exists($mapping->targetEntity) - && ! interface_exists($mapping->targetEntity) - && ! trait_exists($mapping->targetEntity) - ) { - throw MappingException::invalidTargetEntityClass($mapping->targetEntity, $this->name, $mapping->fieldName); - } - } - } - - /** - * Validates lifecycle callbacks. - * - * @throws MappingException - */ - public function validateLifecycleCallbacks(ReflectionService $reflService): void - { - foreach ($this->lifecycleCallbacks as $callbacks) { - foreach ($callbacks as $callbackFuncName) { - if (! $reflService->hasPublicMethod($this->name, $callbackFuncName)) { - throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName); - } - } - } - } - - /** - * {@inheritDoc} - * - * Can return null when using static reflection, in violation of the LSP - */ - public function getReflectionClass(): ReflectionClass|null - { - return $this->reflClass; - } - - /** @psalm-param array{usage?: mixed, region?: mixed} $cache */ - public function enableCache(array $cache): void - { - if (! isset($cache['usage'])) { - $cache['usage'] = self::CACHE_USAGE_READ_ONLY; - } - - if (! isset($cache['region'])) { - $cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName)); - } - - $this->cache = $cache; - } - - /** @psalm-param array{usage?: int, region?: string} $cache */ - public function enableAssociationCache(string $fieldName, array $cache): void - { - $this->associationMappings[$fieldName]->cache = $this->getAssociationCacheDefaults($fieldName, $cache); - } - - /** - * @psalm-param array{usage?: int, region?: string|null} $cache - * - * @return int[]|string[] - * @psalm-return array{usage: int, region: string|null} - */ - public function getAssociationCacheDefaults(string $fieldName, array $cache): array - { - if (! isset($cache['usage'])) { - $cache['usage'] = $this->cache['usage'] ?? self::CACHE_USAGE_READ_ONLY; - } - - if (! isset($cache['region'])) { - $cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName)) . '__' . $fieldName; - } - - return $cache; - } - - /** - * Sets the change tracking policy used by this class. - */ - public function setChangeTrackingPolicy(int $policy): void - { - $this->changeTrackingPolicy = $policy; - } - - /** - * Whether the change tracking policy of this class is "deferred explicit". - */ - public function isChangeTrackingDeferredExplicit(): bool - { - return $this->changeTrackingPolicy === self::CHANGETRACKING_DEFERRED_EXPLICIT; - } - - /** - * Whether the change tracking policy of this class is "deferred implicit". - */ - public function isChangeTrackingDeferredImplicit(): bool - { - return $this->changeTrackingPolicy === self::CHANGETRACKING_DEFERRED_IMPLICIT; - } - - /** - * Checks whether a field is part of the identifier/primary key field(s). - */ - public function isIdentifier(string $fieldName): bool - { - if (! $this->identifier) { - return false; - } - - if (! $this->isIdentifierComposite) { - return $fieldName === $this->identifier[0]; - } - - return in_array($fieldName, $this->identifier, true); - } - - public function isUniqueField(string $fieldName): bool - { - $mapping = $this->getFieldMapping($fieldName); - - return $mapping !== false && isset($mapping->unique) && $mapping->unique; - } - - public function isNullable(string $fieldName): bool - { - $mapping = $this->getFieldMapping($fieldName); - - return $mapping !== false && isset($mapping->nullable) && $mapping->nullable; - } - - /** - * Gets a column name for a field name. - * If the column name for the field cannot be found, the given field name - * is returned. - */ - public function getColumnName(string $fieldName): string - { - return $this->columnNames[$fieldName] ?? $fieldName; - } - - /** - * Gets the mapping of a (regular) field that holds some data but not a - * reference to another object. - * - * @throws MappingException - */ - public function getFieldMapping(string $fieldName): FieldMapping - { - if (! isset($this->fieldMappings[$fieldName])) { - throw MappingException::mappingNotFound($this->name, $fieldName); - } - - return $this->fieldMappings[$fieldName]; - } - - /** - * Gets the mapping of an association. - * - * @see ClassMetadata::$associationMappings - * - * @param string $fieldName The field name that represents the association in - * the object model. - * - * @throws MappingException - */ - public function getAssociationMapping(string $fieldName): AssociationMapping - { - if (! isset($this->associationMappings[$fieldName])) { - throw MappingException::mappingNotFound($this->name, $fieldName); - } - - return $this->associationMappings[$fieldName]; - } - - /** - * Gets all association mappings of the class. - * - * @psalm-return array - */ - public function getAssociationMappings(): array - { - return $this->associationMappings; - } - - /** - * Gets the field name for a column name. - * If no field name can be found the column name is returned. - * - * @return string The column alias. - */ - public function getFieldName(string $columnName): string - { - return $this->fieldNames[$columnName] ?? $columnName; - } - - /** - * Checks whether given property has type - */ - private function isTypedProperty(string $name): bool - { - return isset($this->reflClass) - && $this->reflClass->hasProperty($name) - && $this->reflClass->getProperty($name)->hasType(); - } - - /** - * Validates & completes the given field mapping based on typed property. - * - * @param array{fieldName: string, type?: string} $mapping The field mapping to validate & complete. - * - * @return array{fieldName: string, enumType?: class-string, type?: string} The updated mapping. - */ - private function validateAndCompleteTypedFieldMapping(array $mapping): array - { - $field = $this->reflClass->getProperty($mapping['fieldName']); - - $mapping = $this->typedFieldMapper->validateAndComplete($mapping, $field); - - return $mapping; - } - - /** - * Validates & completes the basic mapping information based on typed property. - * - * @param array{type: self::ONE_TO_ONE|self::MANY_TO_ONE|self::ONE_TO_MANY|self::MANY_TO_MANY, fieldName: string, targetEntity?: class-string} $mapping The mapping. - * - * @return mixed[] The updated mapping. - */ - private function validateAndCompleteTypedAssociationMapping(array $mapping): array - { - $type = $this->reflClass->getProperty($mapping['fieldName'])->getType(); - - if ($type === null || ($mapping['type'] & self::TO_ONE) === 0) { - return $mapping; - } - - if (! isset($mapping['targetEntity']) && $type instanceof ReflectionNamedType) { - $mapping['targetEntity'] = $type->getName(); - } - - return $mapping; - } - - /** - * Validates & completes the given field mapping. - * - * @psalm-param array{ - * fieldName?: string, - * columnName?: string, - * id?: bool, - * generated?: self::GENERATED_*, - * enumType?: class-string, - * } $mapping The field mapping to validate & complete. - * - * @return FieldMapping The updated mapping. - * - * @throws MappingException - */ - protected function validateAndCompleteFieldMapping(array $mapping): FieldMapping - { - // Check mandatory fields - if (! isset($mapping['fieldName']) || ! $mapping['fieldName']) { - throw MappingException::missingFieldName($this->name); - } - - if ($this->isTypedProperty($mapping['fieldName'])) { - $mapping = $this->validateAndCompleteTypedFieldMapping($mapping); - } - - if (! isset($mapping['type'])) { - // Default to string - $mapping['type'] = 'string'; - } - - // Complete fieldName and columnName mapping - if (! isset($mapping['columnName'])) { - $mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName'], $this->name); - } - - $mapping = FieldMapping::fromMappingArray($mapping); - - if ($mapping->columnName[0] === '`') { - $mapping->columnName = trim($mapping->columnName, '`'); - $mapping->quoted = true; - } - - $this->columnNames[$mapping->fieldName] = $mapping->columnName; - - if (isset($this->fieldNames[$mapping->columnName]) || ($this->discriminatorColumn && $this->discriminatorColumn->name === $mapping->columnName)) { - throw MappingException::duplicateColumnName($this->name, $mapping->columnName); - } - - $this->fieldNames[$mapping->columnName] = $mapping->fieldName; - - // Complete id mapping - if (isset($mapping->id) && $mapping->id === true) { - if ($this->versionField === $mapping->fieldName) { - throw MappingException::cannotVersionIdField($this->name, $mapping->fieldName); - } - - if (! in_array($mapping->fieldName, $this->identifier, true)) { - $this->identifier[] = $mapping->fieldName; - } - - // Check for composite key - if (! $this->isIdentifierComposite && count($this->identifier) > 1) { - $this->isIdentifierComposite = true; - } - } - - if (isset($mapping->generated)) { - if (! in_array($mapping->generated, [self::GENERATED_NEVER, self::GENERATED_INSERT, self::GENERATED_ALWAYS])) { - throw MappingException::invalidGeneratedMode($mapping->generated); - } - - if ($mapping->generated === self::GENERATED_NEVER) { - unset($mapping->generated); - } - } - - if (isset($mapping->enumType)) { - if (! enum_exists($mapping->enumType)) { - throw MappingException::nonEnumTypeMapped($this->name, $mapping->fieldName, $mapping->enumType); - } - - if (! empty($mapping->id)) { - $this->containsEnumIdentifier = true; - } - } - - return $mapping; - } - - /** - * Validates & completes the basic mapping information that is common to all - * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many). - * - * @psalm-param array $mapping The mapping. - * - * @return ConcreteAssociationMapping - * - * @throws MappingException If something is wrong with the mapping. - */ - protected function _validateAndCompleteAssociationMapping(array $mapping): AssociationMapping - { - if (array_key_exists('mappedBy', $mapping) && $mapping['mappedBy'] === null) { - unset($mapping['mappedBy']); - } - - if (array_key_exists('inversedBy', $mapping) && $mapping['inversedBy'] === null) { - unset($mapping['inversedBy']); - } - - if (array_key_exists('joinColumns', $mapping) && in_array($mapping['joinColumns'], [null, []], true)) { - unset($mapping['joinColumns']); - } - - $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy - - if (empty($mapping['indexBy'])) { - unset($mapping['indexBy']); - } - - // If targetEntity is unqualified, assume it is in the same namespace as - // the sourceEntity. - $mapping['sourceEntity'] = $this->name; - - if ($this->isTypedProperty($mapping['fieldName'])) { - $mapping = $this->validateAndCompleteTypedAssociationMapping($mapping); - } - - if (isset($mapping['targetEntity'])) { - $mapping['targetEntity'] = $this->fullyQualifiedClassName($mapping['targetEntity']); - $mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\'); - } - - if (($mapping['type'] & self::MANY_TO_ONE) > 0 && isset($mapping['orphanRemoval']) && $mapping['orphanRemoval']) { - throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']); - } - - // Complete id mapping - if (isset($mapping['id']) && $mapping['id'] === true) { - if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval']) { - throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']); - } - - if (! in_array($mapping['fieldName'], $this->identifier, true)) { - if (isset($mapping['joinColumns']) && count($mapping['joinColumns']) >= 2) { - throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId( - $mapping['targetEntity'], - $this->name, - $mapping['fieldName'], - ); - } - - assert(is_string($mapping['fieldName'])); - $this->identifier[] = $mapping['fieldName']; - $this->containsForeignIdentifier = true; - } - - // Check for composite key - if (! $this->isIdentifierComposite && count($this->identifier) > 1) { - $this->isIdentifierComposite = true; - } - - if ($this->cache && ! isset($mapping['cache'])) { - throw NonCacheableEntityAssociation::fromEntityAndField( - $this->name, - $mapping['fieldName'], - ); - } - } - - // Mandatory attributes for both sides - // Mandatory: fieldName, targetEntity - if (! isset($mapping['fieldName']) || ! $mapping['fieldName']) { - throw MappingException::missingFieldName($this->name); - } - - if (! isset($mapping['targetEntity'])) { - throw MappingException::missingTargetEntity($mapping['fieldName']); - } - - // Mandatory and optional attributes for either side - if (! isset($mapping['mappedBy'])) { - if (isset($mapping['joinTable'])) { - if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') { - $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`'); - $mapping['joinTable']['quoted'] = true; - } - } - } else { - $mapping['isOwningSide'] = false; - } - - if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) { - throw MappingException::illegalToManyIdentifierAssociation($this->name, $mapping['fieldName']); - } - - // Fetch mode. Default fetch mode to LAZY, if not set. - if (! isset($mapping['fetch'])) { - $mapping['fetch'] = self::FETCH_LAZY; - } - - // Cascades - $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : []; - - $allCascades = ['remove', 'persist', 'refresh', 'detach']; - if (in_array('all', $cascades, true)) { - $cascades = $allCascades; - } elseif (count($cascades) !== count(array_intersect($cascades, $allCascades))) { - throw MappingException::invalidCascadeOption( - array_diff($cascades, $allCascades), - $this->name, - $mapping['fieldName'], - ); - } - - $mapping['cascade'] = $cascades; - - switch ($mapping['type']) { - case self::ONE_TO_ONE: - if (isset($mapping['joinColumns']) && $mapping['joinColumns'] && ! $mapping['isOwningSide']) { - throw MappingException::joinColumnNotAllowedOnOneToOneInverseSide( - $this->name, - $mapping['fieldName'], - ); - } - - return $mapping['isOwningSide'] ? - OneToOneOwningSideMapping::fromMappingArrayAndName( - $mapping, - $this->namingStrategy, - $this->name, - $this->table ?? null, - $this->isInheritanceTypeSingleTable(), - ) : - OneToOneInverseSideMapping::fromMappingArrayAndName($mapping, $this->name); - - case self::MANY_TO_ONE: - return ManyToOneAssociationMapping::fromMappingArrayAndName( - $mapping, - $this->namingStrategy, - $this->name, - $this->table ?? null, - $this->isInheritanceTypeSingleTable(), - ); - - case self::ONE_TO_MANY: - return OneToManyAssociationMapping::fromMappingArrayAndName($mapping, $this->name); - - case self::MANY_TO_MANY: - if (isset($mapping['joinColumns'])) { - unset($mapping['joinColumns']); - } - - return $mapping['isOwningSide'] ? - ManyToManyOwningSideMapping::fromMappingArrayAndNamingStrategy($mapping, $this->namingStrategy) : - ManyToManyInverseSideMapping::fromMappingArray($mapping); - - default: - throw MappingException::invalidAssociationType( - $this->name, - $mapping['fieldName'], - $mapping['type'], - ); - } - } - - /** - * {@inheritDoc} - */ - public function getIdentifierFieldNames(): array - { - return $this->identifier; - } - - /** - * Gets the name of the single id field. Note that this only works on - * entity classes that have a single-field pk. - * - * @throws MappingException If the class doesn't have an identifier or it has a composite primary key. - */ - public function getSingleIdentifierFieldName(): string - { - if ($this->isIdentifierComposite) { - throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name); - } - - if (! isset($this->identifier[0])) { - throw MappingException::noIdDefined($this->name); - } - - return $this->identifier[0]; - } - - /** - * Gets the column name of the single id column. Note that this only works on - * entity classes that have a single-field pk. - * - * @throws MappingException If the class doesn't have an identifier or it has a composite primary key. - */ - public function getSingleIdentifierColumnName(): string - { - return $this->getColumnName($this->getSingleIdentifierFieldName()); - } - - /** - * INTERNAL: - * Sets the mapped identifier/primary key fields of this class. - * Mainly used by the ClassMetadataFactory to assign inherited identifiers. - * - * @psalm-param list $identifier - */ - public function setIdentifier(array $identifier): void - { - $this->identifier = $identifier; - $this->isIdentifierComposite = (count($this->identifier) > 1); - } - - /** - * {@inheritDoc} - */ - public function getIdentifier(): array - { - return $this->identifier; - } - - public function hasField(string $fieldName): bool - { - return isset($this->fieldMappings[$fieldName]) || isset($this->embeddedClasses[$fieldName]); - } - - /** - * Gets an array containing all the column names. - * - * @psalm-param list|null $fieldNames - * - * @return mixed[] - * @psalm-return list - */ - public function getColumnNames(array|null $fieldNames = null): array - { - if ($fieldNames === null) { - return array_keys($this->fieldNames); - } - - return array_values(array_map($this->getColumnName(...), $fieldNames)); - } - - /** - * Returns an array with all the identifier column names. - * - * @psalm-return list - */ - public function getIdentifierColumnNames(): array - { - $columnNames = []; - - foreach ($this->identifier as $idProperty) { - if (isset($this->fieldMappings[$idProperty])) { - $columnNames[] = $this->fieldMappings[$idProperty]->columnName; - - continue; - } - - // Association defined as Id field - assert($this->associationMappings[$idProperty]->isToOneOwningSide()); - $joinColumns = $this->associationMappings[$idProperty]->joinColumns; - $assocColumnNames = array_map(static fn (JoinColumnMapping $joinColumn): string => $joinColumn->name, $joinColumns); - - $columnNames = array_merge($columnNames, $assocColumnNames); - } - - return $columnNames; - } - - /** - * Sets the type of Id generator to use for the mapped class. - * - * @psalm-param self::GENERATOR_TYPE_* $generatorType - */ - public function setIdGeneratorType(int $generatorType): void - { - $this->generatorType = $generatorType; - } - - /** - * Checks whether the mapped class uses an Id generator. - */ - public function usesIdGenerator(): bool - { - return $this->generatorType !== self::GENERATOR_TYPE_NONE; - } - - public function isInheritanceTypeNone(): bool - { - return $this->inheritanceType === self::INHERITANCE_TYPE_NONE; - } - - /** - * Checks whether the mapped class uses the JOINED inheritance mapping strategy. - * - * @return bool TRUE if the class participates in a JOINED inheritance mapping, - * FALSE otherwise. - */ - public function isInheritanceTypeJoined(): bool - { - return $this->inheritanceType === self::INHERITANCE_TYPE_JOINED; - } - - /** - * Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy. - * - * @return bool TRUE if the class participates in a SINGLE_TABLE inheritance mapping, - * FALSE otherwise. - */ - public function isInheritanceTypeSingleTable(): bool - { - return $this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_TABLE; - } - - /** - * Checks whether the class uses an identity column for the Id generation. - */ - public function isIdGeneratorIdentity(): bool - { - return $this->generatorType === self::GENERATOR_TYPE_IDENTITY; - } - - /** - * Checks whether the class uses a sequence for id generation. - * - * @psalm-assert-if-true !null $this->sequenceGeneratorDefinition - */ - public function isIdGeneratorSequence(): bool - { - return $this->generatorType === self::GENERATOR_TYPE_SEQUENCE; - } - - /** - * Checks whether the class has a natural identifier/pk (which means it does - * not use any Id generator. - */ - public function isIdentifierNatural(): bool - { - return $this->generatorType === self::GENERATOR_TYPE_NONE; - } - - /** - * Gets the type of a field. - * - * @todo 3.0 Remove this. PersisterHelper should fix it somehow - */ - public function getTypeOfField(string $fieldName): string|null - { - return isset($this->fieldMappings[$fieldName]) - ? $this->fieldMappings[$fieldName]->type - : null; - } - - /** - * Gets the name of the primary table. - */ - public function getTableName(): string - { - return $this->table['name']; - } - - /** - * Gets primary table's schema name. - */ - public function getSchemaName(): string|null - { - return $this->table['schema'] ?? null; - } - - /** - * Gets the table name to use for temporary identifier tables of this class. - */ - public function getTemporaryIdTableName(): string - { - // replace dots with underscores because PostgreSQL creates temporary tables in a special schema - return str_replace('.', '_', $this->getTableName() . '_id_tmp'); - } - - /** - * Sets the mapped subclasses of this class. - * - * @psalm-param list $subclasses The names of all mapped subclasses. - */ - public function setSubclasses(array $subclasses): void - { - foreach ($subclasses as $subclass) { - $this->subClasses[] = $this->fullyQualifiedClassName($subclass); - } - } - - /** - * Sets the parent class names. Only entity classes may be given. - * - * Assumes that the class names in the passed array are in the order: - * directParent -> directParentParent -> directParentParentParent ... -> root. - * - * @psalm-param list $classNames - */ - public function setParentClasses(array $classNames): void - { - $this->parentClasses = $classNames; - - if (count($classNames) > 0) { - $this->rootEntityName = array_pop($classNames); - } - } - - /** - * Sets the inheritance type used by the class and its subclasses. - * - * @psalm-param self::INHERITANCE_TYPE_* $type - * - * @throws MappingException - */ - public function setInheritanceType(int $type): void - { - if (! $this->isInheritanceType($type)) { - throw MappingException::invalidInheritanceType($this->name, $type); - } - - $this->inheritanceType = $type; - } - - /** - * Sets the association to override association mapping of property for an entity relationship. - * - * @psalm-param array $overrideMapping - * - * @throws MappingException - */ - public function setAssociationOverride(string $fieldName, array $overrideMapping): void - { - if (! isset($this->associationMappings[$fieldName])) { - throw MappingException::invalidOverrideFieldName($this->name, $fieldName); - } - - $mapping = $this->associationMappings[$fieldName]->toArray(); - - if (isset($mapping['inherited'])) { - throw MappingException::illegalOverrideOfInheritedProperty( - $this->name, - $fieldName, - $mapping['inherited'], - ); - } - - if (isset($overrideMapping['joinColumns'])) { - $mapping['joinColumns'] = $overrideMapping['joinColumns']; - } - - if (isset($overrideMapping['inversedBy'])) { - $mapping['inversedBy'] = $overrideMapping['inversedBy']; - } - - if (isset($overrideMapping['joinTable'])) { - $mapping['joinTable'] = $overrideMapping['joinTable']; - } - - if (isset($overrideMapping['fetch'])) { - $mapping['fetch'] = $overrideMapping['fetch']; - } - - switch ($mapping['type']) { - case self::ONE_TO_ONE: - case self::MANY_TO_ONE: - $mapping['joinColumnFieldNames'] = []; - $mapping['sourceToTargetKeyColumns'] = []; - break; - case self::MANY_TO_MANY: - $mapping['relationToSourceKeyColumns'] = []; - $mapping['relationToTargetKeyColumns'] = []; - break; - } - - $this->associationMappings[$fieldName] = $this->_validateAndCompleteAssociationMapping($mapping); - } - - /** - * Sets the override for a mapped field. - * - * @psalm-param array $overrideMapping - * - * @throws MappingException - */ - public function setAttributeOverride(string $fieldName, array $overrideMapping): void - { - if (! isset($this->fieldMappings[$fieldName])) { - throw MappingException::invalidOverrideFieldName($this->name, $fieldName); - } - - $mapping = $this->fieldMappings[$fieldName]; - - if (isset($mapping->inherited)) { - throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName, $mapping->inherited); - } - - if (isset($mapping->id)) { - $overrideMapping['id'] = $mapping->id; - } - - if (isset($mapping->declared)) { - $overrideMapping['declared'] = $mapping->declared; - } - - if (! isset($overrideMapping['type'])) { - $overrideMapping['type'] = $mapping->type; - } - - if (! isset($overrideMapping['fieldName'])) { - $overrideMapping['fieldName'] = $mapping->fieldName; - } - - if ($overrideMapping['type'] !== $mapping->type) { - throw MappingException::invalidOverrideFieldType($this->name, $fieldName); - } - - unset($this->fieldMappings[$fieldName]); - unset($this->fieldNames[$mapping->columnName]); - unset($this->columnNames[$mapping->fieldName]); - - $overrideMapping = $this->validateAndCompleteFieldMapping($overrideMapping); - - $this->fieldMappings[$fieldName] = $overrideMapping; - } - - /** - * Checks whether a mapped field is inherited from an entity superclass. - */ - public function isInheritedField(string $fieldName): bool - { - return isset($this->fieldMappings[$fieldName]->inherited); - } - - /** - * Checks if this entity is the root in any entity-inheritance-hierarchy. - */ - public function isRootEntity(): bool - { - return $this->name === $this->rootEntityName; - } - - /** - * Checks whether a mapped association field is inherited from a superclass. - */ - public function isInheritedAssociation(string $fieldName): bool - { - return isset($this->associationMappings[$fieldName]->inherited); - } - - public function isInheritedEmbeddedClass(string $fieldName): bool - { - return isset($this->embeddedClasses[$fieldName]->inherited); - } - - /** - * Sets the name of the primary table the class is mapped to. - * - * @deprecated Use {@link setPrimaryTable}. - */ - public function setTableName(string $tableName): void - { - $this->table['name'] = $tableName; - } - - /** - * Sets the primary table definition. The provided array supports the - * following structure: - * - * name => (optional, defaults to class name) - * indexes => array of indexes (optional) - * uniqueConstraints => array of constraints (optional) - * - * If a key is omitted, the current value is kept. - * - * @psalm-param array $table The table description. - */ - public function setPrimaryTable(array $table): void - { - if (isset($table['name'])) { - // Split schema and table name from a table name like "myschema.mytable" - if (str_contains($table['name'], '.')) { - [$this->table['schema'], $table['name']] = explode('.', $table['name'], 2); - } - - if ($table['name'][0] === '`') { - $table['name'] = trim($table['name'], '`'); - $this->table['quoted'] = true; - } - - $this->table['name'] = $table['name']; - } - - if (isset($table['quoted'])) { - $this->table['quoted'] = $table['quoted']; - } - - if (isset($table['schema'])) { - $this->table['schema'] = $table['schema']; - } - - if (isset($table['indexes'])) { - $this->table['indexes'] = $table['indexes']; - } - - if (isset($table['uniqueConstraints'])) { - $this->table['uniqueConstraints'] = $table['uniqueConstraints']; - } - - if (isset($table['options'])) { - $this->table['options'] = $table['options']; - } - } - - /** - * Checks whether the given type identifies an inheritance type. - */ - private function isInheritanceType(int $type): bool - { - return $type === self::INHERITANCE_TYPE_NONE || - $type === self::INHERITANCE_TYPE_SINGLE_TABLE || - $type === self::INHERITANCE_TYPE_JOINED; - } - - /** - * Adds a mapped field to the class. - * - * @psalm-param array $mapping The field mapping. - * - * @throws MappingException - */ - public function mapField(array $mapping): void - { - $mapping = $this->validateAndCompleteFieldMapping($mapping); - $this->assertFieldNotMapped($mapping->fieldName); - - if (isset($mapping->generated)) { - $this->requiresFetchAfterChange = true; - } - - $this->fieldMappings[$mapping->fieldName] = $mapping; - } - - /** - * INTERNAL: - * Adds an association mapping without completing/validating it. - * This is mainly used to add inherited association mappings to derived classes. - * - * @param ConcreteAssociationMapping $mapping - * - * @throws MappingException - */ - public function addInheritedAssociationMapping(AssociationMapping $mapping/*, $owningClassName = null*/): void - { - if (isset($this->associationMappings[$mapping->fieldName])) { - throw MappingException::duplicateAssociationMapping($this->name, $mapping->fieldName); - } - - $this->associationMappings[$mapping->fieldName] = $mapping; - } - - /** - * INTERNAL: - * Adds a field mapping without completing/validating it. - * This is mainly used to add inherited field mappings to derived classes. - */ - public function addInheritedFieldMapping(FieldMapping $fieldMapping): void - { - $this->fieldMappings[$fieldMapping->fieldName] = $fieldMapping; - $this->columnNames[$fieldMapping->fieldName] = $fieldMapping->columnName; - $this->fieldNames[$fieldMapping->columnName] = $fieldMapping->fieldName; - - if (isset($fieldMapping->generated)) { - $this->requiresFetchAfterChange = true; - } - } - - /** - * Adds a one-to-one mapping. - * - * @param array $mapping The mapping. - */ - public function mapOneToOne(array $mapping): void - { - $mapping['type'] = self::ONE_TO_ONE; - - $mapping = $this->_validateAndCompleteAssociationMapping($mapping); - - $this->_storeAssociationMapping($mapping); - } - - /** - * Adds a one-to-many mapping. - * - * @psalm-param array $mapping The mapping. - */ - public function mapOneToMany(array $mapping): void - { - $mapping['type'] = self::ONE_TO_MANY; - - $mapping = $this->_validateAndCompleteAssociationMapping($mapping); - - $this->_storeAssociationMapping($mapping); - } - - /** - * Adds a many-to-one mapping. - * - * @psalm-param array $mapping The mapping. - */ - public function mapManyToOne(array $mapping): void - { - $mapping['type'] = self::MANY_TO_ONE; - - $mapping = $this->_validateAndCompleteAssociationMapping($mapping); - - $this->_storeAssociationMapping($mapping); - } - - /** - * Adds a many-to-many mapping. - * - * @psalm-param array $mapping The mapping. - */ - public function mapManyToMany(array $mapping): void - { - $mapping['type'] = self::MANY_TO_MANY; - - $mapping = $this->_validateAndCompleteAssociationMapping($mapping); - - $this->_storeAssociationMapping($mapping); - } - - /** - * Stores the association mapping. - * - * @param ConcreteAssociationMapping $assocMapping - * - * @throws MappingException - */ - protected function _storeAssociationMapping(AssociationMapping $assocMapping): void - { - $sourceFieldName = $assocMapping->fieldName; - - $this->assertFieldNotMapped($sourceFieldName); - - $this->associationMappings[$sourceFieldName] = $assocMapping; - } - - /** - * Registers a custom repository class for the entity class. - * - * @param string|null $repositoryClassName The class name of the custom mapper. - * @psalm-param class-string|null $repositoryClassName - */ - public function setCustomRepositoryClass(string|null $repositoryClassName): void - { - if ($repositoryClassName === null) { - $this->customRepositoryClassName = null; - - return; - } - - $this->customRepositoryClassName = $this->fullyQualifiedClassName($repositoryClassName); - } - - /** - * Dispatches the lifecycle event of the given entity to the registered - * lifecycle callbacks and lifecycle listeners. - * - * @deprecated Deprecated since version 2.4 in favor of \Doctrine\ORM\Event\ListenersInvoker - * - * @param string $lifecycleEvent The lifecycle event. - */ - public function invokeLifecycleCallbacks(string $lifecycleEvent, object $entity): void - { - foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) { - $entity->$callback(); - } - } - - /** - * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event. - */ - public function hasLifecycleCallbacks(string $lifecycleEvent): bool - { - return isset($this->lifecycleCallbacks[$lifecycleEvent]); - } - - /** - * Gets the registered lifecycle callbacks for an event. - * - * @return string[] - * @psalm-return list - */ - public function getLifecycleCallbacks(string $event): array - { - return $this->lifecycleCallbacks[$event] ?? []; - } - - /** - * Adds a lifecycle callback for entities of this class. - */ - public function addLifecycleCallback(string $callback, string $event): void - { - if ($this->isEmbeddedClass) { - throw MappingException::illegalLifecycleCallbackOnEmbeddedClass($callback, $this->name); - } - - if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], true)) { - return; - } - - $this->lifecycleCallbacks[$event][] = $callback; - } - - /** - * Sets the lifecycle callbacks for entities of this class. - * Any previously registered callbacks are overwritten. - * - * @psalm-param array> $callbacks - */ - public function setLifecycleCallbacks(array $callbacks): void - { - $this->lifecycleCallbacks = $callbacks; - } - - /** - * Adds a entity listener for entities of this class. - * - * @param string $eventName The entity lifecycle event. - * @param string $class The listener class. - * @param string $method The listener callback method. - * - * @throws MappingException - */ - public function addEntityListener(string $eventName, string $class, string $method): void - { - $class = $this->fullyQualifiedClassName($class); - - $listener = [ - 'class' => $class, - 'method' => $method, - ]; - - if (! class_exists($class)) { - throw MappingException::entityListenerClassNotFound($class, $this->name); - } - - if (! method_exists($class, $method)) { - throw MappingException::entityListenerMethodNotFound($class, $method, $this->name); - } - - if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName], true)) { - throw MappingException::duplicateEntityListener($class, $method, $this->name); - } - - $this->entityListeners[$eventName][] = $listener; - } - - /** - * Sets the discriminator column definition. - * - * @see getDiscriminatorColumn() - * - * @param DiscriminatorColumnMapping|mixed[]|null $columnDef - * @psalm-param DiscriminatorColumnMapping|array{ - * name: string|null, - * fieldName?: string|null, - * type?: string|null, - * length?: int|null, - * columnDefinition?: string|null, - * enumType?: class-string|null, - * options?: array|null - * }|null $columnDef - * - * @throws MappingException - */ - public function setDiscriminatorColumn(DiscriminatorColumnMapping|array|null $columnDef): void - { - if ($columnDef instanceof DiscriminatorColumnMapping) { - $this->discriminatorColumn = $columnDef; - - return; - } - - if ($columnDef !== null) { - if (! isset($columnDef['name'])) { - throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name); - } - - if (isset($this->fieldNames[$columnDef['name']])) { - throw MappingException::duplicateColumnName($this->name, $columnDef['name']); - } - - $columnDef['fieldName'] ??= $columnDef['name']; - $columnDef['type'] ??= 'string'; - $columnDef['options'] ??= []; - - if (in_array($columnDef['type'], ['boolean', 'array', 'object', 'datetime', 'time', 'date'], true)) { - throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']); - } - - $this->discriminatorColumn = DiscriminatorColumnMapping::fromMappingArray($columnDef); - } - } - - final public function getDiscriminatorColumn(): DiscriminatorColumnMapping - { - if ($this->discriminatorColumn === null) { - throw new LogicException('The discriminator column was not set.'); - } - - return $this->discriminatorColumn; - } - - /** - * Sets the discriminator values used by this class. - * Used for JOINED and SINGLE_TABLE inheritance mapping strategies. - * - * @param array $map - */ - public function setDiscriminatorMap(array $map): void - { - foreach ($map as $value => $className) { - $this->addDiscriminatorMapClass($value, $className); - } - } - - /** - * Adds one entry of the discriminator map with a new class and corresponding name. - * - * @throws MappingException - */ - public function addDiscriminatorMapClass(int|string $name, string $className): void - { - $className = $this->fullyQualifiedClassName($className); - $className = ltrim($className, '\\'); - - $this->discriminatorMap[$name] = $className; - - if ($this->name === $className) { - $this->discriminatorValue = $name; - - return; - } - - if (! (class_exists($className) || interface_exists($className))) { - throw MappingException::invalidClassInDiscriminatorMap($className, $this->name); - } - - $this->addSubClass($className); - } - - /** @param array $classes */ - public function addSubClasses(array $classes): void - { - foreach ($classes as $className) { - $this->addSubClass($className); - } - } - - public function addSubClass(string $className): void - { - // By ignoring classes that are not subclasses of the current class, we simplify inheriting - // the subclass list from a parent class at the beginning of \Doctrine\ORM\Mapping\ClassMetadataFactory::doLoadMetadata. - - if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses, true)) { - $this->subClasses[] = $className; - } - } - - public function hasAssociation(string $fieldName): bool - { - return isset($this->associationMappings[$fieldName]); - } - - public function isSingleValuedAssociation(string $fieldName): bool - { - return isset($this->associationMappings[$fieldName]) - && ($this->associationMappings[$fieldName]->isToOne()); - } - - public function isCollectionValuedAssociation(string $fieldName): bool - { - return isset($this->associationMappings[$fieldName]) - && ! $this->associationMappings[$fieldName]->isToOne(); - } - - /** - * Is this an association that only has a single join column? - */ - public function isAssociationWithSingleJoinColumn(string $fieldName): bool - { - return isset($this->associationMappings[$fieldName]) - && isset($this->associationMappings[$fieldName]->joinColumns[0]) - && ! isset($this->associationMappings[$fieldName]->joinColumns[1]); - } - - /** - * Returns the single association join column (if any). - * - * @throws MappingException - */ - public function getSingleAssociationJoinColumnName(string $fieldName): string - { - if (! $this->isAssociationWithSingleJoinColumn($fieldName)) { - throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); - } - - $assoc = $this->associationMappings[$fieldName]; - - assert($assoc->isToOneOwningSide()); - - return $assoc->joinColumns[0]->name; - } - - /** - * Returns the single association referenced join column name (if any). - * - * @throws MappingException - */ - public function getSingleAssociationReferencedJoinColumnName(string $fieldName): string - { - if (! $this->isAssociationWithSingleJoinColumn($fieldName)) { - throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); - } - - $assoc = $this->associationMappings[$fieldName]; - - assert($assoc->isToOneOwningSide()); - - return $assoc->joinColumns[0]->referencedColumnName; - } - - /** - * Used to retrieve a fieldname for either field or association from a given column. - * - * This method is used in foreign-key as primary-key contexts. - * - * @throws MappingException - */ - public function getFieldForColumn(string $columnName): string - { - if (isset($this->fieldNames[$columnName])) { - return $this->fieldNames[$columnName]; - } - - foreach ($this->associationMappings as $assocName => $mapping) { - if ( - $this->isAssociationWithSingleJoinColumn($assocName) && - assert($this->associationMappings[$assocName]->isToOneOwningSide()) && - $this->associationMappings[$assocName]->joinColumns[0]->name === $columnName - ) { - return $assocName; - } - } - - throw MappingException::noFieldNameFoundForColumn($this->name, $columnName); - } - - /** - * Sets the ID generator used to generate IDs for instances of this class. - */ - public function setIdGenerator(AbstractIdGenerator $generator): void - { - $this->idGenerator = $generator; - } - - /** - * Sets definition. - * - * @psalm-param array $definition - */ - public function setCustomGeneratorDefinition(array $definition): void - { - $this->customGeneratorDefinition = $definition; - } - - /** - * Sets the definition of the sequence ID generator for this class. - * - * The definition must have the following structure: - * - * array( - * 'sequenceName' => 'name', - * 'allocationSize' => 20, - * 'initialValue' => 1 - * 'quoted' => 1 - * ) - * - * - * @psalm-param array{sequenceName?: string, allocationSize?: int|string, initialValue?: int|string, quoted?: mixed} $definition - * - * @throws MappingException - */ - public function setSequenceGeneratorDefinition(array $definition): void - { - if (! isset($definition['sequenceName']) || trim($definition['sequenceName']) === '') { - throw MappingException::missingSequenceName($this->name); - } - - if ($definition['sequenceName'][0] === '`') { - $definition['sequenceName'] = trim($definition['sequenceName'], '`'); - $definition['quoted'] = true; - } - - if (! isset($definition['allocationSize']) || trim((string) $definition['allocationSize']) === '') { - $definition['allocationSize'] = '1'; - } - - if (! isset($definition['initialValue']) || trim((string) $definition['initialValue']) === '') { - $definition['initialValue'] = '1'; - } - - $definition['allocationSize'] = (string) $definition['allocationSize']; - $definition['initialValue'] = (string) $definition['initialValue']; - - $this->sequenceGeneratorDefinition = $definition; - } - - /** - * Sets the version field mapping used for versioning. Sets the default - * value to use depending on the column type. - * - * @psalm-param array $mapping The version field mapping array. - * - * @throws MappingException - */ - public function setVersionMapping(array &$mapping): void - { - $this->isVersioned = true; - $this->versionField = $mapping['fieldName']; - $this->requiresFetchAfterChange = true; - - if (! isset($mapping['default'])) { - if (in_array($mapping['type'], ['integer', 'bigint', 'smallint'], true)) { - $mapping['default'] = 1; - } elseif ($mapping['type'] === 'datetime') { - $mapping['default'] = 'CURRENT_TIMESTAMP'; - } else { - throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']); - } - } - } - - /** - * Sets whether this class is to be versioned for optimistic locking. - */ - public function setVersioned(bool $bool): void - { - $this->isVersioned = $bool; - - if ($bool) { - $this->requiresFetchAfterChange = true; - } - } - - /** - * Sets the name of the field that is to be used for versioning if this class is - * versioned for optimistic locking. - */ - public function setVersionField(string|null $versionField): void - { - $this->versionField = $versionField; - } - - /** - * Marks this class as read only, no change tracking is applied to it. - */ - public function markReadOnly(): void - { - $this->isReadOnly = true; - } - - /** - * {@inheritDoc} - */ - public function getFieldNames(): array - { - return array_keys($this->fieldMappings); - } - - /** - * {@inheritDoc} - */ - public function getAssociationNames(): array - { - return array_keys($this->associationMappings); - } - - /** - * {@inheritDoc} - * - * @psalm-return class-string - * - * @throws InvalidArgumentException - */ - public function getAssociationTargetClass(string $assocName): string - { - return $this->associationMappings[$assocName]->targetEntity - ?? throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association."); - } - - public function getName(): string - { - return $this->name; - } - - public function isAssociationInverseSide(string $assocName): bool - { - return isset($this->associationMappings[$assocName]) - && ! $this->associationMappings[$assocName]->isOwningSide(); - } - - public function getAssociationMappedByTargetField(string $assocName): string - { - $assoc = $this->getAssociationMapping($assocName); - - if (! $assoc instanceof InverseSideMapping) { - throw new LogicException(sprintf( - <<<'EXCEPTION' - Context: Calling %s() with "%s", which is the owning side of an association. - Problem: The owning side of an association has no "mappedBy" field. - Solution: Call %s::isAssociationInverseSide() to check first. - EXCEPTION, - __METHOD__, - $assocName, - self::class, - )); - } - - return $assoc->mappedBy; - } - - /** - * @param C $className - * - * @return string|null null if and only if the input value is null - * @psalm-return (C is class-string ? class-string : (C is string ? string : null)) - * - * @template C of string|null - */ - public function fullyQualifiedClassName(string|null $className): string|null - { - if ($className === null) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11294', - 'Passing null to %s is deprecated and will not be supported in Doctrine ORM 4.0', - __METHOD__, - ); - - return null; - } - - if (! str_contains($className, '\\') && $this->namespace) { - return $this->namespace . '\\' . $className; - } - - return $className; - } - - public function getMetadataValue(string $name): mixed - { - return $this->$name ?? null; - } - - /** - * Map Embedded Class - * - * @psalm-param array{ - * fieldName: string, - * class?: class-string, - * declaredField?: string, - * columnPrefix?: string|false|null, - * originalField?: string - * } $mapping - * - * @throws MappingException - */ - public function mapEmbedded(array $mapping): void - { - $this->assertFieldNotMapped($mapping['fieldName']); - - if (! isset($mapping['class']) && $this->isTypedProperty($mapping['fieldName'])) { - $type = $this->reflClass->getProperty($mapping['fieldName'])->getType(); - if ($type instanceof ReflectionNamedType) { - $mapping['class'] = $type->getName(); - } - } - - if (! (isset($mapping['class']) && $mapping['class'])) { - throw MappingException::missingEmbeddedClass($mapping['fieldName']); - } - - $this->embeddedClasses[$mapping['fieldName']] = EmbeddedClassMapping::fromMappingArray([ - 'class' => $this->fullyQualifiedClassName($mapping['class']), - 'columnPrefix' => $mapping['columnPrefix'] ?? null, - 'declaredField' => $mapping['declaredField'] ?? null, - 'originalField' => $mapping['originalField'] ?? null, - ]); - } - - /** - * Inline the embeddable class - */ - public function inlineEmbeddable(string $property, ClassMetadata $embeddable): void - { - foreach ($embeddable->fieldMappings as $originalFieldMapping) { - $fieldMapping = (array) $originalFieldMapping; - $fieldMapping['originalClass'] ??= $embeddable->name; - $fieldMapping['declaredField'] = isset($fieldMapping['declaredField']) - ? $property . '.' . $fieldMapping['declaredField'] - : $property; - $fieldMapping['originalField'] ??= $fieldMapping['fieldName']; - $fieldMapping['fieldName'] = $property . '.' . $fieldMapping['fieldName']; - - if (! empty($this->embeddedClasses[$property]->columnPrefix)) { - $fieldMapping['columnName'] = $this->embeddedClasses[$property]->columnPrefix . $fieldMapping['columnName']; - } elseif ($this->embeddedClasses[$property]->columnPrefix !== false) { - assert($this->reflClass !== null); - assert($embeddable->reflClass !== null); - $fieldMapping['columnName'] = $this->namingStrategy - ->embeddedFieldToColumnName( - $property, - $fieldMapping['columnName'], - $this->reflClass->name, - $embeddable->reflClass->name, - ); - } - - $this->mapField($fieldMapping); - } - } - - /** @throws MappingException */ - private function assertFieldNotMapped(string $fieldName): void - { - if ( - isset($this->fieldMappings[$fieldName]) || - isset($this->associationMappings[$fieldName]) || - isset($this->embeddedClasses[$fieldName]) - ) { - throw MappingException::duplicateFieldMapping($this->name, $fieldName); - } - } - - /** - * Gets the sequence name based on class metadata. - * - * @todo Sequence names should be computed in DBAL depending on the platform - */ - public function getSequenceName(AbstractPlatform $platform): string - { - $sequencePrefix = $this->getSequencePrefix($platform); - $columnName = $this->getSingleIdentifierColumnName(); - - return $sequencePrefix . '_' . $columnName . '_seq'; - } - - /** - * Gets the sequence name prefix based on class metadata. - * - * @todo Sequence names should be computed in DBAL depending on the platform - */ - public function getSequencePrefix(AbstractPlatform $platform): string - { - $tableName = $this->getTableName(); - $sequencePrefix = $tableName; - - // Prepend the schema name to the table name if there is one - $schemaName = $this->getSchemaName(); - if ($schemaName) { - $sequencePrefix = $schemaName . '.' . $tableName; - } - - return $sequencePrefix; - } - - /** @psalm-param class-string $class */ - private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field): ReflectionProperty|null - { - $reflectionProperty = $reflService->getAccessibleProperty($class, $field); - if ($reflectionProperty?->isReadOnly()) { - $declaringClass = $reflectionProperty->class; - if ($declaringClass !== $class) { - $reflectionProperty = $reflService->getAccessibleProperty($declaringClass, $field); - } - - if ($reflectionProperty !== null) { - $reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty); - } - } - - return $reflectionProperty; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php b/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php deleted file mode 100644 index a3a4701..0000000 --- a/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php +++ /dev/null @@ -1,729 +0,0 @@ - - */ -class ClassMetadataFactory extends AbstractClassMetadataFactory -{ - private EntityManagerInterface|null $em = null; - private AbstractPlatform|null $targetPlatform = null; - private MappingDriver|null $driver = null; - private EventManager|null $evm = null; - - /** @var mixed[] */ - private array $embeddablesActiveNesting = []; - - private const NON_IDENTITY_DEFAULT_STRATEGY = [ - Platforms\OraclePlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE, - ]; - - public function setEntityManager(EntityManagerInterface $em): void - { - parent::setProxyClassNameResolver(new DefaultProxyClassNameResolver()); - - $this->em = $em; - } - - /** - * @param A $maybeOwningSide - * - * @return (A is ManyToManyAssociationMapping ? ManyToManyOwningSideMapping : ( - * A is OneToOneAssociationMapping ? OneToOneOwningSideMapping : ( - * A is OneToManyAssociationMapping ? ManyToOneAssociationMapping : ( - * A is ManyToOneAssociationMapping ? ManyToOneAssociationMapping : - * ManyToManyOwningSideMapping|OneToOneOwningSideMapping|ManyToOneAssociationMapping - * )))) - * - * @template A of AssociationMapping - */ - final public function getOwningSide(AssociationMapping $maybeOwningSide): OwningSideMapping - { - if ($maybeOwningSide instanceof OwningSideMapping) { - assert($maybeOwningSide instanceof ManyToManyOwningSideMapping || - $maybeOwningSide instanceof OneToOneOwningSideMapping || - $maybeOwningSide instanceof ManyToOneAssociationMapping); - - return $maybeOwningSide; - } - - assert($maybeOwningSide instanceof InverseSideMapping); - - $owningSide = $this->getMetadataFor($maybeOwningSide->targetEntity) - ->associationMappings[$maybeOwningSide->mappedBy]; - - assert($owningSide instanceof ManyToManyOwningSideMapping || - $owningSide instanceof OneToOneOwningSideMapping || - $owningSide instanceof ManyToOneAssociationMapping); - - return $owningSide; - } - - protected function initialize(): void - { - $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl(); - $this->evm = $this->em->getEventManager(); - $this->initialized = true; - } - - protected function onNotFoundMetadata(string $className): ClassMetadata|null - { - if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) { - return null; - } - - $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $this->em); - - $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs); - $classMetadata = $eventArgs->getFoundMetadata(); - assert($classMetadata instanceof ClassMetadata || $classMetadata === null); - - return $classMetadata; - } - - /** - * {@inheritDoc} - */ - protected function doLoadMetadata( - ClassMetadataInterface $class, - ClassMetadataInterface|null $parent, - bool $rootEntityFound, - array $nonSuperclassParents, - ): void { - if ($parent) { - $class->setInheritanceType($parent->inheritanceType); - $class->setDiscriminatorColumn($parent->discriminatorColumn === null ? null : clone $parent->discriminatorColumn); - $class->setIdGeneratorType($parent->generatorType); - $this->addInheritedFields($class, $parent); - $this->addInheritedRelations($class, $parent); - $this->addInheritedEmbeddedClasses($class, $parent); - $class->setIdentifier($parent->identifier); - $class->setVersioned($parent->isVersioned); - $class->setVersionField($parent->versionField); - $class->setDiscriminatorMap($parent->discriminatorMap); - $class->addSubClasses($parent->subClasses); - $class->setLifecycleCallbacks($parent->lifecycleCallbacks); - $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); - - if (! empty($parent->customGeneratorDefinition)) { - $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition); - } - - if ($parent->isMappedSuperclass) { - $class->setCustomRepositoryClass($parent->customRepositoryClassName); - } - } - - // Invoke driver - try { - $this->driver->loadMetadataForClass($class->getName(), $class); - } catch (ReflectionException $e) { - throw MappingException::reflectionFailure($class->getName(), $e); - } - - // If this class has a parent the id generator strategy is inherited. - // However this is only true if the hierarchy of parents contains the root entity, - // if it consists of mapped superclasses these don't necessarily include the id field. - if ($parent && $rootEntityFound) { - $this->inheritIdGeneratorMapping($class, $parent); - } else { - $this->completeIdGeneratorMapping($class); - } - - if (! $class->isMappedSuperclass) { - if ($rootEntityFound && $class->isInheritanceTypeNone()) { - throw MappingException::missingInheritanceTypeDeclaration(end($nonSuperclassParents), $class->name); - } - - foreach ($class->embeddedClasses as $property => $embeddableClass) { - if (isset($embeddableClass->inherited)) { - continue; - } - - if (isset($this->embeddablesActiveNesting[$embeddableClass->class])) { - throw MappingException::infiniteEmbeddableNesting($class->name, $property); - } - - $this->embeddablesActiveNesting[$class->name] = true; - - $embeddableMetadata = $this->getMetadataFor($embeddableClass->class); - - if ($embeddableMetadata->isEmbeddedClass) { - $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); - } - - $identifier = $embeddableMetadata->getIdentifier(); - - if (! empty($identifier)) { - $this->inheritIdGeneratorMapping($class, $embeddableMetadata); - } - - $class->inlineEmbeddable($property, $embeddableMetadata); - - unset($this->embeddablesActiveNesting[$class->name]); - } - } - - if ($parent) { - if ($parent->isInheritanceTypeSingleTable()) { - $class->setPrimaryTable($parent->table); - } - - $this->addInheritedIndexes($class, $parent); - - if ($parent->cache) { - $class->cache = $parent->cache; - } - - if ($parent->containsForeignIdentifier) { - $class->containsForeignIdentifier = true; - } - - if ($parent->containsEnumIdentifier) { - $class->containsEnumIdentifier = true; - } - - if (! empty($parent->entityListeners) && empty($class->entityListeners)) { - $class->entityListeners = $parent->entityListeners; - } - } - - $class->setParentClasses($nonSuperclassParents); - - if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) { - $this->addDefaultDiscriminatorMap($class); - } - - // During the following event, there may also be updates to the discriminator map as per GH-1257/GH-8402. - // So, we must not discover the missing subclasses before that. - - if ($this->evm->hasListeners(Events::loadClassMetadata)) { - $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); - $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); - } - - $this->findAbstractEntityClassesNotListedInDiscriminatorMap($class); - - $this->validateRuntimeMetadata($class, $parent); - } - - /** - * Validate runtime metadata is correctly defined. - * - * @throws MappingException - */ - protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadataInterface|null $parent): void - { - if (! $class->reflClass) { - // only validate if there is a reflection class instance - return; - } - - $class->validateIdentifier(); - $class->validateAssociations(); - $class->validateLifecycleCallbacks($this->getReflectionService()); - - // verify inheritance - if (! $class->isMappedSuperclass && ! $class->isInheritanceTypeNone()) { - if (! $parent) { - if (count($class->discriminatorMap) === 0) { - throw MappingException::missingDiscriminatorMap($class->name); - } - - if (! $class->discriminatorColumn) { - throw MappingException::missingDiscriminatorColumn($class->name); - } - - foreach ($class->subClasses as $subClass) { - if ((new ReflectionClass($subClass))->name !== $subClass) { - throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name); - } - } - } else { - assert($parent instanceof ClassMetadata); // https://github.com/doctrine/orm/issues/8746 - if ( - ! $class->reflClass->isAbstract() - && ! in_array($class->name, $class->discriminatorMap, true) - ) { - throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName); - } - } - } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) { - // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy - throw MappingException::noInheritanceOnMappedSuperClass($class->name); - } - } - - protected function newClassMetadataInstance(string $className): ClassMetadata - { - return new ClassMetadata( - $className, - $this->em->getConfiguration()->getNamingStrategy(), - $this->em->getConfiguration()->getTypedFieldMapper(), - ); - } - - /** - * Adds a default discriminator map if no one is given - * - * If an entity is of any inheritance type and does not contain a - * discriminator map, then the map is generated automatically. This process - * is expensive computation wise. - * - * The automatically generated discriminator map contains the lowercase short name of - * each class as key. - * - * @throws MappingException - */ - private function addDefaultDiscriminatorMap(ClassMetadata $class): void - { - $allClasses = $this->driver->getAllClassNames(); - $fqcn = $class->getName(); - $map = [$this->getShortName($class->name) => $fqcn]; - - $duplicates = []; - foreach ($allClasses as $subClassCandidate) { - if (is_subclass_of($subClassCandidate, $fqcn)) { - $shortName = $this->getShortName($subClassCandidate); - - if (isset($map[$shortName])) { - $duplicates[] = $shortName; - } - - $map[$shortName] = $subClassCandidate; - } - } - - if ($duplicates) { - throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map); - } - - $class->setDiscriminatorMap($map); - } - - private function findAbstractEntityClassesNotListedInDiscriminatorMap(ClassMetadata $rootEntityClass): void - { - // Only root classes in inheritance hierarchies need contain a discriminator map, - // so skip for other classes. - if (! $rootEntityClass->isRootEntity() || $rootEntityClass->isInheritanceTypeNone()) { - return; - } - - $processedClasses = [$rootEntityClass->name => true]; - foreach ($rootEntityClass->subClasses as $knownSubClass) { - $processedClasses[$knownSubClass] = true; - } - - foreach ($rootEntityClass->discriminatorMap as $declaredClassName) { - // This fetches non-transient parent classes only - $parentClasses = $this->getParentClasses($declaredClassName); - - foreach ($parentClasses as $parentClass) { - if (isset($processedClasses[$parentClass])) { - continue; - } - - $processedClasses[$parentClass] = true; - - // All non-abstract entity classes must be listed in the discriminator map, and - // this will be validated/enforced at runtime (possibly at a later time, when the - // subclass is loaded, but anyways). Also, subclasses is about entity classes only. - // That means we can ignore non-abstract classes here. The (expensive) driver - // check for mapped superclasses need only be run for abstract candidate classes. - if (! (new ReflectionClass($parentClass))->isAbstract() || $this->peekIfIsMappedSuperclass($parentClass)) { - continue; - } - - // We have found a non-transient, non-mapped-superclass = an entity class (possibly abstract, but that does not matter) - $rootEntityClass->addSubClass($parentClass); - } - } - } - - /** @param class-string $className */ - private function peekIfIsMappedSuperclass(string $className): bool - { - $reflService = $this->getReflectionService(); - $class = $this->newClassMetadataInstance($className); - $this->initializeReflection($class, $reflService); - - $this->getDriver()->loadMetadataForClass($className, $class); - - return $class->isMappedSuperclass; - } - - /** - * Gets the lower-case short name of a class. - * - * @psalm-param class-string $className - */ - private function getShortName(string $className): string - { - if (! str_contains($className, '\\')) { - return strtolower($className); - } - - $parts = explode('\\', $className); - - return strtolower(end($parts)); - } - - /** - * Puts the `inherited` and `declared` values into mapping information for fields, associations - * and embedded classes. - */ - private function addMappingInheritanceInformation( - AssociationMapping|EmbeddedClassMapping|FieldMapping $mapping, - ClassMetadata $parentClass, - ): void { - if (! isset($mapping->inherited) && ! $parentClass->isMappedSuperclass) { - $mapping->inherited = $parentClass->name; - } - - if (! isset($mapping->declared)) { - $mapping->declared = $parentClass->name; - } - } - - /** - * Adds inherited fields to the subclass mapping. - */ - private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void - { - foreach ($parentClass->fieldMappings as $mapping) { - $subClassMapping = clone $mapping; - $this->addMappingInheritanceInformation($subClassMapping, $parentClass); - $subClass->addInheritedFieldMapping($subClassMapping); - } - - foreach ($parentClass->reflFields as $name => $field) { - $subClass->reflFields[$name] = $field; - } - } - - /** - * Adds inherited association mappings to the subclass mapping. - * - * @throws MappingException - */ - private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass): void - { - foreach ($parentClass->associationMappings as $field => $mapping) { - $subClassMapping = clone $mapping; - $this->addMappingInheritanceInformation($subClassMapping, $parentClass); - // When the class inheriting the relation ($subClass) is the first entity class since the - // relation has been defined in a mapped superclass (or in a chain - // of mapped superclasses) above, then declare this current entity class as the source of - // the relationship. - // According to the definitions given in https://github.com/doctrine/orm/pull/10396/, - // this is the case <=> ! isset($mapping['inherited']). - if (! isset($subClassMapping->inherited)) { - $subClassMapping->sourceEntity = $subClass->name; - } - - $subClass->addInheritedAssociationMapping($subClassMapping); - } - } - - private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass): void - { - foreach ($parentClass->embeddedClasses as $field => $embeddedClass) { - $subClassMapping = clone $embeddedClass; - $this->addMappingInheritanceInformation($subClassMapping, $parentClass); - $subClass->embeddedClasses[$field] = $subClassMapping; - } - } - - /** - * Adds nested embedded classes metadata to a parent class. - * - * @param ClassMetadata $subClass Sub embedded class metadata to add nested embedded classes metadata from. - * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to. - * @param string $prefix Embedded classes' prefix to use for nested embedded classes field names. - */ - private function addNestedEmbeddedClasses( - ClassMetadata $subClass, - ClassMetadata $parentClass, - string $prefix, - ): void { - foreach ($subClass->embeddedClasses as $property => $embeddableClass) { - if (isset($embeddableClass->inherited)) { - continue; - } - - $embeddableMetadata = $this->getMetadataFor($embeddableClass->class); - - $parentClass->mapEmbedded( - [ - 'fieldName' => $prefix . '.' . $property, - 'class' => $embeddableMetadata->name, - 'columnPrefix' => $embeddableClass->columnPrefix, - 'declaredField' => $embeddableClass->declaredField - ? $prefix . '.' . $embeddableClass->declaredField - : $prefix, - 'originalField' => $embeddableClass->originalField ?: $property, - ], - ); - } - } - - /** - * Copy the table indices from the parent class superclass to the child class - */ - private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass): void - { - if (! $parentClass->isMappedSuperclass) { - return; - } - - foreach (['uniqueConstraints', 'indexes'] as $indexType) { - if (isset($parentClass->table[$indexType])) { - foreach ($parentClass->table[$indexType] as $indexName => $index) { - if (isset($subClass->table[$indexType][$indexName])) { - continue; // Let the inheriting table override indices - } - - $subClass->table[$indexType][$indexName] = $index; - } - } - } - } - - /** - * Completes the ID generator mapping. If "auto" is specified we choose the generator - * most appropriate for the targeted database platform. - * - * @throws ORMException - */ - private function completeIdGeneratorMapping(ClassMetadata $class): void - { - $idGenType = $class->generatorType; - if ($idGenType === ClassMetadata::GENERATOR_TYPE_AUTO) { - $class->setIdGeneratorType($this->determineIdGeneratorStrategy($this->getTargetPlatform())); - } - - // Create & assign an appropriate ID generator instance - switch ($class->generatorType) { - case ClassMetadata::GENERATOR_TYPE_IDENTITY: - $sequenceName = null; - $fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null; - $platform = $this->getTargetPlatform(); - - $generator = $fieldName && $class->fieldMappings[$fieldName]->type === 'bigint' - ? new BigIntegerIdentityGenerator() - : new IdentityGenerator(); - - $class->setIdGenerator($generator); - - break; - - case ClassMetadata::GENERATOR_TYPE_SEQUENCE: - // If there is no sequence definition yet, create a default definition - $definition = $class->sequenceGeneratorDefinition; - - if (! $definition) { - $fieldName = $class->getSingleIdentifierFieldName(); - $sequenceName = $class->getSequenceName($this->getTargetPlatform()); - $quoted = isset($class->fieldMappings[$fieldName]->quoted) || isset($class->table['quoted']); - - $definition = [ - 'sequenceName' => $this->truncateSequenceName($sequenceName), - 'allocationSize' => 1, - 'initialValue' => 1, - ]; - - if ($quoted) { - $definition['quoted'] = true; - } - - $class->setSequenceGeneratorDefinition($definition); - } - - $sequenceGenerator = new SequenceGenerator( - $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()), - (int) $definition['allocationSize'], - ); - $class->setIdGenerator($sequenceGenerator); - break; - - case ClassMetadata::GENERATOR_TYPE_NONE: - $class->setIdGenerator(new AssignedGenerator()); - break; - - case ClassMetadata::GENERATOR_TYPE_CUSTOM: - $definition = $class->customGeneratorDefinition; - if ($definition === null) { - throw InvalidCustomGenerator::onClassNotConfigured(); - } - - if (! class_exists($definition['class'])) { - throw InvalidCustomGenerator::onMissingClass($definition); - } - - $class->setIdGenerator(new $definition['class']()); - break; - - default: - throw UnknownGeneratorType::create($class->generatorType); - } - } - - /** @psalm-return ClassMetadata::GENERATOR_TYPE_* */ - private function determineIdGeneratorStrategy(AbstractPlatform $platform): int - { - assert($this->em !== null); - foreach ($this->em->getConfiguration()->getIdentityGenerationPreferences() as $platformFamily => $strategy) { - if (is_a($platform, $platformFamily)) { - return $strategy; - } - } - - $nonIdentityDefaultStrategy = self::NON_IDENTITY_DEFAULT_STRATEGY; - - // DBAL 3 - if (method_exists($platform, 'getIdentitySequenceName')) { - $nonIdentityDefaultStrategy[Platforms\PostgreSQLPlatform::class] = ClassMetadata::GENERATOR_TYPE_SEQUENCE; - } - - foreach ($nonIdentityDefaultStrategy as $platformFamily => $strategy) { - if (is_a($platform, $platformFamily)) { - if ($platform instanceof Platforms\PostgreSQLPlatform) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/issues/8893', - <<<'DEPRECATION' - Relying on non-optimal defaults for ID generation is deprecated, and IDENTITY - results in SERIAL, which is not recommended. - Instead, configure identifier generation strategies explicitly through - configuration. - We currently recommend "SEQUENCE" for "%s", when using DBAL 3, - and "IDENTITY" when using DBAL 4, - so you should probably use the following configuration before upgrading to DBAL 4, - and remove it after deploying that upgrade: - - $configuration->setIdentityGenerationPreferences([ - "%s" => ClassMetadata::GENERATOR_TYPE_SEQUENCE, - ]); - - DEPRECATION, - $platformFamily, - $platformFamily, - ); - } - - return $strategy; - } - } - - return ClassMetadata::GENERATOR_TYPE_IDENTITY; - } - - private function truncateSequenceName(string $schemaElementName): string - { - $platform = $this->getTargetPlatform(); - if (! $platform instanceof Platforms\OraclePlatform) { - return $schemaElementName; - } - - $maxIdentifierLength = $platform->getMaxIdentifierLength(); - - if (strlen($schemaElementName) > $maxIdentifierLength) { - return substr($schemaElementName, 0, $maxIdentifierLength); - } - - return $schemaElementName; - } - - /** - * Inherits the ID generator mapping from a parent class. - */ - private function inheritIdGeneratorMapping(ClassMetadata $class, ClassMetadata $parent): void - { - if ($parent->isIdGeneratorSequence()) { - $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition); - } - - if ($parent->generatorType) { - $class->setIdGeneratorType($parent->generatorType); - } - - if ($parent->idGenerator ?? null) { - $class->setIdGenerator($parent->idGenerator); - } - } - - protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService): void - { - $class->wakeupReflection($reflService); - } - - protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService): void - { - $class->initializeReflection($reflService); - } - - protected function getDriver(): MappingDriver - { - assert($this->driver !== null); - - return $this->driver; - } - - protected function isEntity(ClassMetadataInterface $class): bool - { - return ! $class->isMappedSuperclass; - } - - private function getTargetPlatform(): Platforms\AbstractPlatform - { - if (! $this->targetPlatform) { - $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform(); - } - - return $this->targetPlatform; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Column.php b/vendor/doctrine/orm/src/Mapping/Column.php deleted file mode 100644 index 68121e6..0000000 --- a/vendor/doctrine/orm/src/Mapping/Column.php +++ /dev/null @@ -1,36 +0,0 @@ -|null $enumType - * @param array $options - * @psalm-param 'NEVER'|'INSERT'|'ALWAYS'|null $generated - */ - public function __construct( - public readonly string|null $name = null, - public readonly string|null $type = null, - public readonly int|null $length = null, - public readonly int|null $precision = null, - public readonly int|null $scale = null, - public readonly bool $unique = false, - public readonly bool $nullable = false, - public readonly bool $insertable = true, - public readonly bool $updatable = true, - public readonly string|null $enumType = null, - public readonly array $options = [], - public readonly string|null $columnDefinition = null, - public readonly string|null $generated = null, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/CustomIdGenerator.php b/vendor/doctrine/orm/src/Mapping/CustomIdGenerator.php deleted file mode 100644 index 7b31dc3..0000000 --- a/vendor/doctrine/orm/src/Mapping/CustomIdGenerator.php +++ /dev/null @@ -1,16 +0,0 @@ - Map to store entity listener instances. */ - private array $instances = []; - - public function clear(string|null $className = null): void - { - if ($className === null) { - $this->instances = []; - - return; - } - - $className = trim($className, '\\'); - unset($this->instances[$className]); - } - - public function register(object $object): void - { - $this->instances[$object::class] = $object; - } - - public function resolve(string $className): object - { - $className = trim($className, '\\'); - - return $this->instances[$className] ??= new $className(); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DefaultNamingStrategy.php b/vendor/doctrine/orm/src/Mapping/DefaultNamingStrategy.php deleted file mode 100644 index 15218f9..0000000 --- a/vendor/doctrine/orm/src/Mapping/DefaultNamingStrategy.php +++ /dev/null @@ -1,68 +0,0 @@ -referenceColumnName(); - } - - public function joinTableName( - string $sourceEntity, - string $targetEntity, - string $propertyName, - ): string { - return strtolower($this->classToTableName($sourceEntity) . '_' . - $this->classToTableName($targetEntity)); - } - - public function joinKeyColumnName( - string $entityName, - string|null $referencedColumnName, - ): string { - return strtolower($this->classToTableName($entityName) . '_' . - ($referencedColumnName ?: $this->referenceColumnName())); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DefaultQuoteStrategy.php b/vendor/doctrine/orm/src/Mapping/DefaultQuoteStrategy.php deleted file mode 100644 index 6260336..0000000 --- a/vendor/doctrine/orm/src/Mapping/DefaultQuoteStrategy.php +++ /dev/null @@ -1,145 +0,0 @@ -fieldMappings[$fieldName]->quoted) - ? $platform->quoteIdentifier($class->fieldMappings[$fieldName]->columnName) - : $class->fieldMappings[$fieldName]->columnName; - } - - /** - * {@inheritDoc} - * - * @todo Table names should be computed in DBAL depending on the platform - */ - public function getTableName(ClassMetadata $class, AbstractPlatform $platform): string - { - $tableName = $class->table['name']; - - if (! empty($class->table['schema'])) { - $tableName = $class->table['schema'] . '.' . $class->table['name']; - } - - return isset($class->table['quoted']) - ? $platform->quoteIdentifier($tableName) - : $tableName; - } - - /** - * {@inheritDoc} - */ - public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform): string - { - return isset($definition['quoted']) - ? $platform->quoteIdentifier($definition['sequenceName']) - : $definition['sequenceName']; - } - - public function getJoinColumnName(JoinColumnMapping $joinColumn, ClassMetadata $class, AbstractPlatform $platform): string - { - return isset($joinColumn->quoted) - ? $platform->quoteIdentifier($joinColumn->name) - : $joinColumn->name; - } - - public function getReferencedJoinColumnName( - JoinColumnMapping $joinColumn, - ClassMetadata $class, - AbstractPlatform $platform, - ): string { - return isset($joinColumn->quoted) - ? $platform->quoteIdentifier($joinColumn->referencedColumnName) - : $joinColumn->referencedColumnName; - } - - public function getJoinTableName( - ManyToManyOwningSideMapping $association, - ClassMetadata $class, - AbstractPlatform $platform, - ): string { - $schema = ''; - - if (isset($association->joinTable->schema)) { - $schema = $association->joinTable->schema . '.'; - } - - $tableName = $association->joinTable->name; - - if (isset($association->joinTable->quoted)) { - $tableName = $platform->quoteIdentifier($tableName); - } - - return $schema . $tableName; - } - - /** - * {@inheritDoc} - */ - public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform): array - { - $quotedColumnNames = []; - - foreach ($class->identifier as $fieldName) { - if (isset($class->fieldMappings[$fieldName])) { - $quotedColumnNames[] = $this->getColumnName($fieldName, $class, $platform); - - continue; - } - - // Association defined as Id field - $assoc = $class->associationMappings[$fieldName]; - assert($assoc->isToOneOwningSide()); - $joinColumns = $assoc->joinColumns; - $assocQuotedColumnNames = array_map( - static fn (JoinColumnMapping $joinColumn) => isset($joinColumn->quoted) - ? $platform->quoteIdentifier($joinColumn->name) - : $joinColumn->name, - $joinColumns, - ); - - $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames); - } - - return $quotedColumnNames; - } - - public function getColumnAlias( - string $columnName, - int $counter, - AbstractPlatform $platform, - ClassMetadata|null $class = null, - ): string { - // 1 ) Concatenate column name and counter - // 2 ) Trim the column alias to the maximum identifier length of the platform. - // If the alias is to long, characters are cut off from the beginning. - // 3 ) Strip non alphanumeric characters - // 4 ) Prefix with "_" if the result its numeric - $columnName .= '_' . $counter; - $columnName = substr($columnName, -$platform->getMaxIdentifierLength()); - $columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName); - $columnName = is_numeric($columnName) ? '_' . $columnName : $columnName; - - return $this->getSQLResultCasing($platform, $columnName); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DefaultTypedFieldMapper.php b/vendor/doctrine/orm/src/Mapping/DefaultTypedFieldMapper.php deleted file mode 100644 index 49144b8..0000000 --- a/vendor/doctrine/orm/src/Mapping/DefaultTypedFieldMapper.php +++ /dev/null @@ -1,80 +0,0 @@ -|string> $typedFieldMappings */ - private array $typedFieldMappings; - - private const DEFAULT_TYPED_FIELD_MAPPINGS = [ - DateInterval::class => Types::DATEINTERVAL, - DateTime::class => Types::DATETIME_MUTABLE, - DateTimeImmutable::class => Types::DATETIME_IMMUTABLE, - 'array' => Types::JSON, - 'bool' => Types::BOOLEAN, - 'float' => Types::FLOAT, - 'int' => Types::INTEGER, - 'string' => Types::STRING, - ]; - - /** @param array|string> $typedFieldMappings */ - public function __construct(array $typedFieldMappings = []) - { - $this->typedFieldMappings = array_merge(self::DEFAULT_TYPED_FIELD_MAPPINGS, $typedFieldMappings); - } - - /** - * {@inheritDoc} - */ - public function validateAndComplete(array $mapping, ReflectionProperty $field): array - { - $type = $field->getType(); - - if ( - ! isset($mapping['type']) - && ($type instanceof ReflectionNamedType) - ) { - if (! $type->isBuiltin() && enum_exists($type->getName())) { - $reflection = new ReflectionEnum($type->getName()); - if (! $reflection->isBacked()) { - throw MappingException::backedEnumTypeRequired( - $field->class, - $mapping['fieldName'], - $type->getName(), - ); - } - - assert(is_a($type->getName(), BackedEnum::class, true)); - $mapping['enumType'] = $type->getName(); - $type = $reflection->getBackingType(); - - assert($type instanceof ReflectionNamedType); - } - - if (isset($this->typedFieldMappings[$type->getName()])) { - $mapping['type'] = $this->typedFieldMappings[$type->getName()]; - } - } - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DiscriminatorColumn.php b/vendor/doctrine/orm/src/Mapping/DiscriminatorColumn.php deleted file mode 100644 index fb9c7d3..0000000 --- a/vendor/doctrine/orm/src/Mapping/DiscriminatorColumn.php +++ /dev/null @@ -1,24 +0,0 @@ -|null */ - public readonly string|null $enumType = null, - /** @var array */ - public readonly array $options = [], - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DiscriminatorColumnMapping.php b/vendor/doctrine/orm/src/Mapping/DiscriminatorColumnMapping.php deleted file mode 100644 index 4ccb71c..0000000 --- a/vendor/doctrine/orm/src/Mapping/DiscriminatorColumnMapping.php +++ /dev/null @@ -1,83 +0,0 @@ - */ -final class DiscriminatorColumnMapping implements ArrayAccess -{ - use ArrayAccessImplementation; - - /** The database length of the column. Optional. Default value taken from the type. */ - public int|null $length = null; - - public string|null $columnDefinition = null; - - /** @var class-string|null */ - public string|null $enumType = null; - - /** @var array */ - public array $options = []; - - public function __construct( - public string $type, - public string $fieldName, - public string $name, - ) { - } - - /** - * @psalm-param array{ - * type: string, - * fieldName: string, - * name: string, - * length?: int|null, - * columnDefinition?: string|null, - * enumType?: class-string|null, - * options?: array|null, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): self - { - $mapping = new self( - $mappingArray['type'], - $mappingArray['fieldName'], - $mappingArray['name'], - ); - foreach ($mappingArray as $key => $value) { - if (in_array($key, ['type', 'fieldName', 'name'])) { - continue; - } - - if (property_exists($mapping, $key)) { - $mapping->$key = $value ?? $mapping->$key; - } else { - throw new Exception('Unknown property ' . $key . ' on class ' . static::class); - } - } - - return $mapping; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = ['type', 'fieldName', 'name']; - - foreach (['length', 'columnDefinition', 'enumType', 'options'] as $stringOrArrayKey) { - if ($this->$stringOrArrayKey !== null) { - $serialized[] = $stringOrArrayKey; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/DiscriminatorMap.php b/vendor/doctrine/orm/src/Mapping/DiscriminatorMap.php deleted file mode 100644 index 2b204a9..0000000 --- a/vendor/doctrine/orm/src/Mapping/DiscriminatorMap.php +++ /dev/null @@ -1,17 +0,0 @@ - $value */ - public function __construct( - public readonly array $value, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/AttributeDriver.php b/vendor/doctrine/orm/src/Mapping/Driver/AttributeDriver.php deleted file mode 100644 index 6fed1a2..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/AttributeDriver.php +++ /dev/null @@ -1,768 +0,0 @@ - 1, - Mapping\MappedSuperclass::class => 2, - ]; - - private readonly AttributeReader $reader; - - /** - * @param array $paths - * @param true $reportFieldsWhereDeclared no-op, to be removed in 4.0 - */ - public function __construct(array $paths, bool $reportFieldsWhereDeclared = true) - { - if (! $reportFieldsWhereDeclared) { - throw new InvalidArgumentException(sprintf( - 'The $reportFieldsWhereDeclared argument is no longer supported, make sure to omit it when calling %s.', - __METHOD__, - )); - } - - $this->reader = new AttributeReader(); - $this->addPaths($paths); - } - - public function isTransient(string $className): bool - { - $classAttributes = $this->reader->getClassAttributes(new ReflectionClass($className)); - - foreach ($classAttributes as $a) { - $attr = $a instanceof RepeatableAttributeCollection ? $a[0] : $a; - if (isset(self::ENTITY_ATTRIBUTE_CLASSES[$attr::class])) { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - * - * @psalm-param class-string $className - * @psalm-param ClassMetadata $metadata - * - * @template T of object - */ - public function loadMetadataForClass(string $className, PersistenceClassMetadata $metadata): void - { - $reflectionClass = $metadata->getReflectionClass() - // this happens when running attribute driver in combination with - // static reflection services. This is not the nicest fix - ?? new ReflectionClass($metadata->name); - - $classAttributes = $this->reader->getClassAttributes($reflectionClass); - - // Evaluate Entity attribute - if (isset($classAttributes[Mapping\Entity::class])) { - $entityAttribute = $classAttributes[Mapping\Entity::class]; - if ($entityAttribute->repositoryClass !== null) { - $metadata->setCustomRepositoryClass($entityAttribute->repositoryClass); - } - - if ($entityAttribute->readOnly) { - $metadata->markReadOnly(); - } - } elseif (isset($classAttributes[Mapping\MappedSuperclass::class])) { - $mappedSuperclassAttribute = $classAttributes[Mapping\MappedSuperclass::class]; - - $metadata->setCustomRepositoryClass($mappedSuperclassAttribute->repositoryClass); - $metadata->isMappedSuperclass = true; - } elseif (isset($classAttributes[Mapping\Embeddable::class])) { - $metadata->isEmbeddedClass = true; - } else { - throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); - } - - $primaryTable = []; - - if (isset($classAttributes[Mapping\Table::class])) { - $tableAnnot = $classAttributes[Mapping\Table::class]; - $primaryTable['name'] = $tableAnnot->name; - $primaryTable['schema'] = $tableAnnot->schema; - - if ($tableAnnot->options) { - $primaryTable['options'] = $tableAnnot->options; - } - } - - if (isset($classAttributes[Mapping\Index::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\Index::class); - } - - foreach ($classAttributes[Mapping\Index::class] as $idx => $indexAnnot) { - $index = []; - - if (! empty($indexAnnot->columns)) { - $index['columns'] = $indexAnnot->columns; - } - - if (! empty($indexAnnot->fields)) { - $index['fields'] = $indexAnnot->fields; - } - - if ( - isset($index['columns'], $index['fields']) - || ( - ! isset($index['columns']) - && ! isset($index['fields']) - ) - ) { - throw MappingException::invalidIndexConfiguration( - $className, - (string) ($indexAnnot->name ?? $idx), - ); - } - - if (! empty($indexAnnot->flags)) { - $index['flags'] = $indexAnnot->flags; - } - - if (! empty($indexAnnot->options)) { - $index['options'] = $indexAnnot->options; - } - - if (! empty($indexAnnot->name)) { - $primaryTable['indexes'][$indexAnnot->name] = $index; - } else { - $primaryTable['indexes'][] = $index; - } - } - } - - if (isset($classAttributes[Mapping\UniqueConstraint::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\UniqueConstraint::class); - } - - foreach ($classAttributes[Mapping\UniqueConstraint::class] as $idx => $uniqueConstraintAnnot) { - $uniqueConstraint = []; - - if (! empty($uniqueConstraintAnnot->columns)) { - $uniqueConstraint['columns'] = $uniqueConstraintAnnot->columns; - } - - if (! empty($uniqueConstraintAnnot->fields)) { - $uniqueConstraint['fields'] = $uniqueConstraintAnnot->fields; - } - - if ( - isset($uniqueConstraint['columns'], $uniqueConstraint['fields']) - || ( - ! isset($uniqueConstraint['columns']) - && ! isset($uniqueConstraint['fields']) - ) - ) { - throw MappingException::invalidUniqueConstraintConfiguration( - $className, - (string) ($uniqueConstraintAnnot->name ?? $idx), - ); - } - - if (! empty($uniqueConstraintAnnot->options)) { - $uniqueConstraint['options'] = $uniqueConstraintAnnot->options; - } - - if (! empty($uniqueConstraintAnnot->name)) { - $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; - } else { - $primaryTable['uniqueConstraints'][] = $uniqueConstraint; - } - } - } - - $metadata->setPrimaryTable($primaryTable); - - // Evaluate #[Cache] attribute - if (isset($classAttributes[Mapping\Cache::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\Cache::class); - } - - $cacheAttribute = $classAttributes[Mapping\Cache::class]; - $cacheMap = [ - 'region' => $cacheAttribute->region, - 'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), - ]; - - $metadata->enableCache($cacheMap); - } - - // Evaluate InheritanceType attribute - if (isset($classAttributes[Mapping\InheritanceType::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\InheritanceType::class); - } - - $inheritanceTypeAttribute = $classAttributes[Mapping\InheritanceType::class]; - - $metadata->setInheritanceType( - constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value), - ); - - if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { - // Evaluate DiscriminatorColumn attribute - if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) { - $discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class]; - assert($discrColumnAttribute instanceof Mapping\DiscriminatorColumn); - - $columnDef = [ - 'name' => $discrColumnAttribute->name, - 'type' => $discrColumnAttribute->type ?? 'string', - 'length' => $discrColumnAttribute->length ?? 255, - 'columnDefinition' => $discrColumnAttribute->columnDefinition, - 'enumType' => $discrColumnAttribute->enumType, - ]; - - if ($discrColumnAttribute->options) { - $columnDef['options'] = $discrColumnAttribute->options; - } - - $metadata->setDiscriminatorColumn($columnDef); - } else { - $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]); - } - - // Evaluate DiscriminatorMap attribute - if (isset($classAttributes[Mapping\DiscriminatorMap::class])) { - $discrMapAttribute = $classAttributes[Mapping\DiscriminatorMap::class]; - $metadata->setDiscriminatorMap($discrMapAttribute->value); - } - } - } - - // Evaluate DoctrineChangeTrackingPolicy attribute - if (isset($classAttributes[Mapping\ChangeTrackingPolicy::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\ChangeTrackingPolicy::class); - } - - $changeTrackingAttribute = $classAttributes[Mapping\ChangeTrackingPolicy::class]; - $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAttribute->value)); - } - - foreach ($reflectionClass->getProperties() as $property) { - assert($property instanceof ReflectionProperty); - - if ($this->isRepeatedPropertyDeclaration($property, $metadata)) { - continue; - } - - $mapping = []; - $mapping['fieldName'] = $property->name; - - // Evaluate #[Cache] attribute - $cacheAttribute = $this->reader->getPropertyAttribute($property, Mapping\Cache::class); - if ($cacheAttribute !== null) { - assert($cacheAttribute instanceof Mapping\Cache); - - $mapping['cache'] = $metadata->getAssociationCacheDefaults( - $mapping['fieldName'], - [ - 'usage' => (int) constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), - 'region' => $cacheAttribute->region, - ], - ); - } - - // Check for JoinColumn/JoinColumns attributes - $joinColumns = []; - - $joinColumnAttributes = $this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class); - - foreach ($joinColumnAttributes as $joinColumnAttribute) { - $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); - } - - // Field can only be attributed with one of: - // Column, OneToOne, OneToMany, ManyToOne, ManyToMany, Embedded - $columnAttribute = $this->reader->getPropertyAttribute($property, Mapping\Column::class); - $oneToOneAttribute = $this->reader->getPropertyAttribute($property, Mapping\OneToOne::class); - $oneToManyAttribute = $this->reader->getPropertyAttribute($property, Mapping\OneToMany::class); - $manyToOneAttribute = $this->reader->getPropertyAttribute($property, Mapping\ManyToOne::class); - $manyToManyAttribute = $this->reader->getPropertyAttribute($property, Mapping\ManyToMany::class); - $embeddedAttribute = $this->reader->getPropertyAttribute($property, Mapping\Embedded::class); - - if ($columnAttribute !== null) { - $mapping = $this->columnToArray($property->name, $columnAttribute); - - if ($this->reader->getPropertyAttribute($property, Mapping\Id::class)) { - $mapping['id'] = true; - } - - $generatedValueAttribute = $this->reader->getPropertyAttribute($property, Mapping\GeneratedValue::class); - - if ($generatedValueAttribute !== null) { - $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAttribute->strategy)); - } - - if ($this->reader->getPropertyAttribute($property, Mapping\Version::class)) { - $metadata->setVersionMapping($mapping); - } - - $metadata->mapField($mapping); - - // Check for SequenceGenerator/TableGenerator definition - $seqGeneratorAttribute = $this->reader->getPropertyAttribute($property, Mapping\SequenceGenerator::class); - $customGeneratorAttribute = $this->reader->getPropertyAttribute($property, Mapping\CustomIdGenerator::class); - - if ($seqGeneratorAttribute !== null) { - $metadata->setSequenceGeneratorDefinition( - [ - 'sequenceName' => $seqGeneratorAttribute->sequenceName, - 'allocationSize' => $seqGeneratorAttribute->allocationSize, - 'initialValue' => $seqGeneratorAttribute->initialValue, - ], - ); - } elseif ($customGeneratorAttribute !== null) { - $metadata->setCustomGeneratorDefinition( - [ - 'class' => $customGeneratorAttribute->class, - ], - ); - } - } elseif ($oneToOneAttribute !== null) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\OneToOne::class); - } - - if ($this->reader->getPropertyAttribute($property, Mapping\Id::class)) { - $mapping['id'] = true; - } - - $mapping['targetEntity'] = $oneToOneAttribute->targetEntity; - $mapping['joinColumns'] = $joinColumns; - $mapping['mappedBy'] = $oneToOneAttribute->mappedBy; - $mapping['inversedBy'] = $oneToOneAttribute->inversedBy; - $mapping['cascade'] = $oneToOneAttribute->cascade; - $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); - $metadata->mapOneToOne($mapping); - } elseif ($oneToManyAttribute !== null) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\OneToMany::class); - } - - $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; - $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; - $mapping['cascade'] = $oneToManyAttribute->cascade; - $mapping['indexBy'] = $oneToManyAttribute->indexBy; - $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); - - $orderByAttribute = $this->reader->getPropertyAttribute($property, Mapping\OrderBy::class); - - if ($orderByAttribute !== null) { - $mapping['orderBy'] = $orderByAttribute->value; - } - - $metadata->mapOneToMany($mapping); - } elseif ($manyToOneAttribute !== null) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\OneToMany::class); - } - - $idAttribute = $this->reader->getPropertyAttribute($property, Mapping\Id::class); - - if ($idAttribute !== null) { - $mapping['id'] = true; - } - - $mapping['joinColumns'] = $joinColumns; - $mapping['cascade'] = $manyToOneAttribute->cascade; - $mapping['inversedBy'] = $manyToOneAttribute->inversedBy; - $mapping['targetEntity'] = $manyToOneAttribute->targetEntity; - $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); - $metadata->mapManyToOne($mapping); - } elseif ($manyToManyAttribute !== null) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\ManyToMany::class); - } - - $joinTable = []; - $joinTableAttribute = $this->reader->getPropertyAttribute($property, Mapping\JoinTable::class); - - if ($joinTableAttribute !== null) { - $joinTable = [ - 'name' => $joinTableAttribute->name, - 'schema' => $joinTableAttribute->schema, - ]; - - if ($joinTableAttribute->options) { - $joinTable['options'] = $joinTableAttribute->options; - } - - foreach ($joinTableAttribute->joinColumns as $joinColumn) { - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); - } - - foreach ($joinTableAttribute->inverseJoinColumns as $joinColumn) { - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); - } - } - - foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class) as $joinColumn) { - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); - } - - foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\InverseJoinColumn::class) as $joinColumn) { - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); - } - - $mapping['joinTable'] = $joinTable; - $mapping['targetEntity'] = $manyToManyAttribute->targetEntity; - $mapping['mappedBy'] = $manyToManyAttribute->mappedBy; - $mapping['inversedBy'] = $manyToManyAttribute->inversedBy; - $mapping['cascade'] = $manyToManyAttribute->cascade; - $mapping['indexBy'] = $manyToManyAttribute->indexBy; - $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); - - $orderByAttribute = $this->reader->getPropertyAttribute($property, Mapping\OrderBy::class); - - if ($orderByAttribute !== null) { - $mapping['orderBy'] = $orderByAttribute->value; - } - - $metadata->mapManyToMany($mapping); - } elseif ($embeddedAttribute !== null) { - $mapping['class'] = $embeddedAttribute->class; - $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix; - - $metadata->mapEmbedded($mapping); - } - } - - // Evaluate AssociationOverrides attribute - if (isset($classAttributes[Mapping\AssociationOverrides::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\AssociationOverride::class); - } - - $associationOverride = $classAttributes[Mapping\AssociationOverrides::class]; - - foreach ($associationOverride->overrides as $associationOverride) { - $override = []; - $fieldName = $associationOverride->name; - - // Check for JoinColumn/JoinColumns attributes - if ($associationOverride->joinColumns) { - $joinColumns = []; - - foreach ($associationOverride->joinColumns as $joinColumn) { - $joinColumns[] = $this->joinColumnToArray($joinColumn); - } - - $override['joinColumns'] = $joinColumns; - } - - if ($associationOverride->inverseJoinColumns) { - $joinColumns = []; - - foreach ($associationOverride->inverseJoinColumns as $joinColumn) { - $joinColumns[] = $this->joinColumnToArray($joinColumn); - } - - $override['inverseJoinColumns'] = $joinColumns; - } - - // Check for JoinTable attributes - if ($associationOverride->joinTable) { - $joinTableAnnot = $associationOverride->joinTable; - $joinTable = [ - 'name' => $joinTableAnnot->name, - 'schema' => $joinTableAnnot->schema, - 'joinColumns' => $override['joinColumns'] ?? [], - 'inverseJoinColumns' => $override['inverseJoinColumns'] ?? [], - ]; - - unset($override['joinColumns'], $override['inverseJoinColumns']); - - $override['joinTable'] = $joinTable; - } - - // Check for inversedBy - if ($associationOverride->inversedBy) { - $override['inversedBy'] = $associationOverride->inversedBy; - } - - // Check for `fetch` - if ($associationOverride->fetch) { - $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverride->fetch); - } - - $metadata->setAssociationOverride($fieldName, $override); - } - } - - // Evaluate AttributeOverrides attribute - if (isset($classAttributes[Mapping\AttributeOverrides::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\AttributeOverrides::class); - } - - $attributeOverridesAnnot = $classAttributes[Mapping\AttributeOverrides::class]; - - foreach ($attributeOverridesAnnot->overrides as $attributeOverride) { - $mapping = $this->columnToArray($attributeOverride->name, $attributeOverride->column); - - $metadata->setAttributeOverride($attributeOverride->name, $mapping); - } - } - - // Evaluate EntityListeners attribute - if (isset($classAttributes[Mapping\EntityListeners::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\EntityListeners::class); - } - - $entityListenersAttribute = $classAttributes[Mapping\EntityListeners::class]; - - foreach ($entityListenersAttribute->value as $item) { - $listenerClassName = $metadata->fullyQualifiedClassName($item); - - if (! class_exists($listenerClassName)) { - throw MappingException::entityListenerClassNotFound($listenerClassName, $className); - } - - $hasMapping = false; - $listenerClass = new ReflectionClass($listenerClassName); - - foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - assert($method instanceof ReflectionMethod); - // find method callbacks. - $callbacks = $this->getMethodCallbacks($method); - $hasMapping = $hasMapping ?: ! empty($callbacks); - - foreach ($callbacks as $value) { - $metadata->addEntityListener($value[1], $listenerClassName, $value[0]); - } - } - - // Evaluate the listener using naming convention. - if (! $hasMapping) { - EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName); - } - } - } - - // Evaluate #[HasLifecycleCallbacks] attribute - if (isset($classAttributes[Mapping\HasLifecycleCallbacks::class])) { - if ($metadata->isEmbeddedClass) { - throw MappingException::invalidAttributeOnEmbeddable($metadata->name, Mapping\HasLifecycleCallbacks::class); - } - - foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - assert($method instanceof ReflectionMethod); - foreach ($this->getMethodCallbacks($method) as $value) { - $metadata->addLifecycleCallback($value[0], $value[1]); - } - } - } - } - - /** - * Attempts to resolve the fetch mode. - * - * @param class-string $className The class name. - * @param string $fetchMode The fetch mode. - * - * @return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata. - * - * @throws MappingException If the fetch mode is not valid. - */ - private function getFetchMode(string $className, string $fetchMode): int - { - if (! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) { - throw MappingException::invalidFetchMode($className, $fetchMode); - } - - return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode); - } - - /** - * Attempts to resolve the generated mode. - * - * @throws MappingException If the fetch mode is not valid. - */ - private function getGeneratedMode(string $generatedMode): int - { - if (! defined('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode)) { - throw MappingException::invalidGeneratedMode($generatedMode); - } - - return constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode); - } - - /** - * Parses the given method. - * - * @return list - * @psalm-return list - */ - private function getMethodCallbacks(ReflectionMethod $method): array - { - $callbacks = []; - $attributes = $this->reader->getMethodAttributes($method); - - foreach ($attributes as $attribute) { - if ($attribute instanceof Mapping\PrePersist) { - $callbacks[] = [$method->name, Events::prePersist]; - } - - if ($attribute instanceof Mapping\PostPersist) { - $callbacks[] = [$method->name, Events::postPersist]; - } - - if ($attribute instanceof Mapping\PreUpdate) { - $callbacks[] = [$method->name, Events::preUpdate]; - } - - if ($attribute instanceof Mapping\PostUpdate) { - $callbacks[] = [$method->name, Events::postUpdate]; - } - - if ($attribute instanceof Mapping\PreRemove) { - $callbacks[] = [$method->name, Events::preRemove]; - } - - if ($attribute instanceof Mapping\PostRemove) { - $callbacks[] = [$method->name, Events::postRemove]; - } - - if ($attribute instanceof Mapping\PostLoad) { - $callbacks[] = [$method->name, Events::postLoad]; - } - - if ($attribute instanceof Mapping\PreFlush) { - $callbacks[] = [$method->name, Events::preFlush]; - } - } - - return $callbacks; - } - - /** - * Parse the given JoinColumn as array - * - * @return mixed[] - * @psalm-return array{ - * name: string|null, - * unique: bool, - * nullable: bool, - * onDelete: mixed, - * columnDefinition: string|null, - * referencedColumnName: string, - * options?: array - * } - */ - private function joinColumnToArray(Mapping\JoinColumn|Mapping\InverseJoinColumn $joinColumn): array - { - $mapping = [ - 'name' => $joinColumn->name, - 'unique' => $joinColumn->unique, - 'nullable' => $joinColumn->nullable, - 'onDelete' => $joinColumn->onDelete, - 'columnDefinition' => $joinColumn->columnDefinition, - 'referencedColumnName' => $joinColumn->referencedColumnName, - ]; - - if ($joinColumn->options) { - $mapping['options'] = $joinColumn->options; - } - - return $mapping; - } - - /** - * Parse the given Column as array - * - * @return mixed[] - * @psalm-return array{ - * fieldName: string, - * type: mixed, - * scale: int, - * length: int, - * unique: bool, - * nullable: bool, - * precision: int, - * enumType?: class-string, - * options?: mixed[], - * columnName?: string, - * columnDefinition?: string - * } - */ - private function columnToArray(string $fieldName, Mapping\Column $column): array - { - $mapping = [ - 'fieldName' => $fieldName, - 'type' => $column->type, - 'scale' => $column->scale, - 'length' => $column->length, - 'unique' => $column->unique, - 'nullable' => $column->nullable, - 'precision' => $column->precision, - ]; - - if ($column->options) { - $mapping['options'] = $column->options; - } - - if (isset($column->name)) { - $mapping['columnName'] = $column->name; - } - - if (isset($column->columnDefinition)) { - $mapping['columnDefinition'] = $column->columnDefinition; - } - - if ($column->updatable === false) { - $mapping['notUpdatable'] = true; - } - - if ($column->insertable === false) { - $mapping['notInsertable'] = true; - } - - if ($column->generated !== null) { - $mapping['generated'] = $this->getGeneratedMode($column->generated); - } - - if ($column->enumType) { - $mapping['enumType'] = $column->enumType; - } - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php b/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php deleted file mode 100644 index 2de622a..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php +++ /dev/null @@ -1,146 +0,0 @@ -, bool> */ - private array $isRepeatableAttribute = []; - - /** - * @psalm-return class-string-map> - * - * @template T of MappingAttribute - */ - public function getClassAttributes(ReflectionClass $class): array - { - return $this->convertToAttributeInstances($class->getAttributes()); - } - - /** - * @return class-string-map> - * - * @template T of MappingAttribute - */ - public function getMethodAttributes(ReflectionMethod $method): array - { - return $this->convertToAttributeInstances($method->getAttributes()); - } - - /** - * @return class-string-map> - * - * @template T of MappingAttribute - */ - public function getPropertyAttributes(ReflectionProperty $property): array - { - return $this->convertToAttributeInstances($property->getAttributes()); - } - - /** - * @param class-string $attributeName The name of the annotation. - * - * @return T|null - * - * @template T of MappingAttribute - */ - public function getPropertyAttribute(ReflectionProperty $property, string $attributeName) - { - if ($this->isRepeatable($attributeName)) { - throw new LogicException(sprintf( - 'The attribute "%s" is repeatable. Call getPropertyAttributeCollection() instead.', - $attributeName, - )); - } - - return $this->getPropertyAttributes($property)[$attributeName] ?? null; - } - - /** - * @param class-string $attributeName The name of the annotation. - * - * @return RepeatableAttributeCollection - * - * @template T of MappingAttribute - */ - public function getPropertyAttributeCollection( - ReflectionProperty $property, - string $attributeName, - ): RepeatableAttributeCollection { - if (! $this->isRepeatable($attributeName)) { - throw new LogicException(sprintf( - 'The attribute "%s" is not repeatable. Call getPropertyAttribute() instead.', - $attributeName, - )); - } - - return $this->getPropertyAttributes($property)[$attributeName] ?? new RepeatableAttributeCollection(); - } - - /** - * @param array $attributes - * - * @return class-string-map> - * - * @template T of MappingAttribute - */ - private function convertToAttributeInstances(array $attributes): array - { - $instances = []; - - foreach ($attributes as $attribute) { - $attributeName = $attribute->getName(); - assert(is_string($attributeName)); - // Make sure we only get Doctrine Attributes - if (! is_subclass_of($attributeName, MappingAttribute::class)) { - continue; - } - - $instance = $attribute->newInstance(); - assert($instance instanceof MappingAttribute); - - if ($this->isRepeatable($attributeName)) { - if (! isset($instances[$attributeName])) { - $instances[$attributeName] = new RepeatableAttributeCollection(); - } - - $collection = $instances[$attributeName]; - assert($collection instanceof RepeatableAttributeCollection); - $collection[] = $instance; - } else { - $instances[$attributeName] = $instance; - } - } - - return $instances; - } - - /** @param class-string $attributeClassName */ - private function isRepeatable(string $attributeClassName): bool - { - if (isset($this->isRepeatableAttribute[$attributeClassName])) { - return $this->isRepeatableAttribute[$attributeClassName]; - } - - $reflectionClass = new ReflectionClass($attributeClassName); - $attribute = $reflectionClass->getAttributes()[0]->newInstance(); - - return $this->isRepeatableAttribute[$attributeClassName] = ($attribute->flags & Attribute::IS_REPEATABLE) > 0; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/DatabaseDriver.php b/vendor/doctrine/orm/src/Mapping/Driver/DatabaseDriver.php deleted file mode 100644 index 49e2e93..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/DatabaseDriver.php +++ /dev/null @@ -1,528 +0,0 @@ -|null */ - private array|null $tables = null; - - /** @var array */ - private array $classToTableNames = []; - - /** @psalm-var array */ - private array $manyToManyTables = []; - - /** @var mixed[] */ - private array $classNamesForTables = []; - - /** @var mixed[] */ - private array $fieldNamesForColumns = []; - - /** - * The namespace for the generated entities. - */ - private string|null $namespace = null; - - private Inflector $inflector; - - public function __construct(private readonly AbstractSchemaManager $sm) - { - $this->inflector = InflectorFactory::create()->build(); - } - - /** - * Set the namespace for the generated entities. - */ - public function setNamespace(string $namespace): void - { - $this->namespace = $namespace; - } - - public function isTransient(string $className): bool - { - return true; - } - - /** - * {@inheritDoc} - */ - public function getAllClassNames(): array - { - $this->reverseEngineerMappingFromDatabase(); - - return array_keys($this->classToTableNames); - } - - /** - * Sets class name for a table. - */ - public function setClassNameForTable(string $tableName, string $className): void - { - $this->classNamesForTables[$tableName] = $className; - } - - /** - * Sets field name for a column on a specific table. - */ - public function setFieldNameForColumn(string $tableName, string $columnName, string $fieldName): void - { - $this->fieldNamesForColumns[$tableName][$columnName] = $fieldName; - } - - /** - * Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager. - * - * @param Table[] $entityTables - * @param Table[] $manyToManyTables - * @psalm-param list $entityTables - * @psalm-param list
$manyToManyTables - */ - public function setTables(array $entityTables, array $manyToManyTables): void - { - $this->tables = $this->manyToManyTables = $this->classToTableNames = []; - - foreach ($entityTables as $table) { - $className = $this->getClassNameForTable($table->getName()); - - $this->classToTableNames[$className] = $table->getName(); - $this->tables[$table->getName()] = $table; - } - - foreach ($manyToManyTables as $table) { - $this->manyToManyTables[$table->getName()] = $table; - } - } - - public function setInflector(Inflector $inflector): void - { - $this->inflector = $inflector; - } - - /** - * {@inheritDoc} - * - * @psalm-param class-string $className - * @psalm-param ClassMetadata $metadata - * - * @template T of object - */ - public function loadMetadataForClass(string $className, PersistenceClassMetadata $metadata): void - { - if (! $metadata instanceof ClassMetadata) { - throw new TypeError(sprintf( - 'Argument #2 passed to %s() must be an instance of %s, %s given.', - __METHOD__, - ClassMetadata::class, - get_debug_type($metadata), - )); - } - - $this->reverseEngineerMappingFromDatabase(); - - if (! isset($this->classToTableNames[$className])) { - throw new InvalidArgumentException('Unknown class ' . $className); - } - - $tableName = $this->classToTableNames[$className]; - - $metadata->name = $className; - $metadata->table['name'] = $tableName; - - $this->buildIndexes($metadata); - $this->buildFieldMappings($metadata); - $this->buildToOneAssociationMappings($metadata); - - foreach ($this->manyToManyTables as $manyTable) { - foreach ($manyTable->getForeignKeys() as $foreignKey) { - // foreign key maps to the table of the current entity, many to many association probably exists - if (! (strtolower($tableName) === strtolower($foreignKey->getForeignTableName()))) { - continue; - } - - $myFk = $foreignKey; - $otherFk = null; - - foreach ($manyTable->getForeignKeys() as $foreignKey) { - if ($foreignKey !== $myFk) { - $otherFk = $foreignKey; - break; - } - } - - if (! $otherFk) { - // the definition of this many to many table does not contain - // enough foreign key information to continue reverse engineering. - continue; - } - - $localColumn = current($myFk->getLocalColumns()); - - $associationMapping = []; - $associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getLocalColumns()), true); - $associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName()); - - if (current($manyTable->getColumns())->getName() === $localColumn) { - $associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getLocalColumns()), true); - $associationMapping['joinTable'] = [ - 'name' => strtolower($manyTable->getName()), - 'joinColumns' => [], - 'inverseJoinColumns' => [], - ]; - - $fkCols = $myFk->getForeignColumns(); - $cols = $myFk->getLocalColumns(); - - for ($i = 0, $colsCount = count($cols); $i < $colsCount; $i++) { - $associationMapping['joinTable']['joinColumns'][] = [ - 'name' => $cols[$i], - 'referencedColumnName' => $fkCols[$i], - ]; - } - - $fkCols = $otherFk->getForeignColumns(); - $cols = $otherFk->getLocalColumns(); - - for ($i = 0, $colsCount = count($cols); $i < $colsCount; $i++) { - $associationMapping['joinTable']['inverseJoinColumns'][] = [ - 'name' => $cols[$i], - 'referencedColumnName' => $fkCols[$i], - ]; - } - } else { - $associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getLocalColumns()), true); - } - - $metadata->mapManyToMany($associationMapping); - - break; - } - } - } - - /** @throws MappingException */ - private function reverseEngineerMappingFromDatabase(): void - { - if ($this->tables !== null) { - return; - } - - $this->tables = $this->manyToManyTables = $this->classToTableNames = []; - - foreach ($this->sm->listTables() as $table) { - $tableName = $table->getName(); - $foreignKeys = $table->getForeignKeys(); - - $allForeignKeyColumns = []; - - foreach ($foreignKeys as $foreignKey) { - $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns()); - } - - $primaryKey = $table->getPrimaryKey(); - if ($primaryKey === null) { - throw new MappingException( - 'Table ' . $tableName . ' has no primary key. Doctrine does not ' . - "support reverse engineering from tables that don't have a primary key.", - ); - } - - $pkColumns = $primaryKey->getColumns(); - - sort($pkColumns); - sort($allForeignKeyColumns); - - if ($pkColumns === $allForeignKeyColumns && count($foreignKeys) === 2) { - $this->manyToManyTables[$tableName] = $table; - } else { - // lower-casing is necessary because of Oracle Uppercase Tablenames, - // assumption is lower-case + underscore separated. - $className = $this->getClassNameForTable($tableName); - - $this->tables[$tableName] = $table; - $this->classToTableNames[$className] = $tableName; - } - } - } - - /** - * Build indexes from a class metadata. - */ - private function buildIndexes(ClassMetadata $metadata): void - { - $tableName = $metadata->table['name']; - $indexes = $this->tables[$tableName]->getIndexes(); - - foreach ($indexes as $index) { - if ($index->isPrimary()) { - continue; - } - - $indexName = $index->getName(); - $indexColumns = $index->getColumns(); - $constraintType = $index->isUnique() - ? 'uniqueConstraints' - : 'indexes'; - - $metadata->table[$constraintType][$indexName]['columns'] = $indexColumns; - } - } - - /** - * Build field mapping from class metadata. - */ - private function buildFieldMappings(ClassMetadata $metadata): void - { - $tableName = $metadata->table['name']; - $columns = $this->tables[$tableName]->getColumns(); - $primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]); - $foreignKeys = $this->tables[$tableName]->getForeignKeys(); - $allForeignKeys = []; - - foreach ($foreignKeys as $foreignKey) { - $allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns()); - } - - $ids = []; - $fieldMappings = []; - - foreach ($columns as $column) { - if (in_array($column->getName(), $allForeignKeys, true)) { - continue; - } - - $fieldMapping = $this->buildFieldMapping($tableName, $column); - - if ($primaryKeys && in_array($column->getName(), $primaryKeys, true)) { - $fieldMapping['id'] = true; - $ids[] = $fieldMapping; - } - - $fieldMappings[] = $fieldMapping; - } - - // We need to check for the columns here, because we might have associations as id as well. - if ($ids && count($primaryKeys) === 1) { - $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); - } - - foreach ($fieldMappings as $fieldMapping) { - $metadata->mapField($fieldMapping); - } - } - - /** - * Build field mapping from a schema column definition - * - * @return mixed[] - * @psalm-return array{ - * fieldName: string, - * columnName: string, - * type: string, - * nullable: bool, - * options: array{ - * unsigned?: bool, - * fixed?: bool, - * comment: string|null, - * default?: mixed - * }, - * precision?: int, - * scale?: int, - * length?: int|null - * } - */ - private function buildFieldMapping(string $tableName, Column $column): array - { - $fieldMapping = [ - 'fieldName' => $this->getFieldNameForColumn($tableName, $column->getName(), false), - 'columnName' => $column->getName(), - 'type' => Type::getTypeRegistry()->lookupName($column->getType()), - 'nullable' => ! $column->getNotnull(), - 'options' => [ - 'comment' => $column->getComment(), - ], - ]; - - // Type specific elements - switch ($fieldMapping['type']) { - case self::ARRAY: - case Types::BLOB: - case Types::GUID: - case self::OBJECT: - case Types::SIMPLE_ARRAY: - case Types::STRING: - case Types::TEXT: - $fieldMapping['length'] = $column->getLength(); - $fieldMapping['options']['fixed'] = $column->getFixed(); - break; - - case Types::DECIMAL: - case Types::FLOAT: - $fieldMapping['precision'] = $column->getPrecision(); - $fieldMapping['scale'] = $column->getScale(); - break; - - case Types::INTEGER: - case Types::BIGINT: - case Types::SMALLINT: - $fieldMapping['options']['unsigned'] = $column->getUnsigned(); - break; - } - - // Default - $default = $column->getDefault(); - if ($default !== null) { - $fieldMapping['options']['default'] = $default; - } - - return $fieldMapping; - } - - /** - * Build to one (one to one, many to one) association mapping from class metadata. - */ - private function buildToOneAssociationMappings(ClassMetadata $metadata): void - { - assert($this->tables !== null); - - $tableName = $metadata->table['name']; - $primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]); - $foreignKeys = $this->tables[$tableName]->getForeignKeys(); - - foreach ($foreignKeys as $foreignKey) { - $foreignTableName = $foreignKey->getForeignTableName(); - $fkColumns = $foreignKey->getLocalColumns(); - $fkForeignColumns = $foreignKey->getForeignColumns(); - $localColumn = current($fkColumns); - $associationMapping = [ - 'fieldName' => $this->getFieldNameForColumn($tableName, $localColumn, true), - 'targetEntity' => $this->getClassNameForTable($foreignTableName), - ]; - - if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) { - $associationMapping['fieldName'] .= '2'; // "foo" => "foo2" - } - - if ($primaryKeys && in_array($localColumn, $primaryKeys, true)) { - $associationMapping['id'] = true; - } - - for ($i = 0, $fkColumnsCount = count($fkColumns); $i < $fkColumnsCount; $i++) { - $associationMapping['joinColumns'][] = [ - 'name' => $fkColumns[$i], - 'referencedColumnName' => $fkForeignColumns[$i], - ]; - } - - // Here we need to check if $fkColumns are the same as $primaryKeys - if (! array_diff($fkColumns, $primaryKeys)) { - $metadata->mapOneToOne($associationMapping); - } else { - $metadata->mapManyToOne($associationMapping); - } - } - } - - /** - * Retrieve schema table definition primary keys. - * - * @return string[] - */ - private function getTablePrimaryKeys(Table $table): array - { - try { - return $table->getPrimaryKey()->getColumns(); - } catch (SchemaException) { - // Do nothing - } - - return []; - } - - /** - * Returns the mapped class name for a table if it exists. Otherwise return "classified" version. - * - * @psalm-return class-string - */ - private function getClassNameForTable(string $tableName): string - { - if (isset($this->classNamesForTables[$tableName])) { - return $this->namespace . $this->classNamesForTables[$tableName]; - } - - return $this->namespace . $this->inflector->classify(strtolower($tableName)); - } - - /** - * Return the mapped field name for a column, if it exists. Otherwise return camelized version. - * - * @param bool $fk Whether the column is a foreignkey or not. - */ - private function getFieldNameForColumn( - string $tableName, - string $columnName, - bool $fk = false, - ): string { - if (isset($this->fieldNamesForColumns[$tableName], $this->fieldNamesForColumns[$tableName][$columnName])) { - return $this->fieldNamesForColumns[$tableName][$columnName]; - } - - $columnName = strtolower($columnName); - - // Replace _id if it is a foreignkey column - if ($fk) { - $columnName = preg_replace('/_id$/', '', $columnName); - } - - return $this->inflector->camelize($columnName); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/ReflectionBasedDriver.php b/vendor/doctrine/orm/src/Mapping/Driver/ReflectionBasedDriver.php deleted file mode 100644 index 7d85471..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/ReflectionBasedDriver.php +++ /dev/null @@ -1,44 +0,0 @@ -class; - - if ( - isset($metadata->fieldMappings[$property->name]->declared) - && $metadata->fieldMappings[$property->name]->declared === $declaringClass - ) { - return true; - } - - if ( - isset($metadata->associationMappings[$property->name]->declared) - && $metadata->associationMappings[$property->name]->declared === $declaringClass - ) { - return true; - } - - return isset($metadata->embeddedClasses[$property->name]->declared) - && $metadata->embeddedClasses[$property->name]->declared === $declaringClass; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/RepeatableAttributeCollection.php b/vendor/doctrine/orm/src/Mapping/Driver/RepeatableAttributeCollection.php deleted file mode 100644 index 2f6ae93..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/RepeatableAttributeCollection.php +++ /dev/null @@ -1,16 +0,0 @@ - - * @template T of MappingAttribute - */ -final class RepeatableAttributeCollection extends ArrayObject -{ -} diff --git a/vendor/doctrine/orm/src/Mapping/Driver/SimplifiedXmlDriver.php b/vendor/doctrine/orm/src/Mapping/Driver/SimplifiedXmlDriver.php deleted file mode 100644 index 486185f..0000000 --- a/vendor/doctrine/orm/src/Mapping/Driver/SimplifiedXmlDriver.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ -class XmlDriver extends FileDriver -{ - public const DEFAULT_FILE_EXTENSION = '.dcm.xml'; - - /** - * {@inheritDoc} - */ - public function __construct( - string|array|FileLocator $locator, - string $fileExtension = self::DEFAULT_FILE_EXTENSION, - private readonly bool $isXsdValidationEnabled = true, - ) { - if (! extension_loaded('simplexml')) { - throw new LogicException( - 'The XML metadata driver cannot be enabled because the SimpleXML PHP extension is missing.' - . ' Please configure PHP with SimpleXML or choose a different metadata driver.', - ); - } - - if ($isXsdValidationEnabled && ! extension_loaded('dom')) { - throw new LogicException( - 'XSD validation cannot be enabled because the DOM extension is missing.', - ); - } - - parent::__construct($locator, $fileExtension); - } - - /** - * {@inheritDoc} - * - * @psalm-param class-string $className - * @psalm-param ClassMetadata $metadata - * - * @template T of object - */ - public function loadMetadataForClass($className, PersistenceClassMetadata $metadata): void - { - $xmlRoot = $this->getElement($className); - - if ($xmlRoot->getName() === 'entity') { - if (isset($xmlRoot['repository-class'])) { - $metadata->setCustomRepositoryClass((string) $xmlRoot['repository-class']); - } - - if (isset($xmlRoot['read-only']) && $this->evaluateBoolean($xmlRoot['read-only'])) { - $metadata->markReadOnly(); - } - } elseif ($xmlRoot->getName() === 'mapped-superclass') { - $metadata->setCustomRepositoryClass( - isset($xmlRoot['repository-class']) ? (string) $xmlRoot['repository-class'] : null, - ); - $metadata->isMappedSuperclass = true; - } elseif ($xmlRoot->getName() === 'embeddable') { - $metadata->isEmbeddedClass = true; - } else { - throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); - } - - // Evaluate attributes - $primaryTable = []; - - if (isset($xmlRoot['table'])) { - $primaryTable['name'] = (string) $xmlRoot['table']; - } - - if (isset($xmlRoot['schema'])) { - $primaryTable['schema'] = (string) $xmlRoot['schema']; - } - - $metadata->setPrimaryTable($primaryTable); - - // Evaluate second level cache - if (isset($xmlRoot->cache)) { - $metadata->enableCache($this->cacheToArray($xmlRoot->cache)); - } - - if (isset($xmlRoot['inheritance-type'])) { - $inheritanceType = (string) $xmlRoot['inheritance-type']; - $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType)); - - if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { - // Evaluate - if (isset($xmlRoot->{'discriminator-column'})) { - $discrColumn = $xmlRoot->{'discriminator-column'}; - $columnDef = [ - 'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null, - 'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string', - 'length' => isset($discrColumn['length']) ? (int) $discrColumn['length'] : 255, - 'columnDefinition' => isset($discrColumn['column-definition']) ? (string) $discrColumn['column-definition'] : null, - 'enumType' => isset($discrColumn['enum-type']) ? (string) $discrColumn['enum-type'] : null, - ]; - - if (isset($discrColumn['options'])) { - assert($discrColumn['options'] instanceof SimpleXMLElement); - $columnDef['options'] = $this->parseOptions($discrColumn['options']->children()); - } - - $metadata->setDiscriminatorColumn($columnDef); - } else { - $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]); - } - - // Evaluate - if (isset($xmlRoot->{'discriminator-map'})) { - $map = []; - assert($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} instanceof SimpleXMLElement); - foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) { - $map[(string) $discrMapElement['value']] = (string) $discrMapElement['class']; - } - - $metadata->setDiscriminatorMap($map); - } - } - } - - // Evaluate - if (isset($xmlRoot['change-tracking-policy'])) { - $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' - . strtoupper((string) $xmlRoot['change-tracking-policy']))); - } - - // Evaluate - if (isset($xmlRoot->indexes)) { - $metadata->table['indexes'] = []; - foreach ($xmlRoot->indexes->index ?? [] as $indexXml) { - $index = []; - - if (isset($indexXml['columns']) && ! empty($indexXml['columns'])) { - $index['columns'] = explode(',', (string) $indexXml['columns']); - } - - if (isset($indexXml['fields'])) { - $index['fields'] = explode(',', (string) $indexXml['fields']); - } - - if ( - isset($index['columns'], $index['fields']) - || ( - ! isset($index['columns']) - && ! isset($index['fields']) - ) - ) { - throw MappingException::invalidIndexConfiguration( - $className, - (string) ($indexXml['name'] ?? count($metadata->table['indexes'])), - ); - } - - if (isset($indexXml['flags'])) { - $index['flags'] = explode(',', (string) $indexXml['flags']); - } - - if (isset($indexXml->options)) { - $index['options'] = $this->parseOptions($indexXml->options->children()); - } - - if (isset($indexXml['name'])) { - $metadata->table['indexes'][(string) $indexXml['name']] = $index; - } else { - $metadata->table['indexes'][] = $index; - } - } - } - - // Evaluate - if (isset($xmlRoot->{'unique-constraints'})) { - $metadata->table['uniqueConstraints'] = []; - foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} ?? [] as $uniqueXml) { - $unique = []; - - if (isset($uniqueXml['columns']) && ! empty($uniqueXml['columns'])) { - $unique['columns'] = explode(',', (string) $uniqueXml['columns']); - } - - if (isset($uniqueXml['fields'])) { - $unique['fields'] = explode(',', (string) $uniqueXml['fields']); - } - - if ( - isset($unique['columns'], $unique['fields']) - || ( - ! isset($unique['columns']) - && ! isset($unique['fields']) - ) - ) { - throw MappingException::invalidUniqueConstraintConfiguration( - $className, - (string) ($uniqueXml['name'] ?? count($metadata->table['uniqueConstraints'])), - ); - } - - if (isset($uniqueXml->options)) { - $unique['options'] = $this->parseOptions($uniqueXml->options->children()); - } - - if (isset($uniqueXml['name'])) { - $metadata->table['uniqueConstraints'][(string) $uniqueXml['name']] = $unique; - } else { - $metadata->table['uniqueConstraints'][] = $unique; - } - } - } - - if (isset($xmlRoot->options)) { - $metadata->table['options'] = $this->parseOptions($xmlRoot->options->children()); - } - - // The mapping assignment is done in 2 times as a bug might occurs on some php/xml lib versions - // The internal SimpleXmlIterator get resetted, to this generate a duplicate field exception - // Evaluate mappings - if (isset($xmlRoot->field)) { - foreach ($xmlRoot->field as $fieldMapping) { - $mapping = $this->columnToArray($fieldMapping); - - if (isset($mapping['version'])) { - $metadata->setVersionMapping($mapping); - unset($mapping['version']); - } - - $metadata->mapField($mapping); - } - } - - if (isset($xmlRoot->embedded)) { - foreach ($xmlRoot->embedded as $embeddedMapping) { - $columnPrefix = isset($embeddedMapping['column-prefix']) - ? (string) $embeddedMapping['column-prefix'] - : null; - - $useColumnPrefix = isset($embeddedMapping['use-column-prefix']) - ? $this->evaluateBoolean($embeddedMapping['use-column-prefix']) - : true; - - $mapping = [ - 'fieldName' => (string) $embeddedMapping['name'], - 'class' => isset($embeddedMapping['class']) ? (string) $embeddedMapping['class'] : null, - 'columnPrefix' => $useColumnPrefix ? $columnPrefix : false, - ]; - - $metadata->mapEmbedded($mapping); - } - } - - // Evaluate mappings - $associationIds = []; - foreach ($xmlRoot->id ?? [] as $idElement) { - if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) { - $associationIds[(string) $idElement['name']] = true; - continue; - } - - $mapping = $this->columnToArray($idElement); - $mapping['id'] = true; - - $metadata->mapField($mapping); - - if (isset($idElement->generator)) { - $strategy = isset($idElement->generator['strategy']) ? - (string) $idElement->generator['strategy'] : 'AUTO'; - $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' - . $strategy)); - } - - // Check for SequenceGenerator/TableGenerator definition - if (isset($idElement->{'sequence-generator'})) { - $seqGenerator = $idElement->{'sequence-generator'}; - $metadata->setSequenceGeneratorDefinition( - [ - 'sequenceName' => (string) $seqGenerator['sequence-name'], - 'allocationSize' => (string) $seqGenerator['allocation-size'], - 'initialValue' => (string) $seqGenerator['initial-value'], - ], - ); - } elseif (isset($idElement->{'custom-id-generator'})) { - $customGenerator = $idElement->{'custom-id-generator'}; - $metadata->setCustomGeneratorDefinition( - [ - 'class' => (string) $customGenerator['class'], - ], - ); - } - } - - // Evaluate mappings - if (isset($xmlRoot->{'one-to-one'})) { - foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) { - $mapping = [ - 'fieldName' => (string) $oneToOneElement['field'], - ]; - - if (isset($oneToOneElement['target-entity'])) { - $mapping['targetEntity'] = (string) $oneToOneElement['target-entity']; - } - - if (isset($associationIds[$mapping['fieldName']])) { - $mapping['id'] = true; - } - - if (isset($oneToOneElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $oneToOneElement['fetch']); - } - - if (isset($oneToOneElement['mapped-by'])) { - $mapping['mappedBy'] = (string) $oneToOneElement['mapped-by']; - } else { - if (isset($oneToOneElement['inversed-by'])) { - $mapping['inversedBy'] = (string) $oneToOneElement['inversed-by']; - } - - $joinColumns = []; - - if (isset($oneToOneElement->{'join-column'})) { - $joinColumns[] = $this->joinColumnToArray($oneToOneElement->{'join-column'}); - } elseif (isset($oneToOneElement->{'join-columns'})) { - foreach ($oneToOneElement->{'join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - } - - $mapping['joinColumns'] = $joinColumns; - } - - if (isset($oneToOneElement->cascade)) { - $mapping['cascade'] = $this->getCascadeMappings($oneToOneElement->cascade); - } - - if (isset($oneToOneElement['orphan-removal'])) { - $mapping['orphanRemoval'] = $this->evaluateBoolean($oneToOneElement['orphan-removal']); - } - - // Evaluate second level cache - if (isset($oneToOneElement->cache)) { - $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToOneElement->cache)); - } - - $metadata->mapOneToOne($mapping); - } - } - - // Evaluate mappings - if (isset($xmlRoot->{'one-to-many'})) { - foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) { - $mapping = [ - 'fieldName' => (string) $oneToManyElement['field'], - 'mappedBy' => (string) $oneToManyElement['mapped-by'], - ]; - - if (isset($oneToManyElement['target-entity'])) { - $mapping['targetEntity'] = (string) $oneToManyElement['target-entity']; - } - - if (isset($oneToManyElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $oneToManyElement['fetch']); - } - - if (isset($oneToManyElement->cascade)) { - $mapping['cascade'] = $this->getCascadeMappings($oneToManyElement->cascade); - } - - if (isset($oneToManyElement['orphan-removal'])) { - $mapping['orphanRemoval'] = $this->evaluateBoolean($oneToManyElement['orphan-removal']); - } - - if (isset($oneToManyElement->{'order-by'})) { - $orderBy = []; - foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} ?? [] as $orderByField) { - /** @psalm-suppress DeprecatedConstant */ - $orderBy[(string) $orderByField['name']] = isset($orderByField['direction']) - ? (string) $orderByField['direction'] - : (enum_exists(Order::class) ? Order::Ascending->value : Criteria::ASC); - } - - $mapping['orderBy'] = $orderBy; - } - - if (isset($oneToManyElement['index-by'])) { - $mapping['indexBy'] = (string) $oneToManyElement['index-by']; - } elseif (isset($oneToManyElement->{'index-by'})) { - throw new InvalidArgumentException(' is not a valid tag'); - } - - // Evaluate second level cache - if (isset($oneToManyElement->cache)) { - $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToManyElement->cache)); - } - - $metadata->mapOneToMany($mapping); - } - } - - // Evaluate mappings - if (isset($xmlRoot->{'many-to-one'})) { - foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) { - $mapping = [ - 'fieldName' => (string) $manyToOneElement['field'], - ]; - - if (isset($manyToOneElement['target-entity'])) { - $mapping['targetEntity'] = (string) $manyToOneElement['target-entity']; - } - - if (isset($associationIds[$mapping['fieldName']])) { - $mapping['id'] = true; - } - - if (isset($manyToOneElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $manyToOneElement['fetch']); - } - - if (isset($manyToOneElement['inversed-by'])) { - $mapping['inversedBy'] = (string) $manyToOneElement['inversed-by']; - } - - $joinColumns = []; - - if (isset($manyToOneElement->{'join-column'})) { - $joinColumns[] = $this->joinColumnToArray($manyToOneElement->{'join-column'}); - } elseif (isset($manyToOneElement->{'join-columns'})) { - foreach ($manyToOneElement->{'join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - } - - $mapping['joinColumns'] = $joinColumns; - - if (isset($manyToOneElement->cascade)) { - $mapping['cascade'] = $this->getCascadeMappings($manyToOneElement->cascade); - } - - // Evaluate second level cache - if (isset($manyToOneElement->cache)) { - $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToOneElement->cache)); - } - - $metadata->mapManyToOne($mapping); - } - } - - // Evaluate mappings - if (isset($xmlRoot->{'many-to-many'})) { - foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) { - $mapping = [ - 'fieldName' => (string) $manyToManyElement['field'], - ]; - - if (isset($manyToManyElement['target-entity'])) { - $mapping['targetEntity'] = (string) $manyToManyElement['target-entity']; - } - - if (isset($manyToManyElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $manyToManyElement['fetch']); - } - - if (isset($manyToManyElement['orphan-removal'])) { - $mapping['orphanRemoval'] = $this->evaluateBoolean($manyToManyElement['orphan-removal']); - } - - if (isset($manyToManyElement['mapped-by'])) { - $mapping['mappedBy'] = (string) $manyToManyElement['mapped-by']; - } elseif (isset($manyToManyElement->{'join-table'})) { - if (isset($manyToManyElement['inversed-by'])) { - $mapping['inversedBy'] = (string) $manyToManyElement['inversed-by']; - } - - $joinTableElement = $manyToManyElement->{'join-table'}; - $joinTable = [ - 'name' => (string) $joinTableElement['name'], - ]; - - if (isset($joinTableElement['schema'])) { - $joinTable['schema'] = (string) $joinTableElement['schema']; - } - - if (isset($joinTableElement->options)) { - $joinTable['options'] = $this->parseOptions($joinTableElement->options->children()); - } - - foreach ($joinTableElement->{'join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - $mapping['joinTable'] = $joinTable; - } - - if (isset($manyToManyElement->cascade)) { - $mapping['cascade'] = $this->getCascadeMappings($manyToManyElement->cascade); - } - - if (isset($manyToManyElement->{'order-by'})) { - $orderBy = []; - foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} ?? [] as $orderByField) { - /** @psalm-suppress DeprecatedConstant */ - $orderBy[(string) $orderByField['name']] = isset($orderByField['direction']) - ? (string) $orderByField['direction'] - : (enum_exists(Order::class) ? Order::Ascending->value : Criteria::ASC); - } - - $mapping['orderBy'] = $orderBy; - } - - if (isset($manyToManyElement['index-by'])) { - $mapping['indexBy'] = (string) $manyToManyElement['index-by']; - } elseif (isset($manyToManyElement->{'index-by'})) { - throw new InvalidArgumentException(' is not a valid tag'); - } - - // Evaluate second level cache - if (isset($manyToManyElement->cache)) { - $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToManyElement->cache)); - } - - $metadata->mapManyToMany($mapping); - } - } - - // Evaluate association-overrides - if (isset($xmlRoot->{'attribute-overrides'})) { - foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} ?? [] as $overrideElement) { - $fieldName = (string) $overrideElement['name']; - foreach ($overrideElement->field ?? [] as $field) { - $mapping = $this->columnToArray($field); - $mapping['fieldName'] = $fieldName; - $metadata->setAttributeOverride($fieldName, $mapping); - } - } - } - - // Evaluate association-overrides - if (isset($xmlRoot->{'association-overrides'})) { - foreach ($xmlRoot->{'association-overrides'}->{'association-override'} ?? [] as $overrideElement) { - $fieldName = (string) $overrideElement['name']; - $override = []; - - // Check for join-columns - if (isset($overrideElement->{'join-columns'})) { - $joinColumns = []; - foreach ($overrideElement->{'join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - - $override['joinColumns'] = $joinColumns; - } - - // Check for join-table - if ($overrideElement->{'join-table'}) { - $joinTable = null; - $joinTableElement = $overrideElement->{'join-table'}; - - $joinTable = [ - 'name' => (string) $joinTableElement['name'], - 'schema' => (string) $joinTableElement['schema'], - ]; - - if (isset($joinTableElement->options)) { - $joinTable['options'] = $this->parseOptions($joinTableElement->options->children()); - } - - if (isset($joinTableElement->{'join-columns'})) { - foreach ($joinTableElement->{'join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - } - - if (isset($joinTableElement->{'inverse-join-columns'})) { - foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} ?? [] as $joinColumnElement) { - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - } - - $override['joinTable'] = $joinTable; - } - - // Check for inversed-by - if (isset($overrideElement->{'inversed-by'})) { - $override['inversedBy'] = (string) $overrideElement->{'inversed-by'}['name']; - } - - // Check for `fetch` - if (isset($overrideElement['fetch'])) { - $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . (string) $overrideElement['fetch']); - } - - $metadata->setAssociationOverride($fieldName, $override); - } - } - - // Evaluate - if (isset($xmlRoot->{'lifecycle-callbacks'})) { - foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} ?? [] as $lifecycleCallback) { - $metadata->addLifecycleCallback((string) $lifecycleCallback['method'], constant('Doctrine\ORM\Events::' . (string) $lifecycleCallback['type'])); - } - } - - // Evaluate entity listener - if (isset($xmlRoot->{'entity-listeners'})) { - foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} ?? [] as $listenerElement) { - $className = (string) $listenerElement['class']; - // Evaluate the listener using naming convention. - if ($listenerElement->count() === 0) { - EntityListenerBuilder::bindEntityListener($metadata, $className); - - continue; - } - - foreach ($listenerElement as $callbackElement) { - $eventName = (string) $callbackElement['type']; - $methodName = (string) $callbackElement['method']; - - $metadata->addEntityListener($eventName, $className, $methodName); - } - } - } - } - - /** - * Parses (nested) option elements. - * - * @return mixed[] The options array. - * @psalm-return array|bool|string> - */ - private function parseOptions(SimpleXMLElement|null $options): array - { - $array = []; - - foreach ($options ?? [] as $option) { - if ($option->count()) { - $value = $this->parseOptions($option->children()); - } else { - $value = (string) $option; - } - - $attributes = $option->attributes(); - - if (isset($attributes->name)) { - $nameAttribute = (string) $attributes->name; - $array[$nameAttribute] = in_array($nameAttribute, ['unsigned', 'fixed'], true) - ? $this->evaluateBoolean($value) - : $value; - } else { - $array[] = $value; - } - } - - return $array; - } - - /** - * Constructs a joinColumn mapping array based on the information - * found in the given SimpleXMLElement. - * - * @param SimpleXMLElement $joinColumnElement The XML element. - * - * @return mixed[] The mapping array. - * @psalm-return array{ - * name: string, - * referencedColumnName: string, - * unique?: bool, - * nullable?: bool, - * onDelete?: string, - * columnDefinition?: string, - * options?: mixed[] - * } - */ - private function joinColumnToArray(SimpleXMLElement $joinColumnElement): array - { - $joinColumn = [ - 'name' => (string) $joinColumnElement['name'], - 'referencedColumnName' => (string) $joinColumnElement['referenced-column-name'], - ]; - - if (isset($joinColumnElement['unique'])) { - $joinColumn['unique'] = $this->evaluateBoolean($joinColumnElement['unique']); - } - - if (isset($joinColumnElement['nullable'])) { - $joinColumn['nullable'] = $this->evaluateBoolean($joinColumnElement['nullable']); - } - - if (isset($joinColumnElement['on-delete'])) { - $joinColumn['onDelete'] = (string) $joinColumnElement['on-delete']; - } - - if (isset($joinColumnElement['column-definition'])) { - $joinColumn['columnDefinition'] = (string) $joinColumnElement['column-definition']; - } - - if (isset($joinColumnElement['options'])) { - $joinColumn['options'] = $this->parseOptions($joinColumnElement['options'] ? $joinColumnElement['options']->children() : null); - } - - return $joinColumn; - } - - /** - * Parses the given field as array. - * - * @return mixed[] - * @psalm-return array{ - * fieldName: string, - * type?: string, - * columnName?: string, - * length?: int, - * precision?: int, - * scale?: int, - * unique?: bool, - * nullable?: bool, - * notInsertable?: bool, - * notUpdatable?: bool, - * enumType?: string, - * version?: bool, - * columnDefinition?: string, - * options?: array - * } - */ - private function columnToArray(SimpleXMLElement $fieldMapping): array - { - $mapping = [ - 'fieldName' => (string) $fieldMapping['name'], - ]; - - if (isset($fieldMapping['type'])) { - $mapping['type'] = (string) $fieldMapping['type']; - } - - if (isset($fieldMapping['column'])) { - $mapping['columnName'] = (string) $fieldMapping['column']; - } - - if (isset($fieldMapping['length'])) { - $mapping['length'] = (int) $fieldMapping['length']; - } - - if (isset($fieldMapping['precision'])) { - $mapping['precision'] = (int) $fieldMapping['precision']; - } - - if (isset($fieldMapping['scale'])) { - $mapping['scale'] = (int) $fieldMapping['scale']; - } - - if (isset($fieldMapping['unique'])) { - $mapping['unique'] = $this->evaluateBoolean($fieldMapping['unique']); - } - - if (isset($fieldMapping['nullable'])) { - $mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']); - } - - if (isset($fieldMapping['insertable']) && ! $this->evaluateBoolean($fieldMapping['insertable'])) { - $mapping['notInsertable'] = true; - } - - if (isset($fieldMapping['updatable']) && ! $this->evaluateBoolean($fieldMapping['updatable'])) { - $mapping['notUpdatable'] = true; - } - - if (isset($fieldMapping['generated'])) { - $mapping['generated'] = constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . (string) $fieldMapping['generated']); - } - - if (isset($fieldMapping['version']) && $fieldMapping['version']) { - $mapping['version'] = $this->evaluateBoolean($fieldMapping['version']); - } - - if (isset($fieldMapping['column-definition'])) { - $mapping['columnDefinition'] = (string) $fieldMapping['column-definition']; - } - - if (isset($fieldMapping['enum-type'])) { - $mapping['enumType'] = (string) $fieldMapping['enum-type']; - } - - if (isset($fieldMapping->options)) { - $mapping['options'] = $this->parseOptions($fieldMapping->options->children()); - } - - return $mapping; - } - - /** - * Parse / Normalize the cache configuration - * - * @return mixed[] - * @psalm-return array{usage: int|null, region?: string} - */ - private function cacheToArray(SimpleXMLElement $cacheMapping): array - { - $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null; - $usage = isset($cacheMapping['usage']) ? strtoupper((string) $cacheMapping['usage']) : null; - - if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) { - throw new InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage)); - } - - if ($usage) { - $usage = (int) constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage); - } - - return [ - 'usage' => $usage, - 'region' => $region, - ]; - } - - /** - * Gathers a list of cascade options found in the given cascade element. - * - * @param SimpleXMLElement $cascadeElement The cascade element. - * - * @return string[] The list of cascade options. - * @psalm-return list - */ - private function getCascadeMappings(SimpleXMLElement $cascadeElement): array - { - $cascades = []; - $children = $cascadeElement->children(); - assert($children !== null); - - foreach ($children as $action) { - // According to the JPA specifications, XML uses "cascade-persist" - // instead of "persist". Here, both variations - // are supported because Attribute uses "persist" - // and we want to make sure that this driver doesn't need to know - // anything about the supported cascading actions - $cascades[] = str_replace('cascade-', '', $action->getName()); - } - - return $cascades; - } - - /** - * {@inheritDoc} - */ - protected function loadMappingFile($file) - { - $this->validateMapping($file); - $result = []; - // Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577 - $xmlElement = simplexml_load_string(file_get_contents($file)); - assert($xmlElement !== false); - - if (isset($xmlElement->entity)) { - foreach ($xmlElement->entity as $entityElement) { - /** @psalm-var class-string $entityName */ - $entityName = (string) $entityElement['name']; - $result[$entityName] = $entityElement; - } - } elseif (isset($xmlElement->{'mapped-superclass'})) { - foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) { - /** @psalm-var class-string $className */ - $className = (string) $mappedSuperClass['name']; - $result[$className] = $mappedSuperClass; - } - } elseif (isset($xmlElement->embeddable)) { - foreach ($xmlElement->embeddable as $embeddableElement) { - /** @psalm-var class-string $embeddableName */ - $embeddableName = (string) $embeddableElement['name']; - $result[$embeddableName] = $embeddableElement; - } - } - - return $result; - } - - private function validateMapping(string $file): void - { - if (! $this->isXsdValidationEnabled) { - return; - } - - $backedUpErrorSetting = libxml_use_internal_errors(true); - - try { - $document = new DOMDocument(); - $document->load($file); - - if (! $document->schemaValidate(__DIR__ . '/../../../doctrine-mapping.xsd')) { - throw MappingException::fromLibXmlErrors(libxml_get_errors()); - } - } finally { - libxml_clear_errors(); - libxml_use_internal_errors($backedUpErrorSetting); - } - } - - protected function evaluateBoolean(mixed $element): bool - { - $flag = (string) $element; - - return $flag === 'true' || $flag === '1'; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Embeddable.php b/vendor/doctrine/orm/src/Mapping/Embeddable.php deleted file mode 100644 index b8dfea0..0000000 --- a/vendor/doctrine/orm/src/Mapping/Embeddable.php +++ /dev/null @@ -1,12 +0,0 @@ - */ -final class EmbeddedClassMapping implements ArrayAccess -{ - use ArrayAccessImplementation; - - public string|false|null $columnPrefix = null; - public string|null $declaredField = null; - public string|null $originalField = null; - - /** - * This is set when this embedded-class field is inherited by this class - * from another (inheritance) parent entity class. The value is - * the FQCN of the topmost entity class that contains mapping information - * for this field. (If there are transient classes in the class hierarchy, - * these are ignored, so the class property may in fact come from a class - * further up in the PHP class hierarchy.) Fields initially declared in - * mapped superclasses are not considered 'inherited' in the - * nearest entity subclasses. - * - * @var class-string|null - */ - public string|null $inherited = null; - - /** - * This is set when the embedded-class field does not appear for the first - * time in this class, but is originally declared in another parent - * entity or mapped superclass. The value is the FQCN of the - * topmost non-transient class that contains mapping information for this - * field. - * - * @var class-string|null - */ - public string|null $declared = null; - - /** @param class-string $class */ - public function __construct(public string $class) - { - } - - /** - * @psalm-param array{ - * class: class-string, - * columnPrefix?: false|string|null, - * declaredField?: string|null, - * originalField?: string|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): self - { - $mapping = new self($mappingArray['class']); - foreach ($mappingArray as $key => $value) { - if ($key === 'class') { - continue; - } - - if (property_exists($mapping, $key)) { - $mapping->$key = $value; - } - } - - return $mapping; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = ['class']; - - if ($this->columnPrefix) { - $serialized[] = 'columnPrefix'; - } - - foreach (['declaredField', 'originalField', 'inherited', 'declared'] as $property) { - if ($this->$property !== null) { - $serialized[] = $property; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Entity.php b/vendor/doctrine/orm/src/Mapping/Entity.php deleted file mode 100644 index 0e27913..0000000 --- a/vendor/doctrine/orm/src/Mapping/Entity.php +++ /dev/null @@ -1,20 +0,0 @@ ->|null $repositoryClass */ - public function __construct( - public readonly string|null $repositoryClass = null, - public readonly bool $readOnly = false, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/EntityListenerResolver.php b/vendor/doctrine/orm/src/Mapping/EntityListenerResolver.php deleted file mode 100644 index eabc217..0000000 --- a/vendor/doctrine/orm/src/Mapping/EntityListenerResolver.php +++ /dev/null @@ -1,30 +0,0 @@ - $value */ - public function __construct( - public readonly array $value = [], - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Exception/InvalidCustomGenerator.php b/vendor/doctrine/orm/src/Mapping/Exception/InvalidCustomGenerator.php deleted file mode 100644 index b9e10bf..0000000 --- a/vendor/doctrine/orm/src/Mapping/Exception/InvalidCustomGenerator.php +++ /dev/null @@ -1,28 +0,0 @@ - */ -final class FieldMapping implements ArrayAccess -{ - use ArrayAccessImplementation; - - /** The database length of the column. Optional. Default value taken from the type. */ - public int|null $length = null; - /** - * Marks the field as the primary key of the entity. Multiple - * fields of an entity can have the id attribute, forming a composite key. - */ - public bool|null $id = null; - public bool|null $nullable = null; - public bool|null $notInsertable = null; - public bool|null $notUpdatable = null; - public string|null $columnDefinition = null; - /** @psalm-var ClassMetadata::GENERATED_*|null */ - public int|null $generated = null; - /** @var class-string|null */ - public string|null $enumType = null; - /** - * The precision of a decimal column. - * Only valid if the column type is decimal - */ - public int|null $precision = null; - /** - * The scale of a decimal column. - * Only valid if the column type is decimal - */ - public int|null $scale = null; - /** Whether a unique constraint should be generated for the column. */ - public bool|null $unique = null; - /** - * @var class-string|null This is set when the field is inherited by this - * class from another (inheritance) parent entity class. The value - * is the FQCN of the topmost entity class that contains mapping information - * for this field. (If there are transient classes in the class hierarchy, - * these are ignored, so the class property may in fact come from a class - * further up in the PHP class hierarchy.) - * Fields initially declared in mapped superclasses are - * not considered 'inherited' in the nearest entity subclasses. - */ - public string|null $inherited = null; - - public string|null $originalClass = null; - public string|null $originalField = null; - public bool|null $quoted = null; - /** - * @var class-string|null This is set when the field does not appear for - * the first time in this class, but is originally declared in another - * parent entity or mapped superclass. The value is the FQCN of - * the topmost non-transient class that contains mapping information for - * this field. - */ - public string|null $declared = null; - public string|null $declaredField = null; - public array|null $options = null; - public bool|null $version = null; - public string|int|null $default = null; - - /** - * @param string $type The type name of the mapped field. Can be one of - * Doctrine's mapping types or a custom mapping type. - * @param string $fieldName The name of the field in the Entity. - * @param string $columnName The column name. Optional. Defaults to the field name. - */ - public function __construct( - public string $type, - public string $fieldName, - public string $columnName, - ) { - } - - /** - * @param array $mappingArray - * @psalm-param array{ - * type: string, - * fieldName: string, - * columnName: string, - * length?: int|null, - * id?: bool|null, - * nullable?: bool|null, - * notInsertable?: bool|null, - * notUpdatable?: bool|null, - * columnDefinition?: string|null, - * generated?: ClassMetadata::GENERATED_*|null, - * enumType?: string|null, - * precision?: int|null, - * scale?: int|null, - * unique?: bool|null, - * inherited?: string|null, - * originalClass?: string|null, - * originalField?: string|null, - * quoted?: bool|null, - * declared?: string|null, - * declaredField?: string|null, - * options?: array|null, - * version?: bool|null, - * default?: string|int|null, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): self - { - $mapping = new self( - $mappingArray['type'], - $mappingArray['fieldName'], - $mappingArray['columnName'], - ); - foreach ($mappingArray as $key => $value) { - if (in_array($key, ['type', 'fieldName', 'columnName'])) { - continue; - } - - if (property_exists($mapping, $key)) { - $mapping->$key = $value; - } - } - - return $mapping; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = ['type', 'fieldName', 'columnName']; - - foreach (['nullable', 'notInsertable', 'notUpdatable', 'id', 'unique', 'version', 'quoted'] as $boolKey) { - if ($this->$boolKey) { - $serialized[] = $boolKey; - } - } - - foreach ( - [ - 'length', - 'columnDefinition', - 'generated', - 'enumType', - 'precision', - 'scale', - 'inherited', - 'originalClass', - 'originalField', - 'declared', - 'declaredField', - 'options', - 'default', - ] as $key - ) { - if ($this->$key !== null) { - $serialized[] = $key; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/GeneratedValue.php b/vendor/doctrine/orm/src/Mapping/GeneratedValue.php deleted file mode 100644 index aca5f4b..0000000 --- a/vendor/doctrine/orm/src/Mapping/GeneratedValue.php +++ /dev/null @@ -1,17 +0,0 @@ -|null $columns - * @param array|null $fields - * @param array|null $flags - * @param array|null $options - */ - public function __construct( - public readonly string|null $name = null, - public readonly array|null $columns = null, - public readonly array|null $fields = null, - public readonly array|null $flags = null, - public readonly array|null $options = null, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/InheritanceType.php b/vendor/doctrine/orm/src/Mapping/InheritanceType.php deleted file mode 100644 index c042ee7..0000000 --- a/vendor/doctrine/orm/src/Mapping/InheritanceType.php +++ /dev/null @@ -1,17 +0,0 @@ -mappedBy; - } - - /** @return list */ - public function __sleep(): array - { - return [ - ...parent::__sleep(), - 'mappedBy', - ]; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/JoinColumn.php b/vendor/doctrine/orm/src/Mapping/JoinColumn.php deleted file mode 100644 index 9a049fb..0000000 --- a/vendor/doctrine/orm/src/Mapping/JoinColumn.php +++ /dev/null @@ -1,13 +0,0 @@ - */ -final class JoinColumnMapping implements ArrayAccess -{ - use ArrayAccessImplementation; - - public bool|null $unique = null; - public bool|null $quoted = null; - public string|null $fieldName = null; - public string|null $onDelete = null; - public string|null $columnDefinition = null; - public bool|null $nullable = null; - - /** @var array|null */ - public array|null $options = null; - - public function __construct( - public string $name, - public string $referencedColumnName, - ) { - } - - /** - * @param array $mappingArray - * @psalm-param array{ - * name: string, - * referencedColumnName: string, - * unique?: bool|null, - * quoted?: bool|null, - * fieldName?: string|null, - * onDelete?: string|null, - * columnDefinition?: string|null, - * nullable?: bool|null, - * options?: array|null, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): self - { - $mapping = new self($mappingArray['name'], $mappingArray['referencedColumnName']); - foreach ($mappingArray as $key => $value) { - if (property_exists($mapping, $key) && $value !== null) { - $mapping->$key = $value; - } - } - - return $mapping; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = []; - - foreach (['name', 'fieldName', 'onDelete', 'columnDefinition', 'referencedColumnName', 'options'] as $stringOrArrayKey) { - if ($this->$stringOrArrayKey !== null) { - $serialized[] = $stringOrArrayKey; - } - } - - foreach (['unique', 'quoted', 'nullable'] as $boolKey) { - if ($this->$boolKey !== null) { - $serialized[] = $boolKey; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/JoinColumnProperties.php b/vendor/doctrine/orm/src/Mapping/JoinColumnProperties.php deleted file mode 100644 index 7d13295..0000000 --- a/vendor/doctrine/orm/src/Mapping/JoinColumnProperties.php +++ /dev/null @@ -1,21 +0,0 @@ - $options */ - public function __construct( - public readonly string|null $name = null, - public readonly string $referencedColumnName = 'id', - public readonly bool $unique = false, - public readonly bool $nullable = true, - public readonly mixed $onDelete = null, - public readonly string|null $columnDefinition = null, - public readonly string|null $fieldName = null, - public readonly array $options = [], - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/JoinColumns.php b/vendor/doctrine/orm/src/Mapping/JoinColumns.php deleted file mode 100644 index f166b76..0000000 --- a/vendor/doctrine/orm/src/Mapping/JoinColumns.php +++ /dev/null @@ -1,14 +0,0 @@ - $value */ - public function __construct( - public readonly array $value, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/JoinTable.php b/vendor/doctrine/orm/src/Mapping/JoinTable.php deleted file mode 100644 index 0558761..0000000 --- a/vendor/doctrine/orm/src/Mapping/JoinTable.php +++ /dev/null @@ -1,35 +0,0 @@ - */ - public readonly array $joinColumns; - - /** @var array */ - public readonly array $inverseJoinColumns; - - /** - * @param array|JoinColumn $joinColumns - * @param array|JoinColumn $inverseJoinColumns - * @param array $options - */ - public function __construct( - public readonly string|null $name = null, - public readonly string|null $schema = null, - array|JoinColumn $joinColumns = [], - array|JoinColumn $inverseJoinColumns = [], - public readonly array $options = [], - ) { - $this->joinColumns = $joinColumns instanceof JoinColumn ? [$joinColumns] : $joinColumns; - $this->inverseJoinColumns = $inverseJoinColumns instanceof JoinColumn - ? [$inverseJoinColumns] - : $inverseJoinColumns; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/JoinTableMapping.php b/vendor/doctrine/orm/src/Mapping/JoinTableMapping.php deleted file mode 100644 index c8b4968..0000000 --- a/vendor/doctrine/orm/src/Mapping/JoinTableMapping.php +++ /dev/null @@ -1,115 +0,0 @@ - */ -final class JoinTableMapping implements ArrayAccess -{ - use ArrayAccessImplementation; - - public bool|null $quoted = null; - - /** @var list */ - public array $joinColumns = []; - - /** @var list */ - public array $inverseJoinColumns = []; - - /** @var array */ - public array $options = []; - - public string|null $schema = null; - - public function __construct(public string $name) - { - } - - /** - * @param mixed[] $mappingArray - * @psalm-param array{ - * name: string, - * quoted?: bool|null, - * joinColumns?: mixed[], - * inverseJoinColumns?: mixed[], - * schema?: string|null, - * options?: array - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): self - { - $mapping = new self($mappingArray['name']); - - foreach (['quoted', 'schema', 'options'] as $key) { - if (isset($mappingArray[$key])) { - $mapping->$key = $mappingArray[$key]; - } - } - - if (isset($mappingArray['joinColumns'])) { - foreach ($mappingArray['joinColumns'] as $column) { - $mapping->joinColumns[] = JoinColumnMapping::fromMappingArray($column); - } - } - - if (isset($mappingArray['inverseJoinColumns'])) { - foreach ($mappingArray['inverseJoinColumns'] as $column) { - $mapping->inverseJoinColumns[] = JoinColumnMapping::fromMappingArray($column); - } - } - - return $mapping; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if (in_array($offset, ['joinColumns', 'inverseJoinColumns'], true)) { - $joinColumns = []; - foreach ($value as $column) { - $joinColumns[] = JoinColumnMapping::fromMappingArray($column); - } - - $value = $joinColumns; - } - - $this->$offset = $value; - } - - /** @return mixed[] */ - public function toArray(): array - { - $array = (array) $this; - - $toArray = static fn (JoinColumnMapping $column): array => (array) $column; - $array['joinColumns'] = array_map($toArray, $array['joinColumns']); - $array['inverseJoinColumns'] = array_map($toArray, $array['inverseJoinColumns']); - - return $array; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = []; - - foreach (['joinColumns', 'inverseJoinColumns', 'name', 'schema', 'options'] as $stringOrArrayKey) { - if ($this->$stringOrArrayKey !== null) { - $serialized[] = $stringOrArrayKey; - } - } - - foreach (['quoted'] as $boolKey) { - if ($this->$boolKey) { - $serialized[] = $boolKey; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ManyToMany.php b/vendor/doctrine/orm/src/Mapping/ManyToMany.php deleted file mode 100644 index d90a762..0000000 --- a/vendor/doctrine/orm/src/Mapping/ManyToMany.php +++ /dev/null @@ -1,27 +0,0 @@ - */ - public array $joinTableColumns = []; - - /** @var array */ - public array $relationToSourceKeyColumns = []; - /** @var array */ - public array $relationToTargetKeyColumns = []; - - /** @return array */ - public function toArray(): array - { - $array = parent::toArray(); - - $array['joinTable'] = $this->joinTable->toArray(); - - return $array; - } - - /** - * @param mixed[] $mappingArray - * @psalm-param array{ - * fieldName: string, - * sourceEntity: class-string, - * targetEntity: class-string, - * cascade?: list<'persist'|'remove'|'detach'|'refresh'|'all'>, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * } $mappingArray - */ - public static function fromMappingArrayAndNamingStrategy(array $mappingArray, NamingStrategy $namingStrategy): self - { - if (isset($mappingArray['joinTable']['joinColumns'])) { - foreach ($mappingArray['joinTable']['joinColumns'] as $key => $joinColumn) { - if (empty($joinColumn['name'])) { - $mappingArray['joinTable']['joinColumns'][$key]['name'] = $namingStrategy->joinKeyColumnName( - $mappingArray['sourceEntity'], - $joinColumn['referencedColumnName'] ?? null, - ); - } - } - } - - if (isset($mappingArray['joinTable']['inverseJoinColumns'])) { - foreach ($mappingArray['joinTable']['inverseJoinColumns'] as $key => $joinColumn) { - if (empty($joinColumn['name'])) { - $mappingArray['joinTable']['inverseJoinColumns'][$key]['name'] = $namingStrategy->joinKeyColumnName( - $mappingArray['targetEntity'], - $joinColumn['referencedColumnName'] ?? null, - ); - } - } - } - - // owning side MUST have a join table - if (! isset($mappingArray['joinTable']) || ! isset($mappingArray['joinTable']['name'])) { - $mappingArray['joinTable']['name'] = $namingStrategy->joinTableName( - $mappingArray['sourceEntity'], - $mappingArray['targetEntity'], - $mappingArray['fieldName'], - ); - } - - $mapping = parent::fromMappingArray($mappingArray); - - $selfReferencingEntityWithoutJoinColumns = $mapping->sourceEntity === $mapping->targetEntity - && $mapping->joinTable->joinColumns === [] - && $mapping->joinTable->inverseJoinColumns === []; - - if ($mapping->joinTable->joinColumns === []) { - $mapping->joinTable->joinColumns = [ - JoinColumnMapping::fromMappingArray([ - 'name' => $namingStrategy->joinKeyColumnName($mapping->sourceEntity, $selfReferencingEntityWithoutJoinColumns ? 'source' : null), - 'referencedColumnName' => $namingStrategy->referenceColumnName(), - 'onDelete' => 'CASCADE', - ]), - ]; - } - - if ($mapping->joinTable->inverseJoinColumns === []) { - $mapping->joinTable->inverseJoinColumns = [ - JoinColumnMapping::fromMappingArray([ - 'name' => $namingStrategy->joinKeyColumnName($mapping->targetEntity, $selfReferencingEntityWithoutJoinColumns ? 'target' : null), - 'referencedColumnName' => $namingStrategy->referenceColumnName(), - 'onDelete' => 'CASCADE', - ]), - ]; - } - - $mapping->joinTableColumns = []; - - foreach ($mapping->joinTable->joinColumns as $joinColumn) { - if (empty($joinColumn->referencedColumnName)) { - $joinColumn->referencedColumnName = $namingStrategy->referenceColumnName(); - } - - if ($joinColumn->name[0] === '`') { - $joinColumn->name = trim($joinColumn->name, '`'); - $joinColumn->quoted = true; - } - - if ($joinColumn->referencedColumnName[0] === '`') { - $joinColumn->referencedColumnName = trim($joinColumn->referencedColumnName, '`'); - $joinColumn->quoted = true; - } - - if (isset($joinColumn->onDelete) && strtolower($joinColumn->onDelete) === 'cascade') { - $mapping->isOnDeleteCascade = true; - } - - $mapping->relationToSourceKeyColumns[$joinColumn->name] = $joinColumn->referencedColumnName; - $mapping->joinTableColumns[] = $joinColumn->name; - } - - foreach ($mapping->joinTable->inverseJoinColumns as $inverseJoinColumn) { - if (empty($inverseJoinColumn->referencedColumnName)) { - $inverseJoinColumn->referencedColumnName = $namingStrategy->referenceColumnName(); - } - - if ($inverseJoinColumn->name[0] === '`') { - $inverseJoinColumn->name = trim($inverseJoinColumn->name, '`'); - $inverseJoinColumn->quoted = true; - } - - if ($inverseJoinColumn->referencedColumnName[0] === '`') { - $inverseJoinColumn->referencedColumnName = trim($inverseJoinColumn->referencedColumnName, '`'); - $inverseJoinColumn->quoted = true; - } - - if (isset($inverseJoinColumn->onDelete) && strtolower($inverseJoinColumn->onDelete) === 'cascade') { - $mapping->isOnDeleteCascade = true; - } - - $mapping->relationToTargetKeyColumns[$inverseJoinColumn->name] = $inverseJoinColumn->referencedColumnName; - $mapping->joinTableColumns[] = $inverseJoinColumn->name; - } - - return $mapping; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = parent::__sleep(); - $serialized[] = 'joinTable'; - $serialized[] = 'joinTableColumns'; - - foreach (['relationToSourceKeyColumns', 'relationToTargetKeyColumns'] as $arrayKey) { - if ($this->$arrayKey !== null) { - $serialized[] = $arrayKey; - } - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ManyToOne.php b/vendor/doctrine/orm/src/Mapping/ManyToOne.php deleted file mode 100644 index 8fccff3..0000000 --- a/vendor/doctrine/orm/src/Mapping/ManyToOne.php +++ /dev/null @@ -1,24 +0,0 @@ -|null $repositoryClass */ - public function __construct( - public readonly string|null $repositoryClass = null, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/MappingAttribute.php b/vendor/doctrine/orm/src/Mapping/MappingAttribute.php deleted file mode 100644 index 61091a9..0000000 --- a/vendor/doctrine/orm/src/Mapping/MappingAttribute.php +++ /dev/null @@ -1,10 +0,0 @@ - $map - */ - public static function duplicateDiscriminatorEntry(string $className, array $entries, array $map): self - { - return new self( - 'The entries ' . implode(', ', $entries) . " in discriminator map of class '" . $className . "' is duplicated. " . - 'If the discriminator map is automatically generated you have to convert it to an explicit discriminator map now. ' . - 'The entries of the current map are: @DiscriminatorMap({' . implode(', ', array_map( - static fn ($a, $b) => sprintf("'%s': '%s'", $a, $b), - array_keys($map), - array_values($map), - )) . '})', - ); - } - - /** - * @param class-string $rootEntityClass - * @param class-string $childEntityClass - */ - public static function missingInheritanceTypeDeclaration(string $rootEntityClass, string $childEntityClass): self - { - return new self(sprintf( - "Entity class '%s' is a subclass of the root entity class '%s', but no inheritance mapping type was declared.", - $childEntityClass, - $rootEntityClass, - )); - } - - public static function missingDiscriminatorMap(string $className): self - { - return new self(sprintf( - "Entity class '%s' is using inheritance but no discriminator map was defined.", - $className, - )); - } - - public static function missingDiscriminatorColumn(string $className): self - { - return new self(sprintf( - "Entity class '%s' is using inheritance but no discriminator column was defined.", - $className, - )); - } - - public static function invalidDiscriminatorColumnType(string $className, string $type): self - { - return new self(sprintf( - "Discriminator column type on entity class '%s' is not allowed to be '%s'. 'string' or 'integer' type variables are suggested!", - $className, - $type, - )); - } - - public static function nameIsMandatoryForDiscriminatorColumns(string $className): self - { - return new self(sprintf("Discriminator column name on entity class '%s' is not defined.", $className)); - } - - public static function cannotVersionIdField(string $className, string $fieldName): self - { - return new self(sprintf( - "Setting Id field '%s' as versionable in entity class '%s' is not supported.", - $fieldName, - $className, - )); - } - - public static function duplicateColumnName(string $className, string $columnName): self - { - return new self("Duplicate definition of column '" . $columnName . "' on entity '" . $className . "' in a field or discriminator column mapping."); - } - - public static function illegalToManyAssociationOnMappedSuperclass(string $className, string $field): self - { - return new self("It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass '" . $className . '#' . $field . "'."); - } - - public static function cannotMapCompositePrimaryKeyEntitiesAsForeignId(string $className, string $targetEntity, string $targetField): self - { - return new self("It is not possible to map entity '" . $className . "' with a composite primary key " . - "as part of the primary key of another entity '" . $targetEntity . '#' . $targetField . "'."); - } - - public static function noSingleAssociationJoinColumnFound(string $className, string $field): self - { - return new self(sprintf("'%s#%s' is not an association with a single join column.", $className, $field)); - } - - public static function noFieldNameFoundForColumn(string $className, string $column): self - { - return new self(sprintf( - "Cannot find a field on '%s' that is mapped to column '%s'. Either the " . - 'field does not exist or an association exists but it has multiple join columns.', - $className, - $column, - )); - } - - public static function illegalOrphanRemovalOnIdentifierAssociation(string $className, string $field): self - { - return new self(sprintf( - "The orphan removal option is not allowed on an association that is part of the identifier in '%s#%s'.", - $className, - $field, - )); - } - - public static function illegalOrphanRemoval(string $className, string $field): self - { - return new self('Orphan removal is only allowed on one-to-one and one-to-many ' . - 'associations, but ' . $className . '#' . $field . ' is not.'); - } - - public static function illegalInverseIdentifierAssociation(string $className, string $field): self - { - return new self(sprintf( - "An inverse association is not allowed to be identifier in '%s#%s'.", - $className, - $field, - )); - } - - public static function illegalToManyIdentifierAssociation(string $className, string $field): self - { - return new self(sprintf( - "Many-to-many or one-to-many associations are not allowed to be identifier in '%s#%s'.", - $className, - $field, - )); - } - - public static function noInheritanceOnMappedSuperClass(string $className): self - { - return new self("It is not supported to define inheritance information on a mapped superclass '" . $className . "'."); - } - - public static function mappedClassNotPartOfDiscriminatorMap(string $className, string $rootClassName): self - { - return new self( - "Entity '" . $className . "' has to be part of the discriminator map of '" . $rootClassName . "' " . - "to be properly mapped in the inheritance hierarchy. Alternatively you can make '" . $className . "' an abstract class " . - 'to avoid this exception from occurring.', - ); - } - - public static function lifecycleCallbackMethodNotFound(string $className, string $methodName): self - { - return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback."); - } - - /** @param class-string $className */ - public static function illegalLifecycleCallbackOnEmbeddedClass(string $event, string $className): self - { - return new self(sprintf( - <<<'EXCEPTION' - Context: Attempt to register lifecycle callback "%s" on embedded class "%s". - Problem: Registering lifecycle callbacks on embedded classes is not allowed. - EXCEPTION, - $event, - $className, - )); - } - - public static function entityListenerClassNotFound(string $listenerName, string $className): self - { - return new self(sprintf('Entity Listener "%s" declared on "%s" not found.', $listenerName, $className)); - } - - public static function entityListenerMethodNotFound(string $listenerName, string $methodName, string $className): self - { - return new self(sprintf('Entity Listener "%s" declared on "%s" has no method "%s".', $listenerName, $className, $methodName)); - } - - public static function duplicateEntityListener(string $listenerName, string $methodName, string $className): self - { - return new self(sprintf('Entity Listener "%s#%s()" in "%s" was already declared, but it must be declared only once.', $listenerName, $methodName, $className)); - } - - /** @param class-string $className */ - public static function invalidFetchMode(string $className, string $fetchMode): self - { - return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $fetchMode . "'"); - } - - public static function invalidGeneratedMode(int|string $generatedMode): self - { - return new self("Invalid generated mode '" . $generatedMode . "'"); - } - - public static function compositeKeyAssignedIdGeneratorRequired(string $className): self - { - return new self("Entity '" . $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported."); - } - - public static function invalidTargetEntityClass(string $targetEntity, string $sourceEntity, string $associationName): self - { - return new self('The target-entity ' . $targetEntity . " cannot be found in '" . $sourceEntity . '#' . $associationName . "'."); - } - - /** @param string[] $cascades */ - public static function invalidCascadeOption(array $cascades, string $className, string $propertyName): self - { - $cascades = implode(', ', array_map(static fn (string $e): string => "'" . $e . "'", $cascades)); - - return new self(sprintf( - "You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', and 'detach'", - $className, - $propertyName, - $cascades, - )); - } - - public static function missingSequenceName(string $className): self - { - return new self( - sprintf('Missing "sequenceName" attribute for sequence id generator definition on class "%s".', $className), - ); - } - - public static function infiniteEmbeddableNesting(string $className, string $propertyName): self - { - return new self( - sprintf( - 'Infinite nesting detected for embedded property %s::%s. ' . - 'You cannot embed an embeddable from the same type inside an embeddable.', - $className, - $propertyName, - ), - ); - } - - public static function illegalOverrideOfInheritedProperty(string $className, string $propertyName, string $inheritFromClass): self - { - return new self( - sprintf( - 'Overrides are only allowed for fields or associations declared in mapped superclasses or traits. This is not the case for %s::%s, which was inherited from %s.', - $className, - $propertyName, - $inheritFromClass, - ), - ); - } - - public static function invalidIndexConfiguration(string $className, string $indexName): self - { - return new self( - sprintf( - 'Index %s for entity %s should contain columns or fields values, but not both.', - $indexName, - $className, - ), - ); - } - - public static function invalidUniqueConstraintConfiguration(string $className, string $indexName): self - { - return new self( - sprintf( - 'Unique constraint %s for entity %s should contain columns or fields values, but not both.', - $indexName, - $className, - ), - ); - } - - public static function invalidOverrideType(string $expectdType, mixed $givenValue): self - { - return new self(sprintf( - 'Expected %s, but %s was given.', - $expectdType, - get_debug_type($givenValue), - )); - } - - public static function backedEnumTypeRequired(string $className, string $fieldName, string $enumType): self - { - return new self(sprintf( - 'Attempting to map a non-backed enum type %s in entity %s::$%s. Please use backed enums only', - $enumType, - $className, - $fieldName, - )); - } - - public static function nonEnumTypeMapped(string $className, string $fieldName, string $enumType): self - { - return new self(sprintf( - 'Attempting to map non-enum type %s as enum in entity %s::$%s', - $enumType, - $className, - $fieldName, - )); - } - - /** - * @param class-string $className - * @param class-string $enumType - */ - public static function invalidEnumValue( - string $className, - string $fieldName, - string $value, - string $enumType, - ValueError $previous, - ): self { - return new self(sprintf( - <<<'EXCEPTION' -Context: Trying to hydrate enum property "%s::$%s" -Problem: Case "%s" is not listed in enum "%s" -Solution: Either add the case to the enum type or migrate the database column to use another case of the enum -EXCEPTION - , - $className, - $fieldName, - $value, - $enumType, - ), 0, $previous); - } - - /** @param LibXMLError[] $errors */ - public static function fromLibXmlErrors(array $errors): self - { - $formatter = static fn (LibXMLError $error): string => sprintf( - 'libxml error: %s in %s at line %d', - $error->message, - $error->file, - $error->line, - ); - - return new self(implode(PHP_EOL, array_map($formatter, $errors))); - } - - public static function invalidAttributeOnEmbeddable(string $entityName, string $attributeName): self - { - return new self(sprintf( - 'Attribute "%s" on embeddable "%s" is not allowed.', - $attributeName, - $entityName, - )); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/NamingStrategy.php b/vendor/doctrine/orm/src/Mapping/NamingStrategy.php deleted file mode 100644 index afedebe..0000000 --- a/vendor/doctrine/orm/src/Mapping/NamingStrategy.php +++ /dev/null @@ -1,71 +0,0 @@ -, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): static - { - $mapping = parent::fromMappingArray($mappingArray); - - if ($mapping->orphanRemoval && ! $mapping->isCascadeRemove()) { - $mapping->cascade[] = 'remove'; - } - - return $mapping; - } - - /** - * @param mixed[] $mappingArray - * @psalm-param array{ - * fieldName: string, - * sourceEntity: class-string, - * targetEntity: class-string, - * cascade?: list<'persist'|'remove'|'detach'|'refresh'|'all'>, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * } $mappingArray - */ - public static function fromMappingArrayAndName(array $mappingArray, string $name): static - { - $mapping = self::fromMappingArray($mappingArray); - - // OneToMany-side MUST be inverse (must have mappedBy) - if (! isset($mapping->mappedBy)) { - throw MappingException::oneToManyRequiresMappedBy($name, $mapping->fieldName); - } - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/OneToOne.php b/vendor/doctrine/orm/src/Mapping/OneToOne.php deleted file mode 100644 index 1ddf21c..0000000 --- a/vendor/doctrine/orm/src/Mapping/OneToOne.php +++ /dev/null @@ -1,26 +0,0 @@ -|null $cascade - * @psalm-param 'LAZY'|'EAGER'|'EXTRA_LAZY' $fetch - */ - public function __construct( - public readonly string|null $targetEntity = null, - public readonly string|null $mappedBy = null, - public readonly string|null $inversedBy = null, - public readonly array|null $cascade = null, - public readonly string $fetch = 'LAZY', - public readonly bool $orphanRemoval = false, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/OneToOneAssociationMapping.php b/vendor/doctrine/orm/src/Mapping/OneToOneAssociationMapping.php deleted file mode 100644 index 89c6483..0000000 --- a/vendor/doctrine/orm/src/Mapping/OneToOneAssociationMapping.php +++ /dev/null @@ -1,9 +0,0 @@ - $value */ - public function __construct( - public readonly array $value, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/OwningSideMapping.php b/vendor/doctrine/orm/src/Mapping/OwningSideMapping.php deleted file mode 100644 index ab8b7b2..0000000 --- a/vendor/doctrine/orm/src/Mapping/OwningSideMapping.php +++ /dev/null @@ -1,28 +0,0 @@ - */ - public function __sleep(): array - { - $serialized = parent::__sleep(); - - if ($this->inversedBy !== null) { - $serialized[] = 'inversedBy'; - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/PostLoad.php b/vendor/doctrine/orm/src/Mapping/PostLoad.php deleted file mode 100644 index 9ce1e5c..0000000 --- a/vendor/doctrine/orm/src/Mapping/PostLoad.php +++ /dev/null @@ -1,12 +0,0 @@ - - */ - public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform): array; - - /** - * Gets the column alias. - */ - public function getColumnAlias( - string $columnName, - int $counter, - AbstractPlatform $platform, - ClassMetadata|null $class = null, - ): string; -} diff --git a/vendor/doctrine/orm/src/Mapping/ReflectionEmbeddedProperty.php b/vendor/doctrine/orm/src/Mapping/ReflectionEmbeddedProperty.php deleted file mode 100644 index da3d097..0000000 --- a/vendor/doctrine/orm/src/Mapping/ReflectionEmbeddedProperty.php +++ /dev/null @@ -1,61 +0,0 @@ -getDeclaringClass()->name, $childProperty->getName()); - } - - public function getValue(object|null $object = null): mixed - { - $embeddedObject = $this->parentProperty->getValue($object); - - if ($embeddedObject === null) { - return null; - } - - return $this->childProperty->getValue($embeddedObject); - } - - public function setValue(mixed $object, mixed $value = null): void - { - $embeddedObject = $this->parentProperty->getValue($object); - - if ($embeddedObject === null) { - $this->instantiator ??= new Instantiator(); - - $embeddedObject = $this->instantiator->instantiate($this->embeddedClass); - - $this->parentProperty->setValue($object, $embeddedObject); - } - - $this->childProperty->setValue($embeddedObject, $value); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ReflectionEnumProperty.php b/vendor/doctrine/orm/src/Mapping/ReflectionEnumProperty.php deleted file mode 100644 index 0ebd978..0000000 --- a/vendor/doctrine/orm/src/Mapping/ReflectionEnumProperty.php +++ /dev/null @@ -1,87 +0,0 @@ - $enumType */ - public function __construct( - private readonly ReflectionProperty $originalReflectionProperty, - private readonly string $enumType, - ) { - parent::__construct( - $originalReflectionProperty->class, - $originalReflectionProperty->name, - ); - } - - public function getValue(object|null $object = null): int|string|array|null - { - if ($object === null) { - return null; - } - - $enum = $this->originalReflectionProperty->getValue($object); - - if ($enum === null) { - return null; - } - - if (is_array($enum)) { - return array_map( - static fn (BackedEnum $item): int|string => $item->value, - $enum, - ); - } - - return $enum->value; - } - - /** - * @param object $object - * @param int|string|int[]|string[]|BackedEnum|BackedEnum[]|null $value - */ - public function setValue(mixed $object, mixed $value = null): void - { - if ($value !== null) { - if (is_array($value)) { - $value = array_map(fn (int|string|BackedEnum $item): BackedEnum => $this->initializeEnumValue($object, $item), $value); - } else { - $value = $this->initializeEnumValue($object, $value); - } - } - - $this->originalReflectionProperty->setValue($object, $value); - } - - private function initializeEnumValue(object $object, int|string|BackedEnum $value): BackedEnum - { - if ($value instanceof BackedEnum) { - return $value; - } - - $enumType = $this->enumType; - - try { - return $enumType::from($value); - } catch (ValueError $e) { - throw MappingException::invalidEnumValue( - $object::class, - $this->originalReflectionProperty->name, - (string) $value, - $enumType, - $e, - ); - } - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ReflectionReadonlyProperty.php b/vendor/doctrine/orm/src/Mapping/ReflectionReadonlyProperty.php deleted file mode 100644 index 13e9f6d..0000000 --- a/vendor/doctrine/orm/src/Mapping/ReflectionReadonlyProperty.php +++ /dev/null @@ -1,49 +0,0 @@ -isReadOnly()) { - throw new InvalidArgumentException('Given property is not readonly.'); - } - - parent::__construct($wrappedProperty->class, $wrappedProperty->name); - } - - public function getValue(object|null $object = null): mixed - { - return $this->wrappedProperty->getValue(...func_get_args()); - } - - public function setValue(mixed $objectOrValue, mixed $value = null): void - { - if (func_num_args() < 2 || $objectOrValue === null || ! $this->isInitialized($objectOrValue)) { - $this->wrappedProperty->setValue(...func_get_args()); - - return; - } - - assert(is_object($objectOrValue)); - - if (parent::getValue($objectOrValue) !== $value) { - throw new LogicException(sprintf('Attempting to change readonly property %s::$%s.', $this->class, $this->name)); - } - } -} diff --git a/vendor/doctrine/orm/src/Mapping/SequenceGenerator.php b/vendor/doctrine/orm/src/Mapping/SequenceGenerator.php deleted file mode 100644 index 6c06e84..0000000 --- a/vendor/doctrine/orm/src/Mapping/SequenceGenerator.php +++ /dev/null @@ -1,18 +0,0 @@ -|null $indexes - * @param array|null $uniqueConstraints - * @param array $options - */ - public function __construct( - public readonly string|null $name = null, - public readonly string|null $schema = null, - public readonly array|null $indexes = null, - public readonly array|null $uniqueConstraints = null, - public readonly array $options = [], - ) { - if ($this->indexes !== null) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11357', - 'Providing the property $indexes on %s does not have any effect and will be removed in Doctrine ORM 4.0. Please use the %s attribute instead.', - self::class, - Index::class, - ); - } - - if ($this->uniqueConstraints !== null) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11357', - 'Providing the property $uniqueConstraints on %s does not have any effect and will be removed in Doctrine ORM 4.0. Please use the %s attribute instead.', - self::class, - UniqueConstraint::class, - ); - } - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ToManyAssociationMapping.php b/vendor/doctrine/orm/src/Mapping/ToManyAssociationMapping.php deleted file mode 100644 index 2e4969c..0000000 --- a/vendor/doctrine/orm/src/Mapping/ToManyAssociationMapping.php +++ /dev/null @@ -1,16 +0,0 @@ -indexBy() */ - public function isIndexed(): bool; - - public function indexBy(): string; - - /** @return array */ - public function orderBy(): array; -} diff --git a/vendor/doctrine/orm/src/Mapping/ToManyAssociationMappingImplementation.php b/vendor/doctrine/orm/src/Mapping/ToManyAssociationMappingImplementation.php deleted file mode 100644 index 306880d..0000000 --- a/vendor/doctrine/orm/src/Mapping/ToManyAssociationMappingImplementation.php +++ /dev/null @@ -1,69 +0,0 @@ - - */ - public array $orderBy = []; - - /** @return array */ - final public function orderBy(): array - { - return $this->orderBy; - } - - /** @psalm-assert-if-true !null $this->indexBy */ - final public function isIndexed(): bool - { - return $this->indexBy !== null; - } - - final public function indexBy(): string - { - if (! $this->isIndexed()) { - throw new LogicException(sprintf( - 'This mapping is not indexed. Use %s::isIndexed() to check that before calling %s.', - self::class, - __METHOD__, - )); - } - - return $this->indexBy; - } - - /** @return list */ - public function __sleep(): array - { - $serialized = parent::__sleep(); - - if ($this->indexBy !== null) { - $serialized[] = 'indexBy'; - } - - if ($this->orderBy !== []) { - $serialized[] = 'orderBy'; - } - - return $serialized; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ToManyInverseSideMapping.php b/vendor/doctrine/orm/src/Mapping/ToManyInverseSideMapping.php deleted file mode 100644 index a092ebe..0000000 --- a/vendor/doctrine/orm/src/Mapping/ToManyInverseSideMapping.php +++ /dev/null @@ -1,10 +0,0 @@ -, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * } $mappingArray - */ - public static function fromMappingArrayAndName( - array $mappingArray, - string $name, - ): static { - $mapping = static::fromMappingArray($mappingArray); - - if (isset($mapping->id) && $mapping->id === true) { - throw MappingException::illegalInverseIdentifierAssociation($name, $mapping->fieldName); - } - - if ($mapping->orphanRemoval) { - if (! $mapping->isCascadeRemove()) { - $mapping->cascade[] = 'remove'; - } - - $mapping->unique = null; - } - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/ToOneOwningSideMapping.php b/vendor/doctrine/orm/src/Mapping/ToOneOwningSideMapping.php deleted file mode 100644 index cb85afb..0000000 --- a/vendor/doctrine/orm/src/Mapping/ToOneOwningSideMapping.php +++ /dev/null @@ -1,212 +0,0 @@ - */ - public array $sourceToTargetKeyColumns = []; - - /** @var array */ - public array $targetToSourceKeyColumns = []; - - /** @var list */ - public array $joinColumns = []; - - /** @var array */ - public array $joinColumnFieldNames = []; - - /** - * @param array $mappingArray - * @psalm-param array{ - * fieldName: string, - * sourceEntity: class-string, - * targetEntity: class-string, - * cascade?: list<'persist'|'remove'|'detach'|'refresh'|'all'>, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * joinColumns?: mixed[]|null, - * } $mappingArray - */ - public static function fromMappingArray(array $mappingArray): static - { - $joinColumns = $mappingArray['joinColumns'] ?? []; - unset($mappingArray['joinColumns']); - - $instance = parent::fromMappingArray($mappingArray); - assert($instance->isToOneOwningSide()); - - foreach ($joinColumns as $column) { - $instance->joinColumns[] = JoinColumnMapping::fromMappingArray($column); - } - - if ($instance->orphanRemoval) { - if (! $instance->isCascadeRemove()) { - $instance->cascade[] = 'remove'; - } - - $instance->unique = null; - } - - return $instance; - } - - /** - * @param mixed[] $mappingArray - * @param class-string $name - * @psalm-param array{ - * fieldName: string, - * sourceEntity: class-string, - * targetEntity: class-string, - * cascade?: list<'persist'|'remove'|'detach'|'refresh'|'all'>, - * fetch?: ClassMetadata::FETCH_*|null, - * inherited?: class-string|null, - * declared?: class-string|null, - * cache?: array|null, - * id?: bool|null, - * isOnDeleteCascade?: bool|null, - * originalClass?: class-string|null, - * originalField?: string|null, - * orphanRemoval?: bool, - * unique?: bool|null, - * joinTable?: mixed[]|null, - * type?: int, - * isOwningSide: bool, - * joinColumns?: mixed[]|null, - * } $mappingArray - */ - public static function fromMappingArrayAndName( - array $mappingArray, - NamingStrategy $namingStrategy, - string $name, - array|null $table, - bool $isInheritanceTypeSingleTable, - ): static { - if (isset($mappingArray['joinColumns'])) { - foreach ($mappingArray['joinColumns'] as $index => $joinColumn) { - if (empty($joinColumn['name'])) { - $mappingArray['joinColumns'][$index]['name'] = $namingStrategy->joinColumnName($mappingArray['fieldName'], $name); - } - } - } - - $mapping = static::fromMappingArray($mappingArray); - - assert($mapping->isToOneOwningSide()); - if (empty($mapping->joinColumns)) { - // Apply default join column - $mapping->joinColumns = [ - JoinColumnMapping::fromMappingArray([ - 'name' => $namingStrategy->joinColumnName($mapping->fieldName, $name), - 'referencedColumnName' => $namingStrategy->referenceColumnName(), - ]), - ]; - } - - $uniqueConstraintColumns = []; - - foreach ($mapping->joinColumns as $joinColumn) { - if ($mapping->isOneToOne() && ! $isInheritanceTypeSingleTable) { - if (count($mapping->joinColumns) === 1) { - if (empty($mapping->id)) { - $joinColumn->unique = true; - } - } else { - $uniqueConstraintColumns[] = $joinColumn->name; - } - } - - if (empty($joinColumn->referencedColumnName)) { - $joinColumn->referencedColumnName = $namingStrategy->referenceColumnName(); - } - - if ($joinColumn->name[0] === '`') { - $joinColumn->name = trim($joinColumn->name, '`'); - $joinColumn->quoted = true; - } - - if ($joinColumn->referencedColumnName[0] === '`') { - $joinColumn->referencedColumnName = trim($joinColumn->referencedColumnName, '`'); - $joinColumn->quoted = true; - } - - $mapping->sourceToTargetKeyColumns[$joinColumn->name] = $joinColumn->referencedColumnName; - $mapping->joinColumnFieldNames[$joinColumn->name] = $joinColumn->fieldName ?? $joinColumn->name; - } - - if ($uniqueConstraintColumns) { - if (! $table) { - throw new RuntimeException('ClassMetadata::setTable() has to be called before defining a one to one relationship.'); - } - - $table['uniqueConstraints'][$mapping->fieldName . '_uniq'] = ['columns' => $uniqueConstraintColumns]; - } - - $mapping->targetToSourceKeyColumns = array_flip($mapping->sourceToTargetKeyColumns); - - return $mapping; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if ($offset === 'joinColumns') { - $joinColumns = []; - foreach ($value as $column) { - $joinColumns[] = JoinColumnMapping::fromMappingArray($column); - } - - $this->joinColumns = $joinColumns; - - return; - } - - parent::offsetSet($offset, $value); - } - - /** @return array */ - public function toArray(): array - { - $array = parent::toArray(); - - $joinColumns = []; - foreach ($array['joinColumns'] as $column) { - $joinColumns[] = (array) $column; - } - - $array['joinColumns'] = $joinColumns; - - return $array; - } - - /** @return list */ - public function __sleep(): array - { - return [ - ...parent::__sleep(), - 'joinColumns', - 'joinColumnFieldNames', - 'sourceToTargetKeyColumns', - 'targetToSourceKeyColumns', - ]; - } -} diff --git a/vendor/doctrine/orm/src/Mapping/TypedFieldMapper.php b/vendor/doctrine/orm/src/Mapping/TypedFieldMapper.php deleted file mode 100644 index 2db9e90..0000000 --- a/vendor/doctrine/orm/src/Mapping/TypedFieldMapper.php +++ /dev/null @@ -1,20 +0,0 @@ -, type?: string} $mapping The field mapping to validate & complete. - * - * @return array{fieldName: string, enumType?: class-string, type?: string} The updated mapping. - */ - public function validateAndComplete(array $mapping, ReflectionProperty $field): array; -} diff --git a/vendor/doctrine/orm/src/Mapping/UnderscoreNamingStrategy.php b/vendor/doctrine/orm/src/Mapping/UnderscoreNamingStrategy.php deleted file mode 100644 index cedc150..0000000 --- a/vendor/doctrine/orm/src/Mapping/UnderscoreNamingStrategy.php +++ /dev/null @@ -1,108 +0,0 @@ -case; - } - - /** - * Sets string case CASE_LOWER | CASE_UPPER. - * Alphabetic characters converted to lowercase or uppercase. - */ - public function setCase(int $case): void - { - $this->case = $case; - } - - public function classToTableName(string $className): string - { - if (str_contains($className, '\\')) { - $className = substr($className, strrpos($className, '\\') + 1); - } - - return $this->underscore($className); - } - - public function propertyToColumnName(string $propertyName, string $className): string - { - return $this->underscore($propertyName); - } - - public function embeddedFieldToColumnName( - string $propertyName, - string $embeddedColumnName, - string $className, - string $embeddedClassName, - ): string { - return $this->underscore($propertyName) . '_' . $embeddedColumnName; - } - - public function referenceColumnName(): string - { - return $this->case === CASE_UPPER ? 'ID' : 'id'; - } - - public function joinColumnName(string $propertyName, string $className): string - { - return $this->underscore($propertyName) . '_' . $this->referenceColumnName(); - } - - public function joinTableName( - string $sourceEntity, - string $targetEntity, - string $propertyName, - ): string { - return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity); - } - - public function joinKeyColumnName( - string $entityName, - string|null $referencedColumnName, - ): string { - return $this->classToTableName($entityName) . '_' . - ($referencedColumnName ?: $this->referenceColumnName()); - } - - private function underscore(string $string): string - { - $string = preg_replace('/(?<=[a-z0-9])([A-Z])/', '_$1', $string); - - if ($this->case === CASE_UPPER) { - return strtoupper($string); - } - - return strtolower($string); - } -} diff --git a/vendor/doctrine/orm/src/Mapping/UniqueConstraint.php b/vendor/doctrine/orm/src/Mapping/UniqueConstraint.php deleted file mode 100644 index 3180be0..0000000 --- a/vendor/doctrine/orm/src/Mapping/UniqueConstraint.php +++ /dev/null @@ -1,24 +0,0 @@ -|null $columns - * @param array|null $fields - * @param array|null $options - */ - public function __construct( - public readonly string|null $name = null, - public readonly array|null $columns = null, - public readonly array|null $fields = null, - public readonly array|null $options = null, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Mapping/Version.php b/vendor/doctrine/orm/src/Mapping/Version.php deleted file mode 100644 index 7252e05..0000000 --- a/vendor/doctrine/orm/src/Mapping/Version.php +++ /dev/null @@ -1,12 +0,0 @@ -sql = $sql; - - return $this; - } - - public function getSQL(): string - { - return $this->sql; - } - - protected function _doExecute(): Result|int - { - $parameters = []; - $types = []; - - foreach ($this->getParameters() as $parameter) { - $name = $parameter->getName(); - $value = $this->processParameterValue($parameter->getValue()); - $type = $parameter->getValue() === $value - ? $parameter->getType() - : ParameterTypeInferer::inferType($value); - - $parameters[$name] = $value; - $types[$name] = $type; - } - - if ($parameters && is_int(key($parameters))) { - ksort($parameters); - ksort($types); - - $parameters = array_values($parameters); - $types = array_values($types); - } - - return $this->em->getConnection()->executeQuery( - $this->sql, - $parameters, - $types, - $this->queryCacheProfile, - ); - } -} diff --git a/vendor/doctrine/orm/src/NoResultException.php b/vendor/doctrine/orm/src/NoResultException.php deleted file mode 100644 index 6ecabae..0000000 --- a/vendor/doctrine/orm/src/NoResultException.php +++ /dev/null @@ -1,16 +0,0 @@ - $newEntitiesWithAssociations */ - public static function newEntitiesFoundThroughRelationships(array $newEntitiesWithAssociations): self - { - $errorMessages = array_map( - static function (array $newEntityWithAssociation): string { - [$associationMapping, $entity] = $newEntityWithAssociation; - - return self::newEntityFoundThroughRelationshipMessage($associationMapping, $entity); - }, - $newEntitiesWithAssociations, - ); - - if (count($errorMessages) === 1) { - return new self(reset($errorMessages)); - } - - return new self( - 'Multiple non-persisted new entities were found through the given association graph:' - . "\n\n * " - . implode("\n * ", $errorMessages), - ); - } - - public static function newEntityFoundThroughRelationship(AssociationMapping $associationMapping, object $entry): self - { - return new self(self::newEntityFoundThroughRelationshipMessage($associationMapping, $entry)); - } - - public static function detachedEntityFoundThroughRelationship(AssociationMapping $assoc, object $entry): self - { - return new self('A detached entity of type ' . $assoc->targetEntity . ' (' . self::objToStr($entry) . ') ' - . " was found through the relationship '" . $assoc->sourceEntity . '#' . $assoc->fieldName . "' " - . 'during cascading a persist operation.'); - } - - public static function entityNotManaged(object $entity): self - { - return new self('Entity ' . self::objToStr($entity) . ' is not managed. An entity is managed if its fetched ' . - 'from the database or registered as new through EntityManager#persist'); - } - - public static function entityHasNoIdentity(object $entity, string $operation): self - { - return new self('Entity has no identity, therefore ' . $operation . ' cannot be performed. ' . self::objToStr($entity)); - } - - public static function entityIsRemoved(object $entity, string $operation): self - { - return new self('Entity is removed, therefore ' . $operation . ' cannot be performed. ' . self::objToStr($entity)); - } - - public static function detachedEntityCannot(object $entity, string $operation): self - { - return new self('Detached entity ' . self::objToStr($entity) . ' cannot be ' . $operation); - } - - public static function invalidObject(string $context, mixed $given, int $parameterIndex = 1): self - { - return new self($context . ' expects parameter ' . $parameterIndex . - ' to be an entity object, ' . gettype($given) . ' given.'); - } - - public static function invalidCompositeIdentifier(): self - { - return new self('Binding an entity with a composite primary key to a query is not supported. ' . - 'You should split the parameter into the explicit fields and bind them separately.'); - } - - public static function invalidIdentifierBindingEntity(string $class): self - { - return new self(sprintf( - <<<'EXCEPTION' -Binding entities to query parameters only allowed for entities that have an identifier. -Class "%s" does not have an identifier. -EXCEPTION - , - $class, - )); - } - - public static function invalidAssociation(ClassMetadata $targetClass, AssociationMapping $assoc, mixed $actualValue): self - { - $expectedType = $targetClass->getName(); - - return new self(sprintf( - 'Expected value of type "%s" for association field "%s#$%s", got "%s" instead.', - $expectedType, - $assoc->sourceEntity, - $assoc->fieldName, - get_debug_type($actualValue), - )); - } - - public static function invalidAutoGenerateMode(mixed $value): self - { - return new self(sprintf('Invalid auto generate mode "%s" given.', is_scalar($value) ? (string) $value : get_debug_type($value))); - } - - public static function missingPrimaryKeyValue(string $className, string $idField): self - { - return new self(sprintf('Missing value for primary key %s on %s', $idField, $className)); - } - - public static function proxyDirectoryRequired(): self - { - return new self('You must configure a proxy directory. See docs for details'); - } - - public static function proxyNamespaceRequired(): self - { - return new self('You must configure a proxy namespace'); - } - - public static function proxyDirectoryNotWritable(string $proxyDirectory): self - { - return new self(sprintf('Your proxy directory "%s" must be writable', $proxyDirectory)); - } - - /** - * Helper method to show an object as string. - */ - private static function objToStr(object $obj): string - { - return $obj instanceof Stringable ? (string) $obj : get_debug_type($obj) . '@' . spl_object_id($obj); - } - - private static function newEntityFoundThroughRelationshipMessage(AssociationMapping $associationMapping, object $entity): string - { - return 'A new entity was found through the relationship \'' - . $associationMapping->sourceEntity . '#' . $associationMapping->fieldName . '\' that was not' - . ' configured to cascade persist operations for entity: ' . self::objToStr($entity) . '.' - . ' To solve this issue: Either explicitly call EntityManager#persist()' - . ' on this unknown entity or configure cascade persist' - . ' this association in the mapping for example @ManyToOne(..,cascade={"persist"}).' - . ($entity instanceof Stringable - ? '' - : ' If you cannot find out which entity causes the problem implement \'' - . $associationMapping->targetEntity . '#__toString()\' to get a clue.' - ); - } -} diff --git a/vendor/doctrine/orm/src/ORMSetup.php b/vendor/doctrine/orm/src/ORMSetup.php deleted file mode 100644 index 7354c71..0000000 --- a/vendor/doctrine/orm/src/ORMSetup.php +++ /dev/null @@ -1,127 +0,0 @@ -setMetadataDriverImpl(new AttributeDriver($paths)); - - return $config; - } - - /** - * Creates a configuration with an XML metadata driver. - * - * @param string[] $paths - */ - public static function createXMLMetadataConfiguration( - array $paths, - bool $isDevMode = false, - string|null $proxyDir = null, - CacheItemPoolInterface|null $cache = null, - bool $isXsdValidationEnabled = true, - ): Configuration { - $config = self::createConfiguration($isDevMode, $proxyDir, $cache); - $config->setMetadataDriverImpl(new XmlDriver($paths, XmlDriver::DEFAULT_FILE_EXTENSION, $isXsdValidationEnabled)); - - return $config; - } - - /** - * Creates a configuration without a metadata driver. - */ - public static function createConfiguration( - bool $isDevMode = false, - string|null $proxyDir = null, - CacheItemPoolInterface|null $cache = null, - ): Configuration { - $proxyDir = $proxyDir ?: sys_get_temp_dir(); - - $cache = self::createCacheInstance($isDevMode, $proxyDir, $cache); - - $config = new Configuration(); - - $config->setMetadataCache($cache); - $config->setQueryCache($cache); - $config->setResultCache($cache); - $config->setProxyDir($proxyDir); - $config->setProxyNamespace('DoctrineProxies'); - $config->setAutoGenerateProxyClasses($isDevMode); - - return $config; - } - - private static function createCacheInstance( - bool $isDevMode, - string $proxyDir, - CacheItemPoolInterface|null $cache, - ): CacheItemPoolInterface { - if ($cache !== null) { - return $cache; - } - - if (! class_exists(ArrayAdapter::class)) { - throw new RuntimeException( - 'The Doctrine setup tool cannot configure caches without symfony/cache.' - . ' Please add symfony/cache as explicit dependency or pass your own cache implementation.', - ); - } - - if ($isDevMode) { - return new ArrayAdapter(); - } - - $namespace = 'dc2_' . md5($proxyDir); - - if (extension_loaded('apcu') && apcu_enabled()) { - return new ApcuAdapter($namespace); - } - - if (MemcachedAdapter::isSupported()) { - return new MemcachedAdapter(MemcachedAdapter::createConnection('memcached://127.0.0.1'), $namespace); - } - - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1'); - - return new RedisAdapter($redis, $namespace); - } - - return new ArrayAdapter(); - } - - private function __construct() - { - } -} diff --git a/vendor/doctrine/orm/src/OptimisticLockException.php b/vendor/doctrine/orm/src/OptimisticLockException.php deleted file mode 100644 index f84e134..0000000 --- a/vendor/doctrine/orm/src/OptimisticLockException.php +++ /dev/null @@ -1,55 +0,0 @@ -entity; - } - - /** @param object|class-string $entity */ - public static function lockFailed(object|string $entity): self - { - return new self('The optimistic lock on an entity failed.', $entity); - } - - public static function lockFailedVersionMismatch( - object $entity, - int|string|DateTimeInterface $expectedLockVersion, - int|string|DateTimeInterface $actualLockVersion, - ): self { - $expectedLockVersion = $expectedLockVersion instanceof DateTimeInterface ? $expectedLockVersion->getTimestamp() : $expectedLockVersion; - $actualLockVersion = $actualLockVersion instanceof DateTimeInterface ? $actualLockVersion->getTimestamp() : $actualLockVersion; - - return new self('The optimistic lock failed, version ' . $expectedLockVersion . ' was expected, but is actually ' . $actualLockVersion, $entity); - } - - public static function notVersioned(string $entityName): self - { - return new self('Cannot obtain optimistic lock on unversioned entity ' . $entityName, null); - } -} diff --git a/vendor/doctrine/orm/src/PersistentCollection.php b/vendor/doctrine/orm/src/PersistentCollection.php deleted file mode 100644 index d54d3d1..0000000 --- a/vendor/doctrine/orm/src/PersistentCollection.php +++ /dev/null @@ -1,652 +0,0 @@ - - * @template-implements Selectable - */ -final class PersistentCollection extends AbstractLazyCollection implements Selectable -{ - /** - * A snapshot of the collection at the moment it was fetched from the database. - * This is used to create a diff of the collection at commit time. - * - * @psalm-var array - */ - private array $snapshot = []; - - /** - * The entity that owns this collection. - */ - private object|null $owner = null; - - /** - * The association mapping the collection belongs to. - * This is currently either a OneToManyMapping or a ManyToManyMapping. - * - * @var (AssociationMapping&ToManyAssociationMapping)|null - */ - private AssociationMapping|null $association = null; - - /** - * The name of the field on the target entities that points to the owner - * of the collection. This is only set if the association is bi-directional. - */ - private string|null $backRefFieldName = null; - - /** - * Whether the collection is dirty and needs to be synchronized with the database - * when the UnitOfWork that manages its persistent state commits. - */ - private bool $isDirty = false; - - /** - * Creates a new persistent collection. - * - * @param EntityManagerInterface $em The EntityManager the collection will be associated with. - * @param ClassMetadata $typeClass The class descriptor of the entity type of this collection. - * @psalm-param Collection&Selectable $collection The collection elements. - */ - public function __construct( - private EntityManagerInterface|null $em, - private readonly ClassMetadata|null $typeClass, - Collection $collection, - ) { - $this->collection = $collection; - $this->initialized = true; - } - - /** - * INTERNAL: - * Sets the collection's owning entity together with the AssociationMapping that - * describes the association between the owner and the elements of the collection. - */ - public function setOwner(object $entity, AssociationMapping&ToManyAssociationMapping $assoc): void - { - $this->owner = $entity; - $this->association = $assoc; - $this->backRefFieldName = $assoc->isOwningSide() ? $assoc->inversedBy : $assoc->mappedBy; - } - - /** - * INTERNAL: - * Gets the collection owner. - */ - public function getOwner(): object|null - { - return $this->owner; - } - - public function getTypeClass(): ClassMetadata - { - assert($this->typeClass !== null); - - return $this->typeClass; - } - - private function getUnitOfWork(): UnitOfWork - { - assert($this->em !== null); - - return $this->em->getUnitOfWork(); - } - - /** - * INTERNAL: - * Adds an element to a collection during hydration. This will automatically - * complete bidirectional associations in the case of a one-to-many association. - */ - public function hydrateAdd(mixed $element): void - { - $this->unwrap()->add($element); - - // If _backRefFieldName is set and its a one-to-many association, - // we need to set the back reference. - if ($this->backRefFieldName && $this->getMapping()->isOneToMany()) { - assert($this->typeClass !== null); - // Set back reference to owner - $this->typeClass->reflFields[$this->backRefFieldName]->setValue( - $element, - $this->owner, - ); - - $this->getUnitOfWork()->setOriginalEntityProperty( - spl_object_id($element), - $this->backRefFieldName, - $this->owner, - ); - } - } - - /** - * INTERNAL: - * Sets a keyed element in the collection during hydration. - */ - public function hydrateSet(mixed $key, mixed $element): void - { - $this->unwrap()->set($key, $element); - - // If _backRefFieldName is set, then the association is bidirectional - // and we need to set the back reference. - if ($this->backRefFieldName && $this->getMapping()->isOneToMany()) { - assert($this->typeClass !== null); - // Set back reference to owner - $this->typeClass->reflFields[$this->backRefFieldName]->setValue( - $element, - $this->owner, - ); - } - } - - /** - * Initializes the collection by loading its contents from the database - * if the collection is not yet initialized. - */ - public function initialize(): void - { - if ($this->initialized || ! $this->association) { - return; - } - - $this->doInitialize(); - - $this->initialized = true; - } - - /** - * INTERNAL: - * Tells this collection to take a snapshot of its current state. - */ - public function takeSnapshot(): void - { - $this->snapshot = $this->unwrap()->toArray(); - $this->isDirty = false; - } - - /** - * INTERNAL: - * Returns the last snapshot of the elements in the collection. - * - * @psalm-return array The last snapshot of the elements. - */ - public function getSnapshot(): array - { - return $this->snapshot; - } - - /** - * INTERNAL: - * getDeleteDiff - * - * @return mixed[] - */ - public function getDeleteDiff(): array - { - $collectionItems = $this->unwrap()->toArray(); - - return array_values(array_diff_key( - array_combine(array_map('spl_object_id', $this->snapshot), $this->snapshot), - array_combine(array_map('spl_object_id', $collectionItems), $collectionItems), - )); - } - - /** - * INTERNAL: - * getInsertDiff - * - * @return mixed[] - */ - public function getInsertDiff(): array - { - $collectionItems = $this->unwrap()->toArray(); - - return array_values(array_diff_key( - array_combine(array_map('spl_object_id', $collectionItems), $collectionItems), - array_combine(array_map('spl_object_id', $this->snapshot), $this->snapshot), - )); - } - - /** INTERNAL: Gets the association mapping of the collection. */ - public function getMapping(): AssociationMapping&ToManyAssociationMapping - { - if ($this->association === null) { - throw new UnexpectedValueException('The underlying association mapping is null although it should not be'); - } - - return $this->association; - } - - /** - * Marks this collection as changed/dirty. - */ - private function changed(): void - { - if ($this->isDirty) { - return; - } - - $this->isDirty = true; - } - - /** - * Gets a boolean flag indicating whether this collection is dirty which means - * its state needs to be synchronized with the database. - */ - public function isDirty(): bool - { - return $this->isDirty; - } - - /** - * Sets a boolean flag, indicating whether this collection is dirty. - */ - public function setDirty(bool $dirty): void - { - $this->isDirty = $dirty; - } - - /** - * Sets the initialized flag of the collection, forcing it into that state. - */ - public function setInitialized(bool $bool): void - { - $this->initialized = $bool; - } - - public function remove(string|int $key): mixed - { - // TODO: If the keys are persistent as well (not yet implemented) - // and the collection is not initialized and orphanRemoval is - // not used we can issue a straight SQL delete/update on the - // association (table). Without initializing the collection. - $removed = parent::remove($key); - - if (! $removed) { - return $removed; - } - - $this->changed(); - - if ( - $this->association !== null && - $this->association->isToMany() && - $this->owner && - $this->getMapping()->orphanRemoval - ) { - $this->getUnitOfWork()->scheduleOrphanRemoval($removed); - } - - return $removed; - } - - public function removeElement(mixed $element): bool - { - $removed = parent::removeElement($element); - - if (! $removed) { - return $removed; - } - - $this->changed(); - - if ( - $this->association !== null && - $this->association->isToMany() && - $this->owner && - $this->getMapping()->orphanRemoval - ) { - $this->getUnitOfWork()->scheduleOrphanRemoval($element); - } - - return $removed; - } - - public function containsKey(mixed $key): bool - { - if ( - ! $this->initialized && $this->getMapping()->fetch === ClassMetadata::FETCH_EXTRA_LAZY - && isset($this->getMapping()->indexBy) - ) { - $persister = $this->getUnitOfWork()->getCollectionPersister($this->getMapping()); - - return $this->unwrap()->containsKey($key) || $persister->containsKey($this, $key); - } - - return parent::containsKey($key); - } - - public function contains(mixed $element): bool - { - if (! $this->initialized && $this->getMapping()->fetch === ClassMetadata::FETCH_EXTRA_LAZY) { - $persister = $this->getUnitOfWork()->getCollectionPersister($this->getMapping()); - - return $this->unwrap()->contains($element) || $persister->contains($this, $element); - } - - return parent::contains($element); - } - - public function get(string|int $key): mixed - { - if ( - ! $this->initialized - && $this->getMapping()->fetch === ClassMetadata::FETCH_EXTRA_LAZY - && isset($this->getMapping()->indexBy) - ) { - assert($this->em !== null); - assert($this->typeClass !== null); - if (! $this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->getMapping()->indexBy)) { - return $this->em->find($this->typeClass->name, $key); - } - - return $this->getUnitOfWork()->getCollectionPersister($this->getMapping())->get($this, $key); - } - - return parent::get($key); - } - - public function count(): int - { - if (! $this->initialized && $this->association !== null && $this->getMapping()->fetch === ClassMetadata::FETCH_EXTRA_LAZY) { - $persister = $this->getUnitOfWork()->getCollectionPersister($this->association); - - return $persister->count($this) + ($this->isDirty ? $this->unwrap()->count() : 0); - } - - return parent::count(); - } - - public function set(string|int $key, mixed $value): void - { - parent::set($key, $value); - - $this->changed(); - - if (is_object($value) && $this->em) { - $this->getUnitOfWork()->cancelOrphanRemoval($value); - } - } - - public function add(mixed $value): bool - { - $this->unwrap()->add($value); - - $this->changed(); - - if (is_object($value) && $this->em) { - $this->getUnitOfWork()->cancelOrphanRemoval($value); - } - - return true; - } - - public function offsetExists(mixed $offset): bool - { - return $this->containsKey($offset); - } - - public function offsetGet(mixed $offset): mixed - { - return $this->get($offset); - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if (! isset($offset)) { - $this->add($value); - - return; - } - - $this->set($offset, $value); - } - - public function offsetUnset(mixed $offset): void - { - $this->remove($offset); - } - - public function isEmpty(): bool - { - return $this->unwrap()->isEmpty() && $this->count() === 0; - } - - public function clear(): void - { - if ($this->initialized && $this->isEmpty()) { - $this->unwrap()->clear(); - - return; - } - - $uow = $this->getUnitOfWork(); - $association = $this->getMapping(); - - if ( - $association->isToMany() && - $association->orphanRemoval && - $this->owner - ) { - // we need to initialize here, as orphan removal acts like implicit cascadeRemove, - // hence for event listeners we need the objects in memory. - $this->initialize(); - - foreach ($this->unwrap() as $element) { - $uow->scheduleOrphanRemoval($element); - } - } - - $this->unwrap()->clear(); - - $this->initialized = true; // direct call, {@link initialize()} is too expensive - - if ($association->isOwningSide() && $this->owner) { - $this->changed(); - - $uow->scheduleCollectionDeletion($this); - - $this->takeSnapshot(); - } - } - - /** - * Called by PHP when this collection is serialized. Ensures that only the - * elements are properly serialized. - * - * Internal note: Tried to implement Serializable first but that did not work well - * with circular references. This solution seems simpler and works well. - * - * @return string[] - * @psalm-return array{0: string, 1: string} - */ - public function __sleep(): array - { - return ['collection', 'initialized']; - } - - public function __wakeup(): void - { - $this->em = null; - } - - /** - * Extracts a slice of $length elements starting at position $offset from the Collection. - * - * If $length is null it returns all elements from $offset to the end of the Collection. - * Keys have to be preserved by this method. Calling this method will only return the - * selected slice and NOT change the elements contained in the collection slice is called on. - * - * @return mixed[] - * @psalm-return array - */ - public function slice(int $offset, int|null $length = null): array - { - if (! $this->initialized && ! $this->isDirty && $this->getMapping()->fetch === ClassMetadata::FETCH_EXTRA_LAZY) { - $persister = $this->getUnitOfWork()->getCollectionPersister($this->getMapping()); - - return $persister->slice($this, $offset, $length); - } - - return parent::slice($offset, $length); - } - - /** - * Cleans up internal state of cloned persistent collection. - * - * The following problems have to be prevented: - * 1. Added entities are added to old PC - * 2. New collection is not dirty, if reused on other entity nothing - * changes. - * 3. Snapshot leads to invalid diffs being generated. - * 4. Lazy loading grabs entities from old owner object. - * 5. New collection is connected to old owner and leads to duplicate keys. - */ - public function __clone() - { - if (is_object($this->collection)) { - $this->collection = clone $this->collection; - } - - $this->initialize(); - - $this->owner = null; - $this->snapshot = []; - - $this->changed(); - } - - /** - * Selects all elements from a selectable that match the expression and - * return a new collection containing these elements. - * - * @psalm-return Collection - * - * @throws RuntimeException - */ - public function matching(Criteria $criteria): Collection - { - if ($this->isDirty) { - $this->initialize(); - } - - if ($this->initialized) { - return $this->unwrap()->matching($criteria); - } - - $association = $this->getMapping(); - if ($association->isManyToMany()) { - $persister = $this->getUnitOfWork()->getCollectionPersister($association); - - return new ArrayCollection($persister->loadCriteria($this, $criteria)); - } - - $builder = Criteria::expr(); - $ownerExpression = $builder->eq($this->backRefFieldName, $this->owner); - $expression = $criteria->getWhereExpression(); - $expression = $expression ? $builder->andX($expression, $ownerExpression) : $ownerExpression; - - $criteria = clone $criteria; - $criteria->where($expression); - $criteria->orderBy( - $criteria->orderings() ?: array_map( - static fn (string $order): Order => Order::from(strtoupper($order)), - $association->orderBy(), - ), - ); - - $persister = $this->getUnitOfWork()->getEntityPersister($association->targetEntity); - - return $association->fetch === ClassMetadata::FETCH_EXTRA_LAZY - ? new LazyCriteriaCollection($persister, $criteria) - : new ArrayCollection($persister->loadCriteria($criteria)); - } - - /** - * Retrieves the wrapped Collection instance. - * - * @return Collection&Selectable - */ - public function unwrap(): Selectable&Collection - { - assert($this->collection instanceof Collection); - assert($this->collection instanceof Selectable); - - return $this->collection; - } - - protected function doInitialize(): void - { - // Has NEW objects added through add(). Remember them. - $newlyAddedDirtyObjects = []; - - if ($this->isDirty) { - $newlyAddedDirtyObjects = $this->unwrap()->toArray(); - } - - $this->unwrap()->clear(); - $this->getUnitOfWork()->loadCollection($this); - $this->takeSnapshot(); - - if ($newlyAddedDirtyObjects) { - $this->restoreNewObjectsInDirtyCollection($newlyAddedDirtyObjects); - } - } - - /** - * @param object[] $newObjects - * - * Note: the only reason why this entire looping/complexity is performed via `spl_object_id` - * is because we want to prevent using `array_udiff()`, which is likely to cause very - * high overhead (complexity of O(n^2)). `array_diff_key()` performs the operation in - * core, which is faster than using a callback for comparisons - */ - private function restoreNewObjectsInDirtyCollection(array $newObjects): void - { - $loadedObjects = $this->unwrap()->toArray(); - $newObjectsByOid = array_combine(array_map('spl_object_id', $newObjects), $newObjects); - $loadedObjectsByOid = array_combine(array_map('spl_object_id', $loadedObjects), $loadedObjects); - $newObjectsThatWereNotLoaded = array_diff_key($newObjectsByOid, $loadedObjectsByOid); - - if ($newObjectsThatWereNotLoaded) { - // Reattach NEW objects added through add(), if any. - array_walk($newObjectsThatWereNotLoaded, [$this->unwrap(), 'add']); - - $this->isDirty = true; - } - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Collection/AbstractCollectionPersister.php b/vendor/doctrine/orm/src/Persisters/Collection/AbstractCollectionPersister.php deleted file mode 100644 index 26f0b9e..0000000 --- a/vendor/doctrine/orm/src/Persisters/Collection/AbstractCollectionPersister.php +++ /dev/null @@ -1,50 +0,0 @@ -uow = $em->getUnitOfWork(); - $this->conn = $em->getConnection(); - $this->platform = $this->conn->getDatabasePlatform(); - $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - } - - /** - * Check if entity is in a valid state for operations. - */ - protected function isValidEntityState(object $entity): bool - { - $entityState = $this->uow->getEntityState($entity, UnitOfWork::STATE_NEW); - - if ($entityState === UnitOfWork::STATE_NEW) { - return false; - } - - // If Entity is scheduled for inclusion, it is not in this collection. - // We can assure that because it would have return true before on array check - return ! ($entityState === UnitOfWork::STATE_MANAGED && $this->uow->isScheduledForInsert($entity)); - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Collection/CollectionPersister.php b/vendor/doctrine/orm/src/Persisters/Collection/CollectionPersister.php deleted file mode 100644 index 07c4eaf..0000000 --- a/vendor/doctrine/orm/src/Persisters/Collection/CollectionPersister.php +++ /dev/null @@ -1,59 +0,0 @@ -getMapping($collection); - - if (! $mapping->isOwningSide()) { - return; // ignore inverse side - } - - assert($mapping->isManyToManyOwningSide()); - - $types = []; - $class = $this->em->getClassMetadata($mapping->sourceEntity); - - foreach ($mapping->joinTable->joinColumns as $joinColumn) { - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $class, $this->em); - } - - $this->conn->executeStatement($this->getDeleteSQL($collection), $this->getDeleteSQLParameters($collection), $types); - } - - public function update(PersistentCollection $collection): void - { - $mapping = $this->getMapping($collection); - - if (! $mapping->isOwningSide()) { - return; // ignore inverse side - } - - [$deleteSql, $deleteTypes] = $this->getDeleteRowSQL($collection); - [$insertSql, $insertTypes] = $this->getInsertRowSQL($collection); - - foreach ($collection->getDeleteDiff() as $element) { - $this->conn->executeStatement( - $deleteSql, - $this->getDeleteRowSQLParameters($collection, $element), - $deleteTypes, - ); - } - - foreach ($collection->getInsertDiff() as $element) { - $this->conn->executeStatement( - $insertSql, - $this->getInsertRowSQLParameters($collection, $element), - $insertTypes, - ); - } - } - - public function get(PersistentCollection $collection, mixed $index): object|null - { - $mapping = $this->getMapping($collection); - - if (! $mapping->isIndexed()) { - throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); - } - - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - $mappedKey = $mapping->isOwningSide() - ? $mapping->inversedBy - : $mapping->mappedBy; - - assert($mappedKey !== null); - - return $persister->load( - [$mappedKey => $collection->getOwner(), $mapping->indexBy() => $index], - null, - $mapping, - [], - LockMode::NONE, - 1, - ); - } - - public function count(PersistentCollection $collection): int - { - $conditions = []; - $params = []; - $types = []; - $mapping = $this->getMapping($collection); - $id = $this->uow->getEntityIdentifier($collection->getOwner()); - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $association = $this->em->getMetadataFactory()->getOwningSide($mapping); - - $joinTableName = $this->quoteStrategy->getJoinTableName($association, $sourceClass, $this->platform); - $joinColumns = ! $mapping->isOwningSide() - ? $association->joinTable->inverseJoinColumns - : $association->joinTable->joinColumns; - - foreach ($joinColumns as $joinColumn) { - $columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $sourceClass, $this->platform); - $referencedName = $joinColumn->referencedColumnName; - $conditions[] = 't.' . $columnName . ' = ?'; - $params[] = $id[$sourceClass->getFieldForColumn($referencedName)]; - $types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em); - } - - [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($mapping); - - if ($filterSql) { - $conditions[] = $filterSql; - } - - // If there is a provided criteria, make part of conditions - // @todo Fix this. Current SQL returns something like: - /*if ($criteria && ($expression = $criteria->getWhereExpression()) !== null) { - // A join is needed on the target entity - $targetTableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); - $targetJoinSql = ' JOIN ' . $targetTableName . ' te' - . ' ON' . implode(' AND ', $this->getOnConditionSQL($association)); - - // And criteria conditions needs to be added - $persister = $this->uow->getEntityPersister($targetClass->name); - $visitor = new SqlExpressionVisitor($persister, $targetClass); - $conditions[] = $visitor->dispatch($expression); - - $joinTargetEntitySQL = $targetJoinSql . $joinTargetEntitySQL; - }*/ - - $sql = 'SELECT COUNT(*)' - . ' FROM ' . $joinTableName . ' t' - . $joinTargetEntitySQL - . ' WHERE ' . implode(' AND ', $conditions); - - return (int) $this->conn->fetchOne($sql, $params, $types); - } - - /** - * {@inheritDoc} - */ - public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array - { - $mapping = $this->getMapping($collection); - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - return $persister->getManyToManyCollection($mapping, $collection->getOwner(), $offset, $length); - } - - public function containsKey(PersistentCollection $collection, mixed $key): bool - { - $mapping = $this->getMapping($collection); - - if (! $mapping->isIndexed()) { - throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); - } - - [$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictionsWithKey( - $collection, - (string) $key, - true, - ); - - $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); - - return (bool) $this->conn->fetchOne($sql, $params, $types); - } - - public function contains(PersistentCollection $collection, object $element): bool - { - if (! $this->isValidEntityState($element)) { - return false; - } - - [$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictions( - $collection, - $element, - true, - ); - - $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); - - return (bool) $this->conn->fetchOne($sql, $params, $types); - } - - /** - * {@inheritDoc} - */ - public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array - { - $mapping = $this->getMapping($collection); - $owner = $collection->getOwner(); - $ownerMetadata = $this->em->getClassMetadata($owner::class); - $id = $this->uow->getEntityIdentifier($owner); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $onConditions = $this->getOnConditionSQL($mapping); - $whereClauses = $params = []; - $paramTypes = []; - - if (! $mapping->isOwningSide()) { - assert($mapping instanceof InverseSideMapping); - $associationSourceClass = $targetClass; - $sourceRelationMode = 'relationToTargetKeyColumns'; - } else { - $associationSourceClass = $ownerMetadata; - $sourceRelationMode = 'relationToSourceKeyColumns'; - } - - $mapping = $this->em->getMetadataFactory()->getOwningSide($mapping); - - foreach ($mapping->$sourceRelationMode as $key => $value) { - $whereClauses[] = sprintf('t.%s = ?', $key); - $params[] = $ownerMetadata->containsForeignIdentifier - ? $id[$ownerMetadata->getFieldForColumn($value)] - : $id[$ownerMetadata->fieldNames[$value]]; - $paramTypes[] = PersisterHelper::getTypeOfColumn($value, $ownerMetadata, $this->em); - } - - $parameters = $this->expandCriteriaParameters($criteria); - - foreach ($parameters as $parameter) { - [$name, $value, $operator] = $parameter; - - $field = $this->quoteStrategy->getColumnName($name, $targetClass, $this->platform); - - if ($value === null && ($operator === Comparison::EQ || $operator === Comparison::NEQ)) { - $whereClauses[] = sprintf('te.%s %s NULL', $field, $operator === Comparison::EQ ? 'IS' : 'IS NOT'); - } else { - $whereClauses[] = sprintf('te.%s %s ?', $field, $operator); - $params[] = $value; - $paramTypes[] = PersisterHelper::getTypeOfField($name, $targetClass, $this->em)[0]; - } - } - - $tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); - $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform); - - $rsm = new Query\ResultSetMappingBuilder($this->em); - $rsm->addRootEntityFromClassMetadata($targetClass->name, 'te'); - - $sql = 'SELECT ' . $rsm->generateSelectClause() - . ' FROM ' . $tableName . ' te' - . ' JOIN ' . $joinTable . ' t ON' - . implode(' AND ', $onConditions) - . ' WHERE ' . implode(' AND ', $whereClauses); - - $sql .= $this->getOrderingSql($criteria, $targetClass); - - $sql .= $this->getLimitSql($criteria); - - $stmt = $this->conn->executeQuery($sql, $params, $paramTypes); - - return $this - ->em - ->newHydrator(Query::HYDRATE_OBJECT) - ->hydrateAll($stmt, $rsm); - } - - /** - * Generates the filter SQL for a given mapping. - * - * This method is not used for actually grabbing the related entities - * but when the extra-lazy collection methods are called on a filtered - * association. This is why besides the many to many table we also - * have to join in the actual entities table leading to additional - * JOIN. - * - * @param AssociationMapping $mapping Array containing mapping information. - * - * @return string[] ordered tuple: - * - JOIN condition to add to the SQL - * - WHERE condition to add to the SQL - * @psalm-return array{0: string, 1: string} - */ - public function getFilterSql(AssociationMapping $mapping): array - { - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $rootClass = $this->em->getClassMetadata($targetClass->rootEntityName); - $filterSql = $this->generateFilterConditionSQL($rootClass, 'te'); - - if ($filterSql === '') { - return ['', '']; - } - - // A join is needed if there is filtering on the target entity - $tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform); - $joinSql = ' JOIN ' . $tableName . ' te' - . ' ON' . implode(' AND ', $this->getOnConditionSQL($mapping)); - - return [$joinSql, $filterSql]; - } - - /** - * Generates the filter SQL for a given entity and table alias. - * - * @param ClassMetadata $targetEntity Metadata of the target entity. - * @param string $targetTableAlias The table alias of the joined/selected table. - * - * @return string The SQL query part to add to a query. - */ - protected function generateFilterConditionSQL(ClassMetadata $targetEntity, string $targetTableAlias): string - { - $filterClauses = []; - - foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { - $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias); - if ($filterExpr) { - $filterClauses[] = '(' . $filterExpr . ')'; - } - } - - return $filterClauses - ? '(' . implode(' AND ', $filterClauses) . ')' - : ''; - } - - /** - * Generate ON condition - * - * @return string[] - * @psalm-return list - */ - protected function getOnConditionSQL(AssociationMapping $mapping): array - { - $association = $this->em->getMetadataFactory()->getOwningSide($mapping); - $joinColumns = $mapping->isOwningSide() - ? $association->joinTable->inverseJoinColumns - : $association->joinTable->joinColumns; - - $conditions = []; - - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - foreach ($joinColumns as $joinColumn) { - $joinColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $refColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - - $conditions[] = ' t.' . $joinColumnName . ' = te.' . $refColumnName; - } - - return $conditions; - } - - protected function getDeleteSQL(PersistentCollection $collection): string - { - $columns = []; - $mapping = $this->getMapping($collection); - assert($mapping->isManyToManyOwningSide()); - $class = $this->em->getClassMetadata($collection->getOwner()::class); - $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); - - foreach ($mapping->joinTable->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - - return 'DELETE FROM ' . $joinTable - . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; - } - - /** - * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql. - * - * @return list - */ - protected function getDeleteSQLParameters(PersistentCollection $collection): array - { - $mapping = $this->getMapping($collection); - assert($mapping->isManyToManyOwningSide()); - $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); - - // Optimization for single column identifier - if (count($mapping->relationToSourceKeyColumns) === 1) { - return [reset($identifier)]; - } - - // Composite identifier - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $params = []; - - foreach ($mapping->relationToSourceKeyColumns as $columnName => $refColumnName) { - $params[] = isset($sourceClass->fieldNames[$refColumnName]) - ? $identifier[$sourceClass->fieldNames[$refColumnName]] - : $identifier[$sourceClass->getFieldForColumn($refColumnName)]; - } - - return $params; - } - - /** - * Gets the SQL statement used for deleting a row from the collection. - * - * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array - * of types for bound parameters - * @psalm-return array{0: string, 1: list} - */ - protected function getDeleteRowSQL(PersistentCollection $collection): array - { - $mapping = $this->getMapping($collection); - assert($mapping->isManyToManyOwningSide()); - $class = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $columns = []; - $types = []; - - foreach ($mapping->joinTable->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $class, $this->em); - } - - foreach ($mapping->joinTable->inverseJoinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - } - - return [ - 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) - . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?', - $types, - ]; - } - - /** - * Gets the SQL parameters for the corresponding SQL statement to delete the given - * element from the given collection. - * - * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteRowSql. - * - * @return mixed[] - * @psalm-return list - */ - protected function getDeleteRowSQLParameters(PersistentCollection $collection, object $element): array - { - return $this->collectJoinTableColumnParameters($collection, $element); - } - - /** - * Gets the SQL statement used for inserting a row in the collection. - * - * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array - * of types for bound parameters - * @psalm-return array{0: string, 1: list} - */ - protected function getInsertRowSQL(PersistentCollection $collection): array - { - $columns = []; - $types = []; - $mapping = $this->getMapping($collection); - assert($mapping->isManyToManyOwningSide()); - $class = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - - foreach ($mapping->joinTable->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $class, $this->em); - } - - foreach ($mapping->joinTable->inverseJoinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - } - - return [ - 'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) - . ' (' . implode(', ', $columns) . ')' - . ' VALUES' - . ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')', - $types, - ]; - } - - /** - * Gets the SQL parameters for the corresponding SQL statement to insert the given - * element of the given collection into the database. - * - * Internal note: Order of the parameters must be the same as the order of the columns in getInsertRowSql. - * - * @return mixed[] - * @psalm-return list - */ - protected function getInsertRowSQLParameters(PersistentCollection $collection, object $element): array - { - return $this->collectJoinTableColumnParameters($collection, $element); - } - - /** - * Collects the parameters for inserting/deleting on the join table in the order - * of the join table columns as specified in ManyToManyMapping#joinTableColumns. - * - * @return mixed[] - * @psalm-return list - */ - private function collectJoinTableColumnParameters( - PersistentCollection $collection, - object $element, - ): array { - $params = []; - $mapping = $this->getMapping($collection); - assert($mapping->isManyToManyOwningSide()); - $isComposite = count($mapping->joinTableColumns) > 2; - - $identifier1 = $this->uow->getEntityIdentifier($collection->getOwner()); - $identifier2 = $this->uow->getEntityIdentifier($element); - - $class1 = $class2 = null; - if ($isComposite) { - $class1 = $this->em->getClassMetadata($collection->getOwner()::class); - $class2 = $collection->getTypeClass(); - } - - foreach ($mapping->joinTableColumns as $joinTableColumn) { - $isRelationToSource = isset($mapping->relationToSourceKeyColumns[$joinTableColumn]); - - if (! $isComposite) { - $params[] = $isRelationToSource ? array_pop($identifier1) : array_pop($identifier2); - - continue; - } - - if ($isRelationToSource) { - $params[] = $identifier1[$class1->getFieldForColumn($mapping->relationToSourceKeyColumns[$joinTableColumn])]; - - continue; - } - - $params[] = $identifier2[$class2->getFieldForColumn($mapping->relationToTargetKeyColumns[$joinTableColumn])]; - } - - return $params; - } - - /** - * @param bool $addFilters Whether the filter SQL should be included or not. - * - * @return mixed[] ordered vector: - * - quoted join table name - * - where clauses to be added for filtering - * - parameters to be bound for filtering - * - types of the parameters to be bound for filtering - * @psalm-return array{0: string, 1: list, 2: list, 3: list} - */ - private function getJoinTableRestrictionsWithKey( - PersistentCollection $collection, - string $key, - bool $addFilters, - ): array { - $filterMapping = $this->getMapping($collection); - $mapping = $filterMapping; - $indexBy = $mapping->indexBy(); - $id = $this->uow->getEntityIdentifier($collection->getOwner()); - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - - if (! $mapping->isOwningSide()) { - assert($mapping instanceof InverseSideMapping); - $associationSourceClass = $this->em->getClassMetadata($mapping->targetEntity); - $mapping = $associationSourceClass->associationMappings[$mapping->mappedBy]; - assert($mapping->isManyToManyOwningSide()); - $joinColumns = $mapping->joinTable->joinColumns; - $sourceRelationMode = 'relationToTargetKeyColumns'; - $targetRelationMode = 'relationToSourceKeyColumns'; - } else { - assert($mapping->isManyToManyOwningSide()); - $associationSourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $joinColumns = $mapping->joinTable->inverseJoinColumns; - $sourceRelationMode = 'relationToSourceKeyColumns'; - $targetRelationMode = 'relationToTargetKeyColumns'; - } - - $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform) . ' t'; - $whereClauses = []; - $params = []; - $types = []; - - $joinNeeded = ! in_array($indexBy, $targetClass->identifier, true); - - if ($joinNeeded) { // extra join needed if indexBy is not a @id - $joinConditions = []; - - foreach ($joinColumns as $joinTableColumn) { - $joinConditions[] = 't.' . $joinTableColumn->name . ' = tr.' . $joinTableColumn->referencedColumnName; - } - - $tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); - $quotedJoinTable .= ' JOIN ' . $tableName . ' tr ON ' . implode(' AND ', $joinConditions); - $columnName = $targetClass->getColumnName($indexBy); - - $whereClauses[] = 'tr.' . $columnName . ' = ?'; - $params[] = $key; - $types[] = PersisterHelper::getTypeOfColumn($columnName, $targetClass, $this->em); - } - - foreach ($mapping->joinTableColumns as $joinTableColumn) { - if (isset($mapping->{$sourceRelationMode}[$joinTableColumn])) { - $column = $mapping->{$sourceRelationMode}[$joinTableColumn]; - $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; - $params[] = $sourceClass->containsForeignIdentifier - ? $id[$sourceClass->getFieldForColumn($column)] - : $id[$sourceClass->fieldNames[$column]]; - $types[] = PersisterHelper::getTypeOfColumn($column, $sourceClass, $this->em); - } elseif (! $joinNeeded) { - $column = $mapping->{$targetRelationMode}[$joinTableColumn]; - - $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; - $params[] = $key; - $types[] = PersisterHelper::getTypeOfColumn($column, $targetClass, $this->em); - } - } - - if ($addFilters) { - [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping); - - if ($filterSql) { - $quotedJoinTable .= ' ' . $joinTargetEntitySQL; - $whereClauses[] = $filterSql; - } - } - - return [$quotedJoinTable, $whereClauses, $params, $types]; - } - - /** - * @param bool $addFilters Whether the filter SQL should be included or not. - * - * @return mixed[] ordered vector: - * - quoted join table name - * - where clauses to be added for filtering - * - parameters to be bound for filtering - * - types of the parameters to be bound for filtering - * @psalm-return array{0: string, 1: list, 2: list, 3: list} - */ - private function getJoinTableRestrictions( - PersistentCollection $collection, - object $element, - bool $addFilters, - ): array { - $filterMapping = $this->getMapping($collection); - $mapping = $filterMapping; - - if (! $mapping->isOwningSide()) { - $sourceClass = $this->em->getClassMetadata($mapping->targetEntity); - $targetClass = $this->em->getClassMetadata($mapping->sourceEntity); - $sourceId = $this->uow->getEntityIdentifier($element); - $targetId = $this->uow->getEntityIdentifier($collection->getOwner()); - } else { - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $sourceId = $this->uow->getEntityIdentifier($collection->getOwner()); - $targetId = $this->uow->getEntityIdentifier($element); - } - - $mapping = $this->em->getMetadataFactory()->getOwningSide($mapping); - - $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform); - $whereClauses = []; - $params = []; - $types = []; - - foreach ($mapping->joinTableColumns as $joinTableColumn) { - $whereClauses[] = ($addFilters ? 't.' : '') . $joinTableColumn . ' = ?'; - - if (isset($mapping->relationToTargetKeyColumns[$joinTableColumn])) { - $targetColumn = $mapping->relationToTargetKeyColumns[$joinTableColumn]; - $params[] = $targetId[$targetClass->getFieldForColumn($targetColumn)]; - $types[] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em); - - continue; - } - - // relationToSourceKeyColumns - $targetColumn = $mapping->relationToSourceKeyColumns[$joinTableColumn]; - $params[] = $sourceId[$sourceClass->getFieldForColumn($targetColumn)]; - $types[] = PersisterHelper::getTypeOfColumn($targetColumn, $sourceClass, $this->em); - } - - if ($addFilters) { - $quotedJoinTable .= ' t'; - - [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping); - - if ($filterSql) { - $quotedJoinTable .= ' ' . $joinTargetEntitySQL; - $whereClauses[] = $filterSql; - } - } - - return [$quotedJoinTable, $whereClauses, $params, $types]; - } - - /** - * Expands Criteria Parameters by walking the expressions and grabbing all - * parameters and types from it. - * - * @return mixed[][] - */ - private function expandCriteriaParameters(Criteria $criteria): array - { - $expression = $criteria->getWhereExpression(); - - if ($expression === null) { - return []; - } - - $valueVisitor = new SqlValueVisitor(); - - $valueVisitor->dispatch($expression); - - [, $types] = $valueVisitor->getParamsAndTypes(); - - return $types; - } - - private function getOrderingSql(Criteria $criteria, ClassMetadata $targetClass): string - { - $orderings = $criteria->orderings(); - if ($orderings) { - $orderBy = []; - foreach ($orderings as $name => $direction) { - $field = $this->quoteStrategy->getColumnName( - $name, - $targetClass, - $this->platform, - ); - $orderBy[] = $field . ' ' . $direction->value; - } - - return ' ORDER BY ' . implode(', ', $orderBy); - } - - return ''; - } - - /** @throws DBALException */ - private function getLimitSql(Criteria $criteria): string - { - $limit = $criteria->getMaxResults(); - $offset = $criteria->getFirstResult(); - - return $this->platform->modifyLimitQuery('', $limit, $offset ?? 0); - } - - private function getMapping(PersistentCollection $collection): AssociationMapping&ManyToManyAssociationMapping - { - $mapping = $collection->getMapping(); - - assert($mapping instanceof ManyToManyAssociationMapping); - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Collection/OneToManyPersister.php b/vendor/doctrine/orm/src/Persisters/Collection/OneToManyPersister.php deleted file mode 100644 index 0727b1f..0000000 --- a/vendor/doctrine/orm/src/Persisters/Collection/OneToManyPersister.php +++ /dev/null @@ -1,264 +0,0 @@ -getMapping($collection); - - if (! $mapping->orphanRemoval) { - // Handling non-orphan removal should never happen, as @OneToMany - // can only be inverse side. For owning side one to many, it is - // required to have a join table, which would classify as a ManyToManyPersister. - return; - } - - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - - $targetClass->isInheritanceTypeJoined() - ? $this->deleteJoinedEntityCollection($collection) - : $this->deleteEntityCollection($collection); - } - - public function update(PersistentCollection $collection): void - { - // This can never happen. One to many can only be inverse side. - // For owning side one to many, it is required to have a join table, - // then classifying it as a ManyToManyPersister. - return; - } - - public function get(PersistentCollection $collection, mixed $index): object|null - { - $mapping = $this->getMapping($collection); - - if (! $mapping->isIndexed()) { - throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); - } - - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - return $persister->load( - [ - $mapping->mappedBy => $collection->getOwner(), - $mapping->indexBy() => $index, - ], - null, - $mapping, - [], - null, - 1, - ); - } - - public function count(PersistentCollection $collection): int - { - $mapping = $this->getMapping($collection); - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - // only works with single id identifier entities. Will throw an - // exception in Entity Persisters if that is not the case for the - // 'mappedBy' field. - $criteria = new Criteria(Criteria::expr()->eq($mapping->mappedBy, $collection->getOwner())); - - return $persister->count($criteria); - } - - /** - * {@inheritDoc} - */ - public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array - { - $mapping = $this->getMapping($collection); - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - return $persister->getOneToManyCollection($mapping, $collection->getOwner(), $offset, $length); - } - - public function containsKey(PersistentCollection $collection, mixed $key): bool - { - $mapping = $this->getMapping($collection); - - if (! $mapping->isIndexed()) { - throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); - } - - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - // only works with single id identifier entities. Will throw an - // exception in Entity Persisters if that is not the case for the - // 'mappedBy' field. - $criteria = new Criteria(); - - $criteria->andWhere(Criteria::expr()->eq($mapping->mappedBy, $collection->getOwner())); - $criteria->andWhere(Criteria::expr()->eq($mapping->indexBy(), $key)); - - return (bool) $persister->count($criteria); - } - - public function contains(PersistentCollection $collection, object $element): bool - { - if (! $this->isValidEntityState($element)) { - return false; - } - - $mapping = $this->getMapping($collection); - $persister = $this->uow->getEntityPersister($mapping->targetEntity); - - // only works with single id identifier entities. Will throw an - // exception in Entity Persisters if that is not the case for the - // 'mappedBy' field. - $criteria = new Criteria(Criteria::expr()->eq($mapping->mappedBy, $collection->getOwner())); - - return $persister->exists($element, $criteria); - } - - /** - * {@inheritDoc} - */ - public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array - { - throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.'); - } - - /** - * @throws DBALException - * @throws EntityNotFoundException - * @throws MappingException - */ - private function deleteEntityCollection(PersistentCollection $collection): int - { - $mapping = $this->getMapping($collection); - $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $columns = []; - $parameters = []; - $types = []; - - foreach ($this->em->getMetadataFactory()->getOwningSide($mapping)->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $parameters[] = $identifier[$sourceClass->getFieldForColumn($joinColumn->referencedColumnName)]; - $types[] = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $sourceClass, $this->em); - } - - $statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) - . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; - - if ($targetClass->isInheritanceTypeSingleTable()) { - $discriminatorColumn = $targetClass->getDiscriminatorColumn(); - $statement .= ' AND ' . $discriminatorColumn->name . ' = ?'; - $parameters[] = $targetClass->discriminatorValue; - $types[] = $discriminatorColumn->type; - } - - $numAffected = $this->conn->executeStatement($statement, $parameters, $types); - - assert(is_int($numAffected)); - - return $numAffected; - } - - /** - * Delete Class Table Inheritance entities. - * A temporary table is needed to keep IDs to be deleted in both parent and child class' tables. - * - * Thanks Steve Ebersole (Hibernate) for idea on how to tackle reliably this scenario, we owe him a beer! =) - * - * @throws DBALException - */ - private function deleteJoinedEntityCollection(PersistentCollection $collection): int - { - $mapping = $this->getMapping($collection); - $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity); - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - $rootClass = $this->em->getClassMetadata($targetClass->rootEntityName); - - // 1) Build temporary table DDL - $tempTable = $this->platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); - $idColumnNames = $rootClass->getIdentifierColumnNames(); - $idColumnList = implode(', ', $idColumnNames); - $columnDefinitions = []; - - foreach ($idColumnNames as $idColumnName) { - $columnDefinitions[$idColumnName] = [ - 'name' => $idColumnName, - 'notnull' => true, - 'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $this->em)), - ]; - } - - $statement = $this->platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable - . ' (' . $this->platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; - - $this->conn->executeStatement($statement); - - // 2) Build insert table records into temporary table - $query = $this->em->createQuery( - ' SELECT t0.' . implode(', t0.', $rootClass->getIdentifierFieldNames()) - . ' FROM ' . $targetClass->name . ' t0 WHERE t0.' . $mapping->mappedBy . ' = :owner', - )->setParameter('owner', $collection->getOwner()); - - $sql = $query->getSQL(); - assert(is_string($sql)); - $statement = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ') ' . $sql; - $parameters = array_values($sourceClass->getIdentifierValues($collection->getOwner())); - $numDeleted = $this->conn->executeStatement($statement, $parameters); - - // 3) Delete records on each table in the hierarchy - $classNames = [...$targetClass->parentClasses, ...[$targetClass->name], ...$targetClass->subClasses]; - - foreach (array_reverse($classNames) as $className) { - $tableName = $this->quoteStrategy->getTableName($this->em->getClassMetadata($className), $this->platform); - $statement = 'DELETE FROM ' . $tableName . ' WHERE (' . $idColumnList . ')' - . ' IN (SELECT ' . $idColumnList . ' FROM ' . $tempTable . ')'; - - $this->conn->executeStatement($statement); - } - - // 4) Drop temporary table - $statement = $this->platform->getDropTemporaryTableSQL($tempTable); - - $this->conn->executeStatement($statement); - - assert(is_int($numDeleted)); - - return $numDeleted; - } - - private function getMapping(PersistentCollection $collection): OneToManyAssociationMapping - { - $mapping = $collection->getMapping(); - - assert($mapping->isOneToMany()); - - return $mapping; - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/AbstractEntityInheritancePersister.php b/vendor/doctrine/orm/src/Persisters/Entity/AbstractEntityInheritancePersister.php deleted file mode 100644 index cf8a74e..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/AbstractEntityInheritancePersister.php +++ /dev/null @@ -1,66 +0,0 @@ -class->getDiscriminatorColumn(); - $this->columnTypes[$discColumn->name] = $discColumn->type; - $data[$this->getDiscriminatorColumnTableName()][$discColumn->name] = $this->class->discriminatorValue; - - return $data; - } - - /** - * Gets the name of the table that contains the discriminator column. - */ - abstract protected function getDiscriminatorColumnTableName(): string; - - protected function getSelectColumnSQL(string $field, ClassMetadata $class, string $alias = 'r'): string - { - $tableAlias = $alias === 'r' ? '' : $alias; - $fieldMapping = $class->fieldMappings[$field]; - $columnAlias = $this->getSQLColumnAlias($fieldMapping->columnName); - $sql = sprintf( - '%s.%s', - $this->getSQLTableAlias($class->name, $tableAlias), - $this->quoteStrategy->getColumnName($field, $class, $this->platform), - ); - - $this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field, $class->name); - - $type = Type::getType($fieldMapping->type); - $sql = $type->convertToPHPValueSQL($sql, $this->platform); - - return $sql . ' AS ' . $columnAlias; - } - - protected function getSelectJoinColumnSQL(string $tableAlias, string $joinColumnName, string $quotedColumnName, string $type): string - { - $columnAlias = $this->getSQLColumnAlias($joinColumnName); - - $this->currentPersisterContext->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type); - - return $tableAlias . '.' . $quotedColumnName . ' AS ' . $columnAlias; - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/BasicEntityPersister.php b/vendor/doctrine/orm/src/Persisters/Entity/BasicEntityPersister.php deleted file mode 100644 index 377e03c..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/BasicEntityPersister.php +++ /dev/null @@ -1,2085 +0,0 @@ - */ - private static array $comparisonMap = [ - Comparison::EQ => '= %s', - Comparison::NEQ => '!= %s', - Comparison::GT => '> %s', - Comparison::GTE => '>= %s', - Comparison::LT => '< %s', - Comparison::LTE => '<= %s', - Comparison::IN => 'IN (%s)', - Comparison::NIN => 'NOT IN (%s)', - Comparison::CONTAINS => 'LIKE %s', - Comparison::STARTS_WITH => 'LIKE %s', - Comparison::ENDS_WITH => 'LIKE %s', - ]; - - /** - * The underlying DBAL Connection of the used EntityManager. - */ - protected Connection $conn; - - /** - * The database platform. - */ - protected AbstractPlatform $platform; - - /** - * Queued inserts. - * - * @psalm-var array - */ - protected array $queuedInserts = []; - - /** - * The map of column names to DBAL mapping types of all prepared columns used - * when INSERTing or UPDATEing an entity. - * - * @see prepareInsertData($entity) - * @see prepareUpdateData($entity) - * - * @var mixed[] - */ - protected array $columnTypes = []; - - /** - * The map of quoted column names. - * - * @see prepareInsertData($entity) - * @see prepareUpdateData($entity) - * - * @var mixed[] - */ - protected array $quotedColumns = []; - - /** - * The INSERT SQL statement used for entities handled by this persister. - * This SQL is only generated once per request, if at all. - */ - private string|null $insertSql = null; - - /** - * The quote strategy. - */ - protected QuoteStrategy $quoteStrategy; - - /** - * The IdentifierFlattener used for manipulating identifiers - */ - protected readonly IdentifierFlattener $identifierFlattener; - - protected CachedPersisterContext $currentPersisterContext; - private readonly CachedPersisterContext $limitsHandlingContext; - private readonly CachedPersisterContext $noLimitsContext; - - /** - * Initializes a new BasicEntityPersister that uses the given EntityManager - * and persists instances of the class described by the given ClassMetadata descriptor. - * - * @param ClassMetadata $class Metadata object that describes the mapping of the mapped entity class. - */ - public function __construct( - protected EntityManagerInterface $em, - protected ClassMetadata $class, - ) { - $this->conn = $em->getConnection(); - $this->platform = $this->conn->getDatabasePlatform(); - $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); - $this->noLimitsContext = $this->currentPersisterContext = new CachedPersisterContext( - $class, - new Query\ResultSetMapping(), - false, - ); - $this->limitsHandlingContext = new CachedPersisterContext( - $class, - new Query\ResultSetMapping(), - true, - ); - } - - public function getClassMetadata(): ClassMetadata - { - return $this->class; - } - - public function getResultSetMapping(): ResultSetMapping - { - return $this->currentPersisterContext->rsm; - } - - public function addInsert(object $entity): void - { - $this->queuedInserts[spl_object_id($entity)] = $entity; - } - - /** - * {@inheritDoc} - */ - public function getInserts(): array - { - return $this->queuedInserts; - } - - public function executeInserts(): void - { - if (! $this->queuedInserts) { - return; - } - - $uow = $this->em->getUnitOfWork(); - $idGenerator = $this->class->idGenerator; - $isPostInsertId = $idGenerator->isPostInsertGenerator(); - - $stmt = $this->conn->prepare($this->getInsertSQL()); - $tableName = $this->class->getTableName(); - - foreach ($this->queuedInserts as $key => $entity) { - $insertData = $this->prepareInsertData($entity); - - if (isset($insertData[$tableName])) { - $paramIndex = 1; - - foreach ($insertData[$tableName] as $column => $value) { - $stmt->bindValue($paramIndex++, $value, $this->columnTypes[$column]); - } - } - - $stmt->executeStatement(); - - if ($isPostInsertId) { - $generatedId = $idGenerator->generateId($this->em, $entity); - $id = [$this->class->identifier[0] => $generatedId]; - - $uow->assignPostInsertId($entity, $generatedId); - } else { - $id = $this->class->getIdentifierValues($entity); - } - - if ($this->class->requiresFetchAfterChange) { - $this->assignDefaultVersionAndUpsertableValues($entity, $id); - } - - // Unset this queued insert, so that the prepareUpdateData() method knows right away - // (for the next entity already) that the current entity has been written to the database - // and no extra updates need to be scheduled to refer to it. - // - // In \Doctrine\ORM\UnitOfWork::executeInserts(), the UoW already removed entities - // from its own list (\Doctrine\ORM\UnitOfWork::$entityInsertions) right after they - // were given to our addInsert() method. - unset($this->queuedInserts[$key]); - } - } - - /** - * Retrieves the default version value which was created - * by the preceding INSERT statement and assigns it back in to the - * entities version field if the given entity is versioned. - * Also retrieves values of columns marked as 'non insertable' and / or - * 'not updatable' and assigns them back to the entities corresponding fields. - * - * @param mixed[] $id - */ - protected function assignDefaultVersionAndUpsertableValues(object $entity, array $id): void - { - $values = $this->fetchVersionAndNotUpsertableValues($this->class, $id); - - foreach ($values as $field => $value) { - $value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform); - - $this->class->setFieldValue($entity, $field, $value); - } - } - - /** - * Fetches the current version value of a versioned entity and / or the values of fields - * marked as 'not insertable' and / or 'not updatable'. - * - * @param mixed[] $id - */ - protected function fetchVersionAndNotUpsertableValues(ClassMetadata $versionedClass, array $id): mixed - { - $columnNames = []; - foreach ($this->class->fieldMappings as $key => $column) { - if (isset($column->generated) || ($this->class->isVersioned && $key === $versionedClass->versionField)) { - $columnNames[$key] = $this->quoteStrategy->getColumnName($key, $versionedClass, $this->platform); - } - } - - $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); - $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform); - - // FIXME: Order with composite keys might not be correct - $sql = 'SELECT ' . implode(', ', $columnNames) - . ' FROM ' . $tableName - . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; - - $flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id); - - $values = $this->conn->fetchNumeric( - $sql, - array_values($flatId), - $this->extractIdentifierTypes($id, $versionedClass), - ); - - if ($values === false) { - throw new LengthException('Unexpected empty result for database query.'); - } - - $values = array_combine(array_keys($columnNames), $values); - - if (! $values) { - throw new LengthException('Unexpected number of database columns.'); - } - - return $values; - } - - /** - * @param mixed[] $id - * - * @return list - * @psalm-return list - */ - final protected function extractIdentifierTypes(array $id, ClassMetadata $versionedClass): array - { - $types = []; - - foreach ($id as $field => $value) { - $types = [...$types, ...$this->getTypes($field, $value, $versionedClass)]; - } - - return $types; - } - - public function update(object $entity): void - { - $tableName = $this->class->getTableName(); - $updateData = $this->prepareUpdateData($entity); - - if (! isset($updateData[$tableName])) { - return; - } - - $data = $updateData[$tableName]; - - if (! $data) { - return; - } - - $isVersioned = $this->class->isVersioned; - $quotedTableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - - $this->updateTable($entity, $quotedTableName, $data, $isVersioned); - - if ($this->class->requiresFetchAfterChange) { - $id = $this->class->getIdentifierValues($entity); - - $this->assignDefaultVersionAndUpsertableValues($entity, $id); - } - } - - /** - * Performs an UPDATE statement for an entity on a specific table. - * The UPDATE can optionally be versioned, which requires the entity to have a version field. - * - * @param object $entity The entity object being updated. - * @param string $quotedTableName The quoted name of the table to apply the UPDATE on. - * @param mixed[] $updateData The map of columns to update (column => value). - * @param bool $versioned Whether the UPDATE should be versioned. - * - * @throws UnrecognizedField - * @throws OptimisticLockException - */ - final protected function updateTable( - object $entity, - string $quotedTableName, - array $updateData, - bool $versioned = false, - ): void { - $set = []; - $types = []; - $params = []; - - foreach ($updateData as $columnName => $value) { - $placeholder = '?'; - $column = $columnName; - - switch (true) { - case isset($this->class->fieldNames[$columnName]): - $fieldName = $this->class->fieldNames[$columnName]; - $column = $this->quoteStrategy->getColumnName($fieldName, $this->class, $this->platform); - - if (isset($this->class->fieldMappings[$fieldName])) { - $type = Type::getType($this->columnTypes[$columnName]); - $placeholder = $type->convertToDatabaseValueSQL('?', $this->platform); - } - - break; - - case isset($this->quotedColumns[$columnName]): - $column = $this->quotedColumns[$columnName]; - - break; - } - - $params[] = $value; - $set[] = $column . ' = ' . $placeholder; - $types[] = $this->columnTypes[$columnName]; - } - - $where = []; - $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - - foreach ($this->class->identifier as $idField) { - if (! isset($this->class->associationMappings[$idField])) { - $params[] = $identifier[$idField]; - $types[] = $this->class->fieldMappings[$idField]->type; - $where[] = $this->quoteStrategy->getColumnName($idField, $this->class, $this->platform); - - continue; - } - - assert($this->class->associationMappings[$idField]->isToOneOwningSide()); - - $params[] = $identifier[$idField]; - $where[] = $this->quoteStrategy->getJoinColumnName( - $this->class->associationMappings[$idField]->joinColumns[0], - $this->class, - $this->platform, - ); - - $targetMapping = $this->em->getClassMetadata($this->class->associationMappings[$idField]->targetEntity); - $targetType = PersisterHelper::getTypeOfField($targetMapping->identifier[0], $targetMapping, $this->em); - - if ($targetType === []) { - throw UnrecognizedField::byFullyQualifiedName($this->class->name, $targetMapping->identifier[0]); - } - - $types[] = reset($targetType); - } - - if ($versioned) { - $versionField = $this->class->versionField; - assert($versionField !== null); - $versionFieldType = $this->class->fieldMappings[$versionField]->type; - $versionColumn = $this->quoteStrategy->getColumnName($versionField, $this->class, $this->platform); - - $where[] = $versionColumn; - $types[] = $this->class->fieldMappings[$versionField]->type; - $params[] = $this->class->reflFields[$versionField]->getValue($entity); - - switch ($versionFieldType) { - case Types::SMALLINT: - case Types::INTEGER: - case Types::BIGINT: - $set[] = $versionColumn . ' = ' . $versionColumn . ' + 1'; - break; - - case Types::DATETIME_MUTABLE: - $set[] = $versionColumn . ' = CURRENT_TIMESTAMP'; - break; - } - } - - $sql = 'UPDATE ' . $quotedTableName - . ' SET ' . implode(', ', $set) - . ' WHERE ' . implode(' = ? AND ', $where) . ' = ?'; - - $result = $this->conn->executeStatement($sql, $params, $types); - - if ($versioned && ! $result) { - throw OptimisticLockException::lockFailed($entity); - } - } - - /** - * @param array $identifier - * @param string[] $types - * - * @todo Add check for platform if it supports foreign keys/cascading. - */ - protected function deleteJoinTableRecords(array $identifier, array $types): void - { - foreach ($this->class->associationMappings as $mapping) { - if (! $mapping->isManyToMany() || $mapping->isOnDeleteCascade) { - continue; - } - - // @Todo this only covers scenarios with no inheritance or of the same level. Is there something - // like self-referential relationship between different levels of an inheritance hierarchy? I hope not! - $selfReferential = ($mapping->targetEntity === $mapping->sourceEntity); - $class = $this->class; - $association = $mapping; - $otherColumns = []; - $otherKeys = []; - $keys = []; - - if (! $mapping->isOwningSide()) { - $class = $this->em->getClassMetadata($mapping->targetEntity); - } - - $association = $this->em->getMetadataFactory()->getOwningSide($association); - $joinColumns = $mapping->isOwningSide() - ? $association->joinTable->joinColumns - : $association->joinTable->inverseJoinColumns; - - if ($selfReferential) { - $otherColumns = ! $mapping->isOwningSide() - ? $association->joinTable->joinColumns - : $association->joinTable->inverseJoinColumns; - } - - foreach ($joinColumns as $joinColumn) { - $keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - - foreach ($otherColumns as $joinColumn) { - $otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - - $joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform); - - $this->conn->delete($joinTableName, array_combine($keys, $identifier), $types); - - if ($selfReferential) { - $this->conn->delete($joinTableName, array_combine($otherKeys, $identifier), $types); - } - } - } - - public function delete(object $entity): bool - { - $class = $this->class; - $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - $tableName = $this->quoteStrategy->getTableName($class, $this->platform); - $idColumns = $this->quoteStrategy->getIdentifierColumnNames($class, $this->platform); - $id = array_combine($idColumns, $identifier); - $types = $this->getClassIdentifiersTypes($class); - - $this->deleteJoinTableRecords($identifier, $types); - - return (bool) $this->conn->delete($tableName, $id, $types); - } - - /** - * Prepares the changeset of an entity for database insertion (UPDATE). - * - * The changeset is obtained from the currently running UnitOfWork. - * - * During this preparation the array that is passed as the second parameter is filled with - * => pairs, grouped by table name. - * - * Example: - * - * array( - * 'foo_table' => array('column1' => 'value1', 'column2' => 'value2', ...), - * 'bar_table' => array('columnX' => 'valueX', 'columnY' => 'valueY', ...), - * ... - * ) - * - * - * @param object $entity The entity for which to prepare the data. - * @param bool $isInsert Whether the data to be prepared refers to an insert statement. - * - * @return mixed[][] The prepared data. - * @psalm-return array> - */ - protected function prepareUpdateData(object $entity, bool $isInsert = false): array - { - $versionField = null; - $result = []; - $uow = $this->em->getUnitOfWork(); - - $versioned = $this->class->isVersioned; - if ($versioned !== false) { - $versionField = $this->class->versionField; - } - - foreach ($uow->getEntityChangeSet($entity) as $field => $change) { - if (isset($versionField) && $versionField === $field) { - continue; - } - - if (isset($this->class->embeddedClasses[$field])) { - continue; - } - - $newVal = $change[1]; - - if (! isset($this->class->associationMappings[$field])) { - $fieldMapping = $this->class->fieldMappings[$field]; - $columnName = $fieldMapping->columnName; - - if (! $isInsert && isset($fieldMapping->notUpdatable)) { - continue; - } - - if ($isInsert && isset($fieldMapping->notInsertable)) { - continue; - } - - $this->columnTypes[$columnName] = $fieldMapping->type; - - $result[$this->getOwningTable($field)][$columnName] = $newVal; - - continue; - } - - $assoc = $this->class->associationMappings[$field]; - - // Only owning side of x-1 associations can have a FK column. - if (! $assoc->isToOneOwningSide()) { - continue; - } - - if ($newVal !== null) { - $oid = spl_object_id($newVal); - - // If the associated entity $newVal is not yet persisted and/or does not yet have - // an ID assigned, we must set $newVal = null. This will insert a null value and - // schedule an extra update on the UnitOfWork. - // - // This gives us extra time to a) possibly obtain a database-generated identifier - // value for $newVal, and b) insert $newVal into the database before the foreign - // key reference is being made. - // - // When looking at $this->queuedInserts and $uow->isScheduledForInsert, be aware - // of the implementation details that our own executeInserts() method will remove - // entities from the former as soon as the insert statement has been executed and - // a post-insert ID has been assigned (if necessary), and that the UnitOfWork has - // already removed entities from its own list at the time they were passed to our - // addInsert() method. - // - // Then, there is one extra exception we can make: An entity that references back to itself - // _and_ uses an application-provided ID (the "NONE" generator strategy) also does not - // need the extra update, although it is still in the list of insertions itself. - // This looks like a minor optimization at first, but is the capstone for being able to - // use non-NULLable, self-referencing associations in applications that provide IDs (like UUIDs). - if ( - (isset($this->queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) - && ! ($newVal === $entity && $this->class->isIdentifierNatural()) - ) { - $uow->scheduleExtraUpdate($entity, [$field => [null, $newVal]]); - - $newVal = null; - } - } - - $newValId = null; - - if ($newVal !== null) { - $newValId = $uow->getEntityIdentifier($newVal); - } - - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - $owningTable = $this->getOwningTable($field); - - foreach ($assoc->joinColumns as $joinColumn) { - $sourceColumn = $joinColumn->name; - $targetColumn = $joinColumn->referencedColumnName; - $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - - $this->quotedColumns[$sourceColumn] = $quotedColumn; - $this->columnTypes[$sourceColumn] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em); - $result[$owningTable][$sourceColumn] = $newValId - ? $newValId[$targetClass->getFieldForColumn($targetColumn)] - : null; - } - } - - return $result; - } - - /** - * Prepares the data changeset of a managed entity for database insertion (initial INSERT). - * The changeset of the entity is obtained from the currently running UnitOfWork. - * - * The default insert data preparation is the same as for updates. - * - * @see prepareUpdateData - * - * @param object $entity The entity for which to prepare the data. - * - * @return mixed[][] The prepared data for the tables to update. - * @psalm-return array - */ - protected function prepareInsertData(object $entity): array - { - return $this->prepareUpdateData($entity, true); - } - - public function getOwningTable(string $fieldName): string - { - return $this->class->getTableName(); - } - - /** - * {@inheritDoc} - */ - public function load( - array $criteria, - object|null $entity = null, - AssociationMapping|null $assoc = null, - array $hints = [], - LockMode|int|null $lockMode = null, - int|null $limit = null, - array|null $orderBy = null, - ): object|null { - $this->switchPersisterContext(null, $limit); - - $sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy); - [$params, $types] = $this->expandParameters($criteria); - $stmt = $this->conn->executeQuery($sql, $params, $types); - - if ($entity !== null) { - $hints[Query::HINT_REFRESH] = true; - $hints[Query::HINT_REFRESH_ENTITY] = $entity; - } - - $hydrator = $this->em->newHydrator($this->currentPersisterContext->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - $entities = $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, $hints); - - return $entities ? $entities[0] : null; - } - - /** - * {@inheritDoc} - */ - public function loadById(array $identifier, object|null $entity = null): object|null - { - return $this->load($identifier, $entity); - } - - /** - * {@inheritDoc} - */ - public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null - { - $foundEntity = $this->em->getUnitOfWork()->tryGetById($identifier, $assoc->targetEntity); - if ($foundEntity !== false) { - return $foundEntity; - } - - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - if ($assoc->isOwningSide()) { - $isInverseSingleValued = $assoc->inversedBy !== null && ! $targetClass->isCollectionValuedAssociation($assoc->inversedBy); - - // Mark inverse side as fetched in the hints, otherwise the UoW would - // try to load it in a separate query (remember: to-one inverse sides can not be lazy). - $hints = []; - - if ($isInverseSingleValued) { - $hints['fetched']['r'][$assoc->inversedBy] = true; - } - - $targetEntity = $this->load($identifier, null, $assoc, $hints); - - // Complete bidirectional association, if necessary - if ($targetEntity !== null && $isInverseSingleValued) { - $targetClass->reflFields[$assoc->inversedBy]->setValue($targetEntity, $sourceEntity); - } - - return $targetEntity; - } - - assert(isset($assoc->mappedBy)); - $sourceClass = $this->em->getClassMetadata($assoc->sourceEntity); - $owningAssoc = $targetClass->getAssociationMapping($assoc->mappedBy); - assert($owningAssoc->isOneToOneOwningSide()); - - $computedIdentifier = []; - - // TRICKY: since the association is specular source and target are flipped - foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) { - if (! isset($sourceClass->fieldNames[$sourceKeyColumn])) { - throw MappingException::joinColumnMustPointToMappedField( - $sourceClass->name, - $sourceKeyColumn, - ); - } - - $computedIdentifier[$targetClass->getFieldForColumn($targetKeyColumn)] = - $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); - } - - $targetEntity = $this->load($computedIdentifier, null, $assoc); - - if ($targetEntity !== null) { - $targetClass->setFieldValue($targetEntity, $assoc->mappedBy, $sourceEntity); - } - - return $targetEntity; - } - - /** - * {@inheritDoc} - */ - public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void - { - $sql = $this->getSelectSQL($id, null, $lockMode); - [$params, $types] = $this->expandParameters($id); - $stmt = $this->conn->executeQuery($sql, $params, $types); - - $hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT); - $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, [Query::HINT_REFRESH => true]); - } - - public function count(array|Criteria $criteria = []): int - { - $sql = $this->getCountSQL($criteria); - - [$params, $types] = $criteria instanceof Criteria - ? $this->expandCriteriaParameters($criteria) - : $this->expandParameters($criteria); - - return (int) $this->conn->executeQuery($sql, $params, $types)->fetchOne(); - } - - /** - * {@inheritDoc} - */ - public function loadCriteria(Criteria $criteria): array - { - $orderBy = array_map( - static fn (Order $order): string => $order->value, - $criteria->orderings(), - ); - $limit = $criteria->getMaxResults(); - $offset = $criteria->getFirstResult(); - $query = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); - - [$params, $types] = $this->expandCriteriaParameters($criteria); - - $stmt = $this->conn->executeQuery($query, $params, $types); - $hydrator = $this->em->newHydrator($this->currentPersisterContext->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - - return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, [UnitOfWork::HINT_DEFEREAGERLOAD => true]); - } - - /** - * {@inheritDoc} - */ - public function expandCriteriaParameters(Criteria $criteria): array - { - $expression = $criteria->getWhereExpression(); - $sqlParams = []; - $sqlTypes = []; - - if ($expression === null) { - return [$sqlParams, $sqlTypes]; - } - - $valueVisitor = new SqlValueVisitor(); - - $valueVisitor->dispatch($expression); - - [, $types] = $valueVisitor->getParamsAndTypes(); - - foreach ($types as $type) { - [$field, $value, $operator] = $type; - - if ($value === null && ($operator === Comparison::EQ || $operator === Comparison::NEQ)) { - continue; - } - - $sqlParams = [...$sqlParams, ...$this->getValues($value)]; - $sqlTypes = [...$sqlTypes, ...$this->getTypes($field, $value, $this->class)]; - } - - return [$sqlParams, $sqlTypes]; - } - - /** - * {@inheritDoc} - */ - public function loadAll( - array $criteria = [], - array|null $orderBy = null, - int|null $limit = null, - int|null $offset = null, - ): array { - $this->switchPersisterContext($offset, $limit); - - $sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); - [$params, $types] = $this->expandParameters($criteria); - $stmt = $this->conn->executeQuery($sql, $params, $types); - - $hydrator = $this->em->newHydrator($this->currentPersisterContext->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - - return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, [UnitOfWork::HINT_DEFEREAGERLOAD => true]); - } - - /** - * {@inheritDoc} - */ - public function getManyToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array { - assert($assoc->isManyToMany()); - $this->switchPersisterContext($offset, $limit); - - $stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit); - - return $this->loadArrayFromResult($assoc, $stmt); - } - - /** - * Loads an array of entities from a given DBAL statement. - * - * @return mixed[] - */ - private function loadArrayFromResult(AssociationMapping $assoc, Result $stmt): array - { - $rsm = $this->currentPersisterContext->rsm; - $hints = [UnitOfWork::HINT_DEFEREAGERLOAD => true]; - - if ($assoc->isIndexed()) { - $rsm = clone $this->currentPersisterContext->rsm; // this is necessary because the "default rsm" should be changed. - $rsm->addIndexBy('r', $assoc->indexBy()); - } - - return $this->em->newHydrator(Query::HYDRATE_OBJECT)->hydrateAll($stmt, $rsm, $hints); - } - - /** - * Hydrates a collection from a given DBAL statement. - * - * @return mixed[] - */ - private function loadCollectionFromStatement( - AssociationMapping $assoc, - Result $stmt, - PersistentCollection $coll, - ): array { - $rsm = $this->currentPersisterContext->rsm; - $hints = [ - UnitOfWork::HINT_DEFEREAGERLOAD => true, - 'collection' => $coll, - ]; - - if ($assoc->isIndexed()) { - $rsm = clone $this->currentPersisterContext->rsm; // this is necessary because the "default rsm" should be changed. - $rsm->addIndexBy('r', $assoc->indexBy()); - } - - return $this->em->newHydrator(Query::HYDRATE_OBJECT)->hydrateAll($stmt, $rsm, $hints); - } - - /** - * {@inheritDoc} - */ - public function loadManyToManyCollection(AssociationMapping $assoc, object $sourceEntity, PersistentCollection $collection): array - { - assert($assoc->isManyToMany()); - $stmt = $this->getManyToManyStatement($assoc, $sourceEntity); - - return $this->loadCollectionFromStatement($assoc, $stmt, $collection); - } - - /** @throws MappingException */ - private function getManyToManyStatement( - AssociationMapping&ManyToManyAssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): Result { - $this->switchPersisterContext($offset, $limit); - - $sourceClass = $this->em->getClassMetadata($assoc->sourceEntity); - $class = $sourceClass; - $association = $assoc; - $criteria = []; - $parameters = []; - - if (! $assoc->isOwningSide()) { - $class = $this->em->getClassMetadata($assoc->targetEntity); - } - - $association = $this->em->getMetadataFactory()->getOwningSide($assoc); - $joinColumns = $assoc->isOwningSide() - ? $association->joinTable->joinColumns - : $association->joinTable->inverseJoinColumns; - - $quotedJoinTable = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform); - - foreach ($joinColumns as $joinColumn) { - $sourceKeyColumn = $joinColumn->referencedColumnName; - $quotedKeyColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - - switch (true) { - case $sourceClass->containsForeignIdentifier: - $field = $sourceClass->getFieldForColumn($sourceKeyColumn); - $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); - - if (isset($sourceClass->associationMappings[$field])) { - $value = $this->em->getUnitOfWork()->getEntityIdentifier($value); - $value = $value[$this->em->getClassMetadata($sourceClass->associationMappings[$field]->targetEntity)->identifier[0]]; - } - - break; - - case isset($sourceClass->fieldNames[$sourceKeyColumn]): - $field = $sourceClass->fieldNames[$sourceKeyColumn]; - $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); - - break; - - default: - throw MappingException::joinColumnMustPointToMappedField( - $sourceClass->name, - $sourceKeyColumn, - ); - } - - $criteria[$quotedJoinTable . '.' . $quotedKeyColumn] = $value; - $parameters[] = [ - 'value' => $value, - 'field' => $field, - 'class' => $sourceClass, - ]; - } - - $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset); - [$params, $types] = $this->expandToManyParameters($parameters); - - return $this->conn->executeQuery($sql, $params, $types); - } - - public function getSelectSQL( - array|Criteria $criteria, - AssociationMapping|null $assoc = null, - LockMode|int|null $lockMode = null, - int|null $limit = null, - int|null $offset = null, - array|null $orderBy = null, - ): string { - $this->switchPersisterContext($offset, $limit); - - $joinSql = ''; - $orderBySql = ''; - - if ($assoc !== null && $assoc->isManyToMany()) { - $joinSql = $this->getSelectManyToManyJoinSQL($assoc); - } - - if ($assoc !== null && $assoc->isOrdered()) { - $orderBy = $assoc->orderBy(); - } - - if ($orderBy) { - $orderBySql = $this->getOrderBySQL($orderBy, $this->getSQLTableAlias($this->class->name)); - } - - $conditionSql = $criteria instanceof Criteria - ? $this->getSelectConditionCriteriaSQL($criteria) - : $this->getSelectConditionSQL($criteria, $assoc); - - $lockSql = match ($lockMode) { - LockMode::PESSIMISTIC_READ => ' ' . $this->getReadLockSQL($this->platform), - LockMode::PESSIMISTIC_WRITE => ' ' . $this->getWriteLockSQL($this->platform), - default => '', - }; - - $columnList = $this->getSelectColumnsSQL(); - $tableAlias = $this->getSQLTableAlias($this->class->name); - $filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias); - $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - - if ($filterSql !== '') { - $conditionSql = $conditionSql - ? $conditionSql . ' AND ' . $filterSql - : $filterSql; - } - - $select = 'SELECT ' . $columnList; - $from = ' FROM ' . $tableName . ' ' . $tableAlias; - $join = $this->currentPersisterContext->selectJoinSql . $joinSql; - $where = ($conditionSql ? ' WHERE ' . $conditionSql : ''); - $lock = $this->platform->appendLockHint($from, $lockMode ?? LockMode::NONE); - $query = $select - . $lock - . $join - . $where - . $orderBySql; - - return $this->platform->modifyLimitQuery($query, $limit, $offset ?? 0) . $lockSql; - } - - public function getCountSQL(array|Criteria $criteria = []): string - { - $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - $tableAlias = $this->getSQLTableAlias($this->class->name); - - $conditionSql = $criteria instanceof Criteria - ? $this->getSelectConditionCriteriaSQL($criteria) - : $this->getSelectConditionSQL($criteria); - - $filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias); - - if ($filterSql !== '') { - $conditionSql = $conditionSql - ? $conditionSql . ' AND ' . $filterSql - : $filterSql; - } - - return 'SELECT COUNT(*) ' - . 'FROM ' . $tableName . ' ' . $tableAlias - . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql); - } - - /** - * Gets the ORDER BY SQL snippet for ordered collections. - * - * @psalm-param array $orderBy - * - * @throws InvalidOrientation - * @throws InvalidFindByCall - * @throws UnrecognizedField - */ - final protected function getOrderBySQL(array $orderBy, string $baseTableAlias): string - { - $orderByList = []; - - foreach ($orderBy as $fieldName => $orientation) { - $orientation = strtoupper(trim($orientation)); - - if ($orientation !== 'ASC' && $orientation !== 'DESC') { - throw InvalidOrientation::fromClassNameAndField($this->class->name, $fieldName); - } - - if (isset($this->class->fieldMappings[$fieldName])) { - $tableAlias = isset($this->class->fieldMappings[$fieldName]->inherited) - ? $this->getSQLTableAlias($this->class->fieldMappings[$fieldName]->inherited) - : $baseTableAlias; - - $columnName = $this->quoteStrategy->getColumnName($fieldName, $this->class, $this->platform); - $orderByList[] = $tableAlias . '.' . $columnName . ' ' . $orientation; - - continue; - } - - if (isset($this->class->associationMappings[$fieldName])) { - $association = $this->class->associationMappings[$fieldName]; - if (! $association->isOwningSide()) { - throw InvalidFindByCall::fromInverseSideUsage($this->class->name, $fieldName); - } - - assert($association->isToOneOwningSide()); - - $tableAlias = isset($association->inherited) - ? $this->getSQLTableAlias($association->inherited) - : $baseTableAlias; - - foreach ($association->joinColumns as $joinColumn) { - $columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - $orderByList[] = $tableAlias . '.' . $columnName . ' ' . $orientation; - } - - continue; - } - - throw UnrecognizedField::byFullyQualifiedName($this->class->name, $fieldName); - } - - return ' ORDER BY ' . implode(', ', $orderByList); - } - - /** - * Gets the SQL fragment with the list of columns to select when querying for - * an entity in this persister. - * - * Subclasses should override this method to alter or change the select column - * list SQL fragment. Note that in the implementation of BasicEntityPersister - * the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}. - * Subclasses may or may not do the same. - */ - protected function getSelectColumnsSQL(): string - { - if ($this->currentPersisterContext->selectColumnListSql !== null) { - return $this->currentPersisterContext->selectColumnListSql; - } - - $columnList = []; - $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r'); // r for root - - // Add regular columns to select list - foreach ($this->class->fieldNames as $field) { - $columnList[] = $this->getSelectColumnSQL($field, $this->class); - } - - $this->currentPersisterContext->selectJoinSql = ''; - $eagerAliasCounter = 0; - - foreach ($this->class->associationMappings as $assocField => $assoc) { - $assocColumnSQL = $this->getSelectColumnAssociationSQL($assocField, $assoc, $this->class); - - if ($assocColumnSQL) { - $columnList[] = $assocColumnSQL; - } - - $isAssocToOneInverseSide = $assoc->isToOne() && ! $assoc->isOwningSide(); - $isAssocFromOneEager = $assoc->isToOne() && $assoc->fetch === ClassMetadata::FETCH_EAGER; - - if (! ($isAssocFromOneEager || $isAssocToOneInverseSide)) { - continue; - } - - if ($assoc->isToMany() && $this->currentPersisterContext->handlesLimits) { - continue; - } - - $eagerEntity = $this->em->getClassMetadata($assoc->targetEntity); - - if ($eagerEntity->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { - continue; // now this is why you shouldn't use inheritance - } - - $assocAlias = 'e' . ($eagerAliasCounter++); - $this->currentPersisterContext->rsm->addJoinedEntityResult($assoc->targetEntity, $assocAlias, 'r', $assocField); - - foreach ($eagerEntity->fieldNames as $field) { - $columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias); - } - - foreach ($eagerEntity->associationMappings as $eagerAssocField => $eagerAssoc) { - $eagerAssocColumnSQL = $this->getSelectColumnAssociationSQL( - $eagerAssocField, - $eagerAssoc, - $eagerEntity, - $assocAlias, - ); - - if ($eagerAssocColumnSQL) { - $columnList[] = $eagerAssocColumnSQL; - } - } - - $association = $assoc; - $joinCondition = []; - - if ($assoc->isIndexed()) { - assert($assoc->isToMany()); - $this->currentPersisterContext->rsm->addIndexBy($assocAlias, $assoc->indexBy()); - } - - if (! $assoc->isOwningSide()) { - $eagerEntity = $this->em->getClassMetadata($assoc->targetEntity); - $association = $eagerEntity->getAssociationMapping($assoc->mappedBy); - } - - assert($association->isToOneOwningSide()); - - $joinTableAlias = $this->getSQLTableAlias($eagerEntity->name, $assocAlias); - $joinTableName = $this->quoteStrategy->getTableName($eagerEntity, $this->platform); - - if ($assoc->isOwningSide()) { - $tableAlias = $this->getSQLTableAlias($association->targetEntity, $assocAlias); - $this->currentPersisterContext->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association->joinColumns); - - foreach ($association->joinColumns as $joinColumn) { - $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform); - $joinCondition[] = $this->getSQLTableAlias($association->sourceEntity) - . '.' . $sourceCol . ' = ' . $tableAlias . '.' . $targetCol; - } - - // Add filter SQL - $filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias); - if ($filterSql) { - $joinCondition[] = $filterSql; - } - } else { - $this->currentPersisterContext->selectJoinSql .= ' LEFT JOIN'; - - foreach ($association->joinColumns as $joinColumn) { - $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform); - - $joinCondition[] = $this->getSQLTableAlias($association->sourceEntity, $assocAlias) . '.' . $sourceCol . ' = ' - . $this->getSQLTableAlias($association->targetEntity) . '.' . $targetCol; - } - } - - $this->currentPersisterContext->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON '; - $this->currentPersisterContext->selectJoinSql .= implode(' AND ', $joinCondition); - } - - $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - - return $this->currentPersisterContext->selectColumnListSql; - } - - /** Gets the SQL join fragment used when selecting entities from an association. */ - protected function getSelectColumnAssociationSQL( - string $field, - AssociationMapping $assoc, - ClassMetadata $class, - string $alias = 'r', - ): string { - if (! $assoc->isToOneOwningSide()) { - return ''; - } - - $columnList = []; - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - $isIdentifier = isset($assoc->id) && $assoc->id === true; - $sqlTableAlias = $this->getSQLTableAlias($class->name, ($alias === 'r' ? '' : $alias)); - - foreach ($assoc->joinColumns as $joinColumn) { - $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - $resultColumnName = $this->getSQLColumnAlias($joinColumn->name); - $type = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - - $this->currentPersisterContext->rsm->addMetaResult($alias, $resultColumnName, $joinColumn->name, $isIdentifier, $type); - - $columnList[] = sprintf('%s.%s AS %s', $sqlTableAlias, $quotedColumn, $resultColumnName); - } - - return implode(', ', $columnList); - } - - /** - * Gets the SQL join fragment used when selecting entities from a - * many-to-many association. - */ - protected function getSelectManyToManyJoinSQL(AssociationMapping&ManyToManyAssociationMapping $manyToMany): string - { - $conditions = []; - $association = $manyToMany; - $sourceTableAlias = $this->getSQLTableAlias($this->class->name); - - $association = $this->em->getMetadataFactory()->getOwningSide($manyToMany); - $joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform); - $joinColumns = $manyToMany->isOwningSide() - ? $association->joinTable->inverseJoinColumns - : $association->joinTable->joinColumns; - - foreach ($joinColumns as $joinColumn) { - $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform); - $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableName . '.' . $quotedSourceColumn; - } - - return ' INNER JOIN ' . $joinTableName . ' ON ' . implode(' AND ', $conditions); - } - - public function getInsertSQL(): string - { - if ($this->insertSql !== null) { - return $this->insertSql; - } - - $columns = $this->getInsertColumnList(); - $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - - if (empty($columns)) { - $identityColumn = $this->quoteStrategy->getColumnName($this->class->identifier[0], $this->class, $this->platform); - $this->insertSql = $this->platform->getEmptyIdentityInsertSQL($tableName, $identityColumn); - - return $this->insertSql; - } - - $values = []; - $columns = array_unique($columns); - - foreach ($columns as $column) { - $placeholder = '?'; - - if ( - isset($this->class->fieldNames[$column]) - && isset($this->columnTypes[$this->class->fieldNames[$column]]) - && isset($this->class->fieldMappings[$this->class->fieldNames[$column]]) - ) { - $type = Type::getType($this->columnTypes[$this->class->fieldNames[$column]]); - $placeholder = $type->convertToDatabaseValueSQL('?', $this->platform); - } - - $values[] = $placeholder; - } - - $columns = implode(', ', $columns); - $values = implode(', ', $values); - - $this->insertSql = sprintf('INSERT INTO %s (%s) VALUES (%s)', $tableName, $columns, $values); - - return $this->insertSql; - } - - /** - * Gets the list of columns to put in the INSERT SQL statement. - * - * Subclasses should override this method to alter or change the list of - * columns placed in the INSERT statements used by the persister. - * - * @psalm-return list - */ - protected function getInsertColumnList(): array - { - $columns = []; - - foreach ($this->class->reflFields as $name => $field) { - if ($this->class->isVersioned && $this->class->versionField === $name) { - continue; - } - - if (isset($this->class->embeddedClasses[$name])) { - continue; - } - - if (isset($this->class->associationMappings[$name])) { - $assoc = $this->class->associationMappings[$name]; - - if ($assoc->isToOneOwningSide()) { - foreach ($assoc->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - } - } - - continue; - } - - if (! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] !== $name) { - if (isset($this->class->fieldMappings[$name]->notInsertable)) { - continue; - } - - $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); - $this->columnTypes[$name] = $this->class->fieldMappings[$name]->type; - } - } - - return $columns; - } - - /** - * Gets the SQL snippet of a qualified column name for the given field name. - * - * @param ClassMetadata $class The class that declares this field. The table this class is - * mapped to must own the column for the given field. - */ - protected function getSelectColumnSQL(string $field, ClassMetadata $class, string $alias = 'r'): string - { - $root = $alias === 'r' ? '' : $alias; - $tableAlias = $this->getSQLTableAlias($class->name, $root); - $fieldMapping = $class->fieldMappings[$field]; - $sql = sprintf('%s.%s', $tableAlias, $this->quoteStrategy->getColumnName($field, $class, $this->platform)); - $columnAlias = $this->getSQLColumnAlias($fieldMapping->columnName); - - $this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field); - if (! empty($fieldMapping->enumType)) { - $this->currentPersisterContext->rsm->addEnumResult($columnAlias, $fieldMapping->enumType); - } - - $type = Type::getType($fieldMapping->type); - $sql = $type->convertToPHPValueSQL($sql, $this->platform); - - return $sql . ' AS ' . $columnAlias; - } - - /** - * Gets the SQL table alias for the given class name. - * - * @todo Reconsider. Binding table aliases to class names is not such a good idea. - */ - protected function getSQLTableAlias(string $className, string $assocName = ''): string - { - if ($assocName) { - $className .= '#' . $assocName; - } - - if (isset($this->currentPersisterContext->sqlTableAliases[$className])) { - return $this->currentPersisterContext->sqlTableAliases[$className]; - } - - $tableAlias = 't' . $this->currentPersisterContext->sqlAliasCounter++; - - $this->currentPersisterContext->sqlTableAliases[$className] = $tableAlias; - - return $tableAlias; - } - - /** - * {@inheritDoc} - */ - public function lock(array $criteria, LockMode|int $lockMode): void - { - $conditionSql = $this->getSelectConditionSQL($criteria); - - $lockSql = match ($lockMode) { - LockMode::PESSIMISTIC_READ => $this->getReadLockSQL($this->platform), - LockMode::PESSIMISTIC_WRITE => $this->getWriteLockSQL($this->platform), - default => '', - }; - - $lock = $this->getLockTablesSql($lockMode); - $where = ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' '; - $sql = 'SELECT 1 ' - . $lock - . $where - . $lockSql; - - [$params, $types] = $this->expandParameters($criteria); - - $this->conn->executeQuery($sql, $params, $types); - } - - /** - * Gets the FROM and optionally JOIN conditions to lock the entity managed by this persister. - * - * @psalm-param LockMode::* $lockMode - */ - protected function getLockTablesSql(LockMode|int $lockMode): string - { - return $this->platform->appendLockHint( - 'FROM ' - . $this->quoteStrategy->getTableName($this->class, $this->platform) . ' ' - . $this->getSQLTableAlias($this->class->name), - $lockMode, - ); - } - - /** - * Gets the Select Where Condition from a Criteria object. - */ - protected function getSelectConditionCriteriaSQL(Criteria $criteria): string - { - $expression = $criteria->getWhereExpression(); - - if ($expression === null) { - return ''; - } - - $visitor = new SqlExpressionVisitor($this, $this->class); - - return $visitor->dispatch($expression); - } - - public function getSelectConditionStatementSQL( - string $field, - mixed $value, - AssociationMapping|null $assoc = null, - string|null $comparison = null, - ): string { - $selectedColumns = []; - $columns = $this->getSelectConditionStatementColumnSQL($field, $assoc); - - if (count($columns) > 1 && $comparison === Comparison::IN) { - /* - * @todo try to support multi-column IN expressions. - * Example: (col1, col2) IN (('val1A', 'val2A'), ('val1B', 'val2B')) - */ - throw CantUseInOperatorOnCompositeKeys::create(); - } - - foreach ($columns as $column) { - $placeholder = '?'; - - if (isset($this->class->fieldMappings[$field])) { - $type = Type::getType($this->class->fieldMappings[$field]->type); - $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->platform); - } - - if ($comparison !== null) { - // special case null value handling - if (($comparison === Comparison::EQ || $comparison === Comparison::IS) && $value === null) { - $selectedColumns[] = $column . ' IS NULL'; - - continue; - } - - if ($comparison === Comparison::NEQ && $value === null) { - $selectedColumns[] = $column . ' IS NOT NULL'; - - continue; - } - - $selectedColumns[] = $column . ' ' . sprintf(self::$comparisonMap[$comparison], $placeholder); - - continue; - } - - if (is_array($value)) { - $in = sprintf('%s IN (%s)', $column, $placeholder); - - if (array_search(null, $value, true) !== false) { - $selectedColumns[] = sprintf('(%s OR %s IS NULL)', $in, $column); - - continue; - } - - $selectedColumns[] = $in; - - continue; - } - - if ($value === null) { - $selectedColumns[] = sprintf('%s IS NULL', $column); - - continue; - } - - $selectedColumns[] = sprintf('%s = %s', $column, $placeholder); - } - - return implode(' AND ', $selectedColumns); - } - - /** - * Builds the left-hand-side of a where condition statement. - * - * @return string[] - * @psalm-return list - * - * @throws InvalidFindByCall - * @throws UnrecognizedField - */ - private function getSelectConditionStatementColumnSQL( - string $field, - AssociationMapping|null $assoc = null, - ): array { - if (isset($this->class->fieldMappings[$field])) { - $className = $this->class->fieldMappings[$field]->inherited ?? $this->class->name; - - return [$this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform)]; - } - - if (isset($this->class->associationMappings[$field])) { - $association = $this->class->associationMappings[$field]; - // Many-To-Many requires join table check for joinColumn - $columns = []; - $class = $this->class; - - if ($association->isManyToMany()) { - assert($assoc !== null); - if (! $association->isOwningSide()) { - $association = $assoc; - } - - assert($association->isManyToManyOwningSide()); - - $joinTableName = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform); - $joinColumns = $assoc->isOwningSide() - ? $association->joinTable->joinColumns - : $association->joinTable->inverseJoinColumns; - - foreach ($joinColumns as $joinColumn) { - $columns[] = $joinTableName . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - } else { - if (! $association->isOwningSide()) { - throw InvalidFindByCall::fromInverseSideUsage( - $this->class->name, - $field, - ); - } - - assert($association->isToOneOwningSide()); - - $className = $association->inherited ?? $this->class->name; - - foreach ($association->joinColumns as $joinColumn) { - $columns[] = $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); - } - } - - return $columns; - } - - if ($assoc !== null && ! str_contains($field, ' ') && ! str_contains($field, '(')) { - // very careless developers could potentially open up this normally hidden api for userland attacks, - // therefore checking for spaces and function calls which are not allowed. - - // found a join column condition, not really a "field" - return [$field]; - } - - throw UnrecognizedField::byFullyQualifiedName($this->class->name, $field); - } - - /** - * Gets the conditional SQL fragment used in the WHERE clause when selecting - * entities in this persister. - * - * Subclasses are supposed to override this method if they intend to change - * or alter the criteria by which entities are selected. - * - * @psalm-param array $criteria - */ - protected function getSelectConditionSQL(array $criteria, AssociationMapping|null $assoc = null): string - { - $conditions = []; - - foreach ($criteria as $field => $value) { - $conditions[] = $this->getSelectConditionStatementSQL($field, $value, $assoc); - } - - return implode(' AND ', $conditions); - } - - /** - * {@inheritDoc} - */ - public function getOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array { - assert($assoc instanceof OneToManyAssociationMapping); - $this->switchPersisterContext($offset, $limit); - - $stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit); - - return $this->loadArrayFromResult($assoc, $stmt); - } - - public function loadOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - PersistentCollection $collection, - ): mixed { - assert($assoc instanceof OneToManyAssociationMapping); - $stmt = $this->getOneToManyStatement($assoc, $sourceEntity); - - return $this->loadCollectionFromStatement($assoc, $stmt, $collection); - } - - /** Builds criteria and execute SQL statement to fetch the one to many entities from. */ - private function getOneToManyStatement( - OneToManyAssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): Result { - $this->switchPersisterContext($offset, $limit); - - $criteria = []; - $parameters = []; - $owningAssoc = $this->class->associationMappings[$assoc->mappedBy]; - $sourceClass = $this->em->getClassMetadata($assoc->sourceEntity); - $tableAlias = $this->getSQLTableAlias($owningAssoc->inherited ?? $this->class->name); - assert($owningAssoc->isManyToOne()); - - foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) { - if ($sourceClass->containsForeignIdentifier) { - $field = $sourceClass->getFieldForColumn($sourceKeyColumn); - $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); - - if (isset($sourceClass->associationMappings[$field])) { - $value = $this->em->getUnitOfWork()->getEntityIdentifier($value); - $value = $value[$this->em->getClassMetadata($sourceClass->associationMappings[$field]->targetEntity)->identifier[0]]; - } - - $criteria[$tableAlias . '.' . $targetKeyColumn] = $value; - $parameters[] = [ - 'value' => $value, - 'field' => $field, - 'class' => $sourceClass, - ]; - - continue; - } - - $field = $sourceClass->fieldNames[$sourceKeyColumn]; - $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); - - $criteria[$tableAlias . '.' . $targetKeyColumn] = $value; - $parameters[] = [ - 'value' => $value, - 'field' => $field, - 'class' => $sourceClass, - ]; - } - - $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset); - [$params, $types] = $this->expandToManyParameters($parameters); - - return $this->conn->executeQuery($sql, $params, $types); - } - - /** - * {@inheritDoc} - */ - public function expandParameters(array $criteria): array - { - $params = []; - $types = []; - - foreach ($criteria as $field => $value) { - if ($value === null) { - continue; // skip null values. - } - - $types = [...$types, ...$this->getTypes($field, $value, $this->class)]; - $params = array_merge($params, $this->getValues($value)); - } - - return [$params, $types]; - } - - /** - * Expands the parameters from the given criteria and use the correct binding types if found, - * specialized for OneToMany or ManyToMany associations. - * - * @param mixed[][] $criteria an array of arrays containing following: - * - field to which each criterion will be bound - * - value to be bound - * - class to which the field belongs to - * - * @return mixed[][] - * @psalm-return array{0: array, 1: list} - */ - private function expandToManyParameters(array $criteria): array - { - $params = []; - $types = []; - - foreach ($criteria as $criterion) { - if ($criterion['value'] === null) { - continue; // skip null values. - } - - $types = [...$types, ...$this->getTypes($criterion['field'], $criterion['value'], $criterion['class'])]; - $params = array_merge($params, $this->getValues($criterion['value'])); - } - - return [$params, $types]; - } - - /** - * Infers field types to be used by parameter type casting. - * - * @return list - * @psalm-return list - * - * @throws QueryException - */ - private function getTypes(string $field, mixed $value, ClassMetadata $class): array - { - $types = []; - - switch (true) { - case isset($class->fieldMappings[$field]): - $types = array_merge($types, [$class->fieldMappings[$field]->type]); - break; - - case isset($class->associationMappings[$field]): - $assoc = $this->em->getMetadataFactory()->getOwningSide($class->associationMappings[$field]); - $class = $this->em->getClassMetadata($assoc->targetEntity); - - if ($assoc->isManyToManyOwningSide()) { - $columns = $assoc->relationToTargetKeyColumns; - } else { - assert($assoc->isToOneOwningSide()); - $columns = $assoc->sourceToTargetKeyColumns; - } - - foreach ($columns as $column) { - $types[] = PersisterHelper::getTypeOfColumn($column, $class, $this->em); - } - - break; - - default: - $types[] = ParameterType::STRING; - break; - } - - if (is_array($value)) { - return array_map($this->getArrayBindingType(...), $types); - } - - return $types; - } - - /** @psalm-return ArrayParameterType::* */ - private function getArrayBindingType(ParameterType|int|string $type): ArrayParameterType|int - { - if (! $type instanceof ParameterType) { - $type = Type::getType((string) $type)->getBindingType(); - } - - return match ($type) { - ParameterType::STRING => ArrayParameterType::STRING, - ParameterType::INTEGER => ArrayParameterType::INTEGER, - ParameterType::ASCII => ArrayParameterType::ASCII, - }; - } - - /** - * Retrieves the parameters that identifies a value. - * - * @return mixed[] - */ - private function getValues(mixed $value): array - { - if (is_array($value)) { - $newValue = []; - - foreach ($value as $itemValue) { - $newValue = array_merge($newValue, $this->getValues($itemValue)); - } - - return [$newValue]; - } - - return $this->getIndividualValue($value); - } - - /** - * Retrieves an individual parameter value. - * - * @psalm-return list - */ - private function getIndividualValue(mixed $value): array - { - if (! is_object($value)) { - return [$value]; - } - - if ($value instanceof BackedEnum) { - return [$value->value]; - } - - $valueClass = DefaultProxyClassNameResolver::getClass($value); - - if ($this->em->getMetadataFactory()->isTransient($valueClass)) { - return [$value]; - } - - $class = $this->em->getClassMetadata($valueClass); - - if ($class->isIdentifierComposite) { - $newValue = []; - - foreach ($class->getIdentifierValues($value) as $innerValue) { - $newValue = array_merge($newValue, $this->getValues($innerValue)); - } - - return $newValue; - } - - return [$this->em->getUnitOfWork()->getSingleIdentifierValue($value)]; - } - - public function exists(object $entity, Criteria|null $extraConditions = null): bool - { - $criteria = $this->class->getIdentifierValues($entity); - - if (! $criteria) { - return false; - } - - $alias = $this->getSQLTableAlias($this->class->name); - - $sql = 'SELECT 1 ' - . $this->getLockTablesSql(LockMode::NONE) - . ' WHERE ' . $this->getSelectConditionSQL($criteria); - - [$params, $types] = $this->expandParameters($criteria); - - if ($extraConditions !== null) { - $sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions); - [$criteriaParams, $criteriaTypes] = $this->expandCriteriaParameters($extraConditions); - - $params = [...$params, ...$criteriaParams]; - $types = [...$types, ...$criteriaTypes]; - } - - $filterSql = $this->generateFilterConditionSQL($this->class, $alias); - if ($filterSql) { - $sql .= ' AND ' . $filterSql; - } - - return (bool) $this->conn->fetchOne($sql, $params, $types); - } - - /** - * Generates the appropriate join SQL for the given join column. - * - * @param list $joinColumns The join columns definition of an association. - * - * @return string LEFT JOIN if one of the columns is nullable, INNER JOIN otherwise. - */ - protected function getJoinSQLForJoinColumns(array $joinColumns): string - { - // if one of the join columns is nullable, return left join - foreach ($joinColumns as $joinColumn) { - if (! isset($joinColumn->nullable) || $joinColumn->nullable) { - return 'LEFT JOIN'; - } - } - - return 'INNER JOIN'; - } - - public function getSQLColumnAlias(string $columnName): string - { - return $this->quoteStrategy->getColumnAlias($columnName, $this->currentPersisterContext->sqlAliasCounter++, $this->platform); - } - - /** - * Generates the filter SQL for a given entity and table alias. - * - * @param ClassMetadata $targetEntity Metadata of the target entity. - * @param string $targetTableAlias The table alias of the joined/selected table. - * - * @return string The SQL query part to add to a query. - */ - protected function generateFilterConditionSQL(ClassMetadata $targetEntity, string $targetTableAlias): string - { - $filterClauses = []; - - foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { - $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias); - if ($filterExpr !== '') { - $filterClauses[] = '(' . $filterExpr . ')'; - } - } - - $sql = implode(' AND ', $filterClauses); - - return $sql ? '(' . $sql . ')' : ''; // Wrap again to avoid "X or Y and FilterConditionSQL" - } - - /** - * Switches persister context according to current query offset/limits - * - * This is due to the fact that to-many associations cannot be fetch-joined when a limit is involved - */ - protected function switchPersisterContext(int|null $offset, int|null $limit): void - { - if ($offset === null && $limit === null) { - $this->currentPersisterContext = $this->noLimitsContext; - - return; - } - - $this->currentPersisterContext = $this->limitsHandlingContext; - } - - /** - * @return string[] - * @psalm-return list - */ - protected function getClassIdentifiersTypes(ClassMetadata $class): array - { - $entityManager = $this->em; - - return array_map( - static function ($fieldName) use ($class, $entityManager): string { - $types = PersisterHelper::getTypeOfField($fieldName, $class, $entityManager); - assert(isset($types[0])); - - return $types[0]; - }, - $class->identifier, - ); - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/CachedPersisterContext.php b/vendor/doctrine/orm/src/Persisters/Entity/CachedPersisterContext.php deleted file mode 100644 index 03d053b..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/CachedPersisterContext.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ - public array $sqlTableAliases = []; - - public function __construct( - /** - * Metadata object that describes the mapping of the mapped entity class. - */ - public ClassMetadata $class, - /** - * ResultSetMapping that is used for all queries. Is generated lazily once per request. - */ - public ResultSetMapping $rsm, - /** - * Whether this persistent context is considering limit operations applied to the selection queries - */ - public bool $handlesLimits, - ) { - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/EntityPersister.php b/vendor/doctrine/orm/src/Persisters/Entity/EntityPersister.php deleted file mode 100644 index 6b278a7..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/EntityPersister.php +++ /dev/null @@ -1,298 +0,0 @@ -, list} - */ - public function expandParameters(array $criteria): array; - - /** - * Expands Criteria Parameters by walking the expressions and grabbing all parameters and types from it. - * - * @psalm-return array{list, list} - */ - public function expandCriteriaParameters(Criteria $criteria): array; - - /** Gets the SQL WHERE condition for matching a field with a given value. */ - public function getSelectConditionStatementSQL( - string $field, - mixed $value, - AssociationMapping|null $assoc = null, - string|null $comparison = null, - ): string; - - /** - * Adds an entity to the queued insertions. - * The entity remains queued until {@link executeInserts} is invoked. - */ - public function addInsert(object $entity): void; - - /** - * Executes all queued entity insertions. - * - * If no inserts are queued, invoking this method is a NOOP. - */ - public function executeInserts(): void; - - /** - * Updates a managed entity. The entity is updated according to its current changeset - * in the running UnitOfWork. If there is no changeset, nothing is updated. - */ - public function update(object $entity): void; - - /** - * Deletes a managed entity. - * - * The entity to delete must be managed and have a persistent identifier. - * The deletion happens instantaneously. - * - * Subclasses may override this method to customize the semantics of entity deletion. - * - * @return bool TRUE if the entity got deleted in the database, FALSE otherwise. - */ - public function delete(object $entity): bool; - - /** - * Count entities (optionally filtered by a criteria) - * - * @param mixed[]|Criteria $criteria - */ - public function count(array|Criteria $criteria = []): int; - - /** - * Gets the name of the table that owns the column the given field is mapped to. - * - * The default implementation in BasicEntityPersister always returns the name - * of the table the entity type of this persister is mapped to, since an entity - * is always persisted to a single table with a BasicEntityPersister. - */ - public function getOwningTable(string $fieldName): string; - - /** - * Loads an entity by a list of field criteria. - * - * @param mixed[] $criteria The criteria by which to load the entity. - * @param object|null $entity The entity to load the data into. If not specified, - * a new entity is created. - * @param AssociationMapping|null $assoc The association that connects the entity - * to load to another entity, if any. - * @param mixed[] $hints Hints for entity creation. - * @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants - * or NULL if no specific lock mode should be used - * for loading the entity. - * @param int|null $limit Limit number of results. - * @param string[]|null $orderBy Criteria to order by. - * @psalm-param array $criteria - * @psalm-param array $hints - * @psalm-param LockMode::*|null $lockMode - * @psalm-param array|null $orderBy - * - * @return object|null The loaded and managed entity instance or NULL if the entity can not be found. - * - * @todo Check identity map? loadById method? Try to guess whether $criteria is the id? - */ - public function load( - array $criteria, - object|null $entity = null, - AssociationMapping|null $assoc = null, - array $hints = [], - LockMode|int|null $lockMode = null, - int|null $limit = null, - array|null $orderBy = null, - ): object|null; - - /** - * Loads an entity by identifier. - * - * @param object|null $entity The entity to load the data into. If not specified, a new entity is created. - * @psalm-param array $identifier The entity identifier. - * - * @return object|null The loaded and managed entity instance or NULL if the entity can not be found. - * - * @todo Check parameters - */ - public function loadById(array $identifier, object|null $entity = null): object|null; - - /** - * Loads an entity of this persister's mapped class as part of a single-valued - * association from another entity. - * - * @param AssociationMapping $assoc The association to load. - * @param object $sourceEntity The entity that owns the association (not necessarily the "owning side"). - * @psalm-param array $identifier The identifier of the entity to load. Must be provided if - * the association to load represents the owning side, otherwise - * the identifier is derived from the $sourceEntity. - * - * @return object|null The loaded and managed entity instance or NULL if the entity can not be found. - * - * @throws MappingException - */ - public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null; - - /** - * Refreshes a managed entity. - * - * @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants - * or NULL if no specific lock mode should be used - * for refreshing the managed entity. - * @psalm-param array $id The identifier of the entity as an - * associative array from column or - * field names to values. - * @psalm-param LockMode::*|null $lockMode - */ - public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void; - - /** - * Loads Entities matching the given Criteria object. - * - * @return mixed[] - */ - public function loadCriteria(Criteria $criteria): array; - - /** - * Loads a list of entities by a list of field criteria. - * - * @psalm-param array|null $orderBy - * @psalm-param array $criteria - * - * @return mixed[] - */ - public function loadAll( - array $criteria = [], - array|null $orderBy = null, - int|null $limit = null, - int|null $offset = null, - ): array; - - /** - * Gets (sliced or full) elements of the given collection. - * - * @return mixed[] - */ - public function getManyToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array; - - /** - * Loads a collection of entities of a many-to-many association. - * - * @param AssociationMapping $assoc The association mapping of the association being loaded. - * @param object $sourceEntity The entity that owns the collection. - * @param PersistentCollection $collection The collection to fill. - * - * @return mixed[] - */ - public function loadManyToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - PersistentCollection $collection, - ): array; - - /** - * Loads a collection of entities in a one-to-many association. - * - * @param PersistentCollection $collection The collection to load/fill. - */ - public function loadOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - PersistentCollection $collection, - ): mixed; - - /** - * Locks all rows of this entity matching the given criteria with the specified pessimistic lock mode. - * - * @psalm-param array $criteria - * @psalm-param LockMode::* $lockMode - */ - public function lock(array $criteria, LockMode|int $lockMode): void; - - /** - * Returns an array with (sliced or full list) of elements in the specified collection. - * - * @return mixed[] - */ - public function getOneToManyCollection( - AssociationMapping $assoc, - object $sourceEntity, - int|null $offset = null, - int|null $limit = null, - ): array; - - /** - * Checks whether the given managed entity exists in the database. - */ - public function exists(object $entity, Criteria|null $extraConditions = null): bool; -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/JoinedSubclassPersister.php b/vendor/doctrine/orm/src/Persisters/Entity/JoinedSubclassPersister.php deleted file mode 100644 index 76719a2..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/JoinedSubclassPersister.php +++ /dev/null @@ -1,601 +0,0 @@ -Class Table Inheritance strategy. - * - * @see https://martinfowler.com/eaaCatalog/classTableInheritance.html - */ -class JoinedSubclassPersister extends AbstractEntityInheritancePersister -{ - use LockSqlHelper; - use SQLResultCasing; - - /** - * Map that maps column names to the table names that own them. - * This is mainly a temporary cache, used during a single request. - * - * @psalm-var array - */ - private array $owningTableMap = []; - - /** - * Map of table to quoted table names. - * - * @psalm-var array - */ - private array $quotedTableMap = []; - - protected function getDiscriminatorColumnTableName(): string - { - $class = $this->class->name !== $this->class->rootEntityName - ? $this->em->getClassMetadata($this->class->rootEntityName) - : $this->class; - - return $class->getTableName(); - } - - /** - * This function finds the ClassMetadata instance in an inheritance hierarchy - * that is responsible for enabling versioning. - */ - private function getVersionedClassMetadata(): ClassMetadata - { - if (isset($this->class->fieldMappings[$this->class->versionField]->inherited)) { - $definingClassName = $this->class->fieldMappings[$this->class->versionField]->inherited; - - return $this->em->getClassMetadata($definingClassName); - } - - return $this->class; - } - - /** - * Gets the name of the table that owns the column the given field is mapped to. - */ - public function getOwningTable(string $fieldName): string - { - if (isset($this->owningTableMap[$fieldName])) { - return $this->owningTableMap[$fieldName]; - } - - $cm = match (true) { - isset($this->class->associationMappings[$fieldName]->inherited) - => $this->em->getClassMetadata($this->class->associationMappings[$fieldName]->inherited), - isset($this->class->fieldMappings[$fieldName]->inherited) - => $this->em->getClassMetadata($this->class->fieldMappings[$fieldName]->inherited), - default => $this->class, - }; - - $tableName = $cm->getTableName(); - $quotedTableName = $this->quoteStrategy->getTableName($cm, $this->platform); - - $this->owningTableMap[$fieldName] = $tableName; - $this->quotedTableMap[$tableName] = $quotedTableName; - - return $tableName; - } - - public function executeInserts(): void - { - if (! $this->queuedInserts) { - return; - } - - $uow = $this->em->getUnitOfWork(); - $idGenerator = $this->class->idGenerator; - $isPostInsertId = $idGenerator->isPostInsertGenerator(); - $rootClass = $this->class->name !== $this->class->rootEntityName - ? $this->em->getClassMetadata($this->class->rootEntityName) - : $this->class; - - // Prepare statement for the root table - $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->name); - $rootTableName = $rootClass->getTableName(); - $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL()); - - // Prepare statements for sub tables. - $subTableStmts = []; - - if ($rootClass !== $this->class) { - $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL()); - } - - foreach ($this->class->parentClasses as $parentClassName) { - $parentClass = $this->em->getClassMetadata($parentClassName); - $parentTableName = $parentClass->getTableName(); - - if ($parentClass !== $rootClass) { - $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClassName); - $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL()); - } - } - - // Execute all inserts. For each entity: - // 1) Insert on root table - // 2) Insert on sub tables - foreach ($this->queuedInserts as $entity) { - $insertData = $this->prepareInsertData($entity); - - // Execute insert on root table - $paramIndex = 1; - - foreach ($insertData[$rootTableName] as $columnName => $value) { - $rootTableStmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]); - } - - $rootTableStmt->executeStatement(); - - if ($isPostInsertId) { - $generatedId = $idGenerator->generateId($this->em, $entity); - $id = [$this->class->identifier[0] => $generatedId]; - - $uow->assignPostInsertId($entity, $generatedId); - } else { - $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - } - - // Execute inserts on subtables. - // The order doesn't matter because all child tables link to the root table via FK. - foreach ($subTableStmts as $tableName => $stmt) { - $paramIndex = 1; - $data = $insertData[$tableName] ?? []; - - foreach ($id as $idName => $idVal) { - $type = $this->columnTypes[$idName] ?? Types::STRING; - - $stmt->bindValue($paramIndex++, $idVal, $type); - } - - foreach ($data as $columnName => $value) { - if (! isset($id[$columnName])) { - $stmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]); - } - } - - $stmt->executeStatement(); - } - - if ($this->class->requiresFetchAfterChange) { - $this->assignDefaultVersionAndUpsertableValues($entity, $id); - } - } - - $this->queuedInserts = []; - } - - public function update(object $entity): void - { - $updateData = $this->prepareUpdateData($entity); - - if (! $updateData) { - return; - } - - $isVersioned = $this->class->isVersioned; - - $versionedClass = $this->getVersionedClassMetadata(); - $versionedTable = $versionedClass->getTableName(); - - foreach ($updateData as $tableName => $data) { - $tableName = $this->quotedTableMap[$tableName]; - $versioned = $isVersioned && $versionedTable === $tableName; - - $this->updateTable($entity, $tableName, $data, $versioned); - } - - if ($this->class->requiresFetchAfterChange) { - // Make sure the table with the version column is updated even if no columns on that - // table were affected. - if ($isVersioned && ! isset($updateData[$versionedTable])) { - $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); - - $this->updateTable($entity, $tableName, [], true); - } - - $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - - $this->assignDefaultVersionAndUpsertableValues($entity, $identifiers); - } - } - - public function delete(object $entity): bool - { - $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - $id = array_combine($this->class->getIdentifierColumnNames(), $identifier); - $types = $this->getClassIdentifiersTypes($this->class); - - $this->deleteJoinTableRecords($identifier, $types); - - // Delete the row from the root table. Cascades do the rest. - $rootClass = $this->em->getClassMetadata($this->class->rootEntityName); - $rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform); - $rootTypes = $this->getClassIdentifiersTypes($rootClass); - - return (bool) $this->conn->delete($rootTable, $id, $rootTypes); - } - - public function getSelectSQL( - array|Criteria $criteria, - AssociationMapping|null $assoc = null, - LockMode|int|null $lockMode = null, - int|null $limit = null, - int|null $offset = null, - array|null $orderBy = null, - ): string { - $this->switchPersisterContext($offset, $limit); - - $baseTableAlias = $this->getSQLTableAlias($this->class->name); - $joinSql = $this->getJoinSql($baseTableAlias); - - if ($assoc !== null && $assoc->isManyToMany()) { - $joinSql .= $this->getSelectManyToManyJoinSQL($assoc); - } - - $conditionSql = $criteria instanceof Criteria - ? $this->getSelectConditionCriteriaSQL($criteria) - : $this->getSelectConditionSQL($criteria, $assoc); - - $filterSql = $this->generateFilterConditionSQL( - $this->em->getClassMetadata($this->class->rootEntityName), - $this->getSQLTableAlias($this->class->rootEntityName), - ); - // If the current class in the root entity, add the filters - if ($filterSql) { - $conditionSql .= $conditionSql - ? ' AND ' . $filterSql - : $filterSql; - } - - $orderBySql = ''; - - if ($assoc !== null && $assoc->isOrdered()) { - $orderBy = $assoc->orderBy(); - } - - if ($orderBy) { - $orderBySql = $this->getOrderBySQL($orderBy, $baseTableAlias); - } - - $lockSql = ''; - - switch ($lockMode) { - case LockMode::PESSIMISTIC_READ: - $lockSql = ' ' . $this->getReadLockSQL($this->platform); - - break; - - case LockMode::PESSIMISTIC_WRITE: - $lockSql = ' ' . $this->getWriteLockSQL($this->platform); - - break; - } - - $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - $from = ' FROM ' . $tableName . ' ' . $baseTableAlias; - $where = $conditionSql !== '' ? ' WHERE ' . $conditionSql : ''; - $lock = $this->platform->appendLockHint($from, $lockMode ?? LockMode::NONE); - $columnList = $this->getSelectColumnsSQL(); - $query = 'SELECT ' . $columnList - . $lock - . $joinSql - . $where - . $orderBySql; - - return $this->platform->modifyLimitQuery($query, $limit, $offset ?? 0) . $lockSql; - } - - public function getCountSQL(array|Criteria $criteria = []): string - { - $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); - $baseTableAlias = $this->getSQLTableAlias($this->class->name); - $joinSql = $this->getJoinSql($baseTableAlias); - - $conditionSql = $criteria instanceof Criteria - ? $this->getSelectConditionCriteriaSQL($criteria) - : $this->getSelectConditionSQL($criteria); - - $filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName)); - - if ($filterSql !== '') { - $conditionSql = $conditionSql - ? $conditionSql . ' AND ' . $filterSql - : $filterSql; - } - - return 'SELECT COUNT(*) ' - . 'FROM ' . $tableName . ' ' . $baseTableAlias - . $joinSql - . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql); - } - - protected function getLockTablesSql(LockMode|int $lockMode): string - { - $joinSql = ''; - $identifierColumns = $this->class->getIdentifierColumnNames(); - $baseTableAlias = $this->getSQLTableAlias($this->class->name); - - // INNER JOIN parent tables - foreach ($this->class->parentClasses as $parentClassName) { - $conditions = []; - $tableAlias = $this->getSQLTableAlias($parentClassName); - $parentClass = $this->em->getClassMetadata($parentClassName); - $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON '; - - foreach ($identifierColumns as $idColumn) { - $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; - } - - $joinSql .= implode(' AND ', $conditions); - } - - return parent::getLockTablesSql($lockMode) . $joinSql; - } - - /** - * Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly. - */ - protected function getSelectColumnsSQL(): string - { - // Create the column list fragment only once - if ($this->currentPersisterContext->selectColumnListSql !== null) { - return $this->currentPersisterContext->selectColumnListSql; - } - - $columnList = []; - $discrColumn = $this->class->getDiscriminatorColumn(); - $discrColumnName = $discrColumn->name; - $discrColumnType = $discrColumn->type; - $baseTableAlias = $this->getSQLTableAlias($this->class->name); - $resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName); - - $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r'); - $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType); - - // Add regular columns - foreach ($this->class->fieldMappings as $fieldName => $mapping) { - $class = isset($mapping->inherited) - ? $this->em->getClassMetadata($mapping->inherited) - : $this->class; - - $columnList[] = $this->getSelectColumnSQL($fieldName, $class); - } - - // Add foreign key columns - foreach ($this->class->associationMappings as $mapping) { - if (! $mapping->isToOneOwningSide()) { - continue; - } - - $tableAlias = isset($mapping->inherited) - ? $this->getSQLTableAlias($mapping->inherited) - : $baseTableAlias; - - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - - foreach ($mapping->joinColumns as $joinColumn) { - $columnList[] = $this->getSelectJoinColumnSQL( - $tableAlias, - $joinColumn->name, - $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform), - PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em), - ); - } - } - - // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult). - $tableAlias = $this->class->rootEntityName === $this->class->name - ? $baseTableAlias - : $this->getSQLTableAlias($this->class->rootEntityName); - - $columnList[] = $tableAlias . '.' . $discrColumnName; - - // sub tables - foreach ($this->class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - $tableAlias = $this->getSQLTableAlias($subClassName); - - // Add subclass columns - foreach ($subClass->fieldMappings as $fieldName => $mapping) { - if (isset($mapping->inherited)) { - continue; - } - - $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass); - } - - // Add join columns (foreign keys) - foreach ($subClass->associationMappings as $mapping) { - if (! $mapping->isToOneOwningSide() || isset($mapping->inherited)) { - continue; - } - - $targetClass = $this->em->getClassMetadata($mapping->targetEntity); - - foreach ($mapping->joinColumns as $joinColumn) { - $columnList[] = $this->getSelectJoinColumnSQL( - $tableAlias, - $joinColumn->name, - $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform), - PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em), - ); - } - } - } - - $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - - return $this->currentPersisterContext->selectColumnListSql; - } - - /** - * {@inheritDoc} - */ - protected function getInsertColumnList(): array - { - // Identifier columns must always come first in the column list of subclasses. - $columns = $this->class->parentClasses - ? $this->class->getIdentifierColumnNames() - : []; - - foreach ($this->class->reflFields as $name => $field) { - if ( - isset($this->class->fieldMappings[$name]->inherited) - && ! isset($this->class->fieldMappings[$name]->id) - || isset($this->class->associationMappings[$name]->inherited) - || ($this->class->isVersioned && $this->class->versionField === $name) - || isset($this->class->embeddedClasses[$name]) - || isset($this->class->fieldMappings[$name]->notInsertable) - ) { - continue; - } - - if (isset($this->class->associationMappings[$name])) { - $assoc = $this->class->associationMappings[$name]; - if ($assoc->isToOneOwningSide()) { - foreach ($assoc->targetToSourceKeyColumns as $sourceCol) { - $columns[] = $sourceCol; - } - } - } elseif ( - $this->class->name !== $this->class->rootEntityName || - ! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] !== $name - ) { - $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); - $this->columnTypes[$name] = $this->class->fieldMappings[$name]->type; - } - } - - // Add discriminator column if it is the topmost class. - if ($this->class->name === $this->class->rootEntityName) { - $columns[] = $this->class->getDiscriminatorColumn()->name; - } - - return $columns; - } - - /** - * {@inheritDoc} - */ - protected function assignDefaultVersionAndUpsertableValues(object $entity, array $id): void - { - $values = $this->fetchVersionAndNotUpsertableValues($this->getVersionedClassMetadata(), $id); - - foreach ($values as $field => $value) { - $value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform); - - $this->class->setFieldValue($entity, $field, $value); - } - } - - /** - * {@inheritDoc} - */ - protected function fetchVersionAndNotUpsertableValues(ClassMetadata $versionedClass, array $id): mixed - { - $columnNames = []; - foreach ($this->class->fieldMappings as $key => $column) { - $class = null; - if ($this->class->isVersioned && $key === $versionedClass->versionField) { - $class = $versionedClass; - } elseif (isset($column->generated)) { - $class = isset($column->inherited) - ? $this->em->getClassMetadata($column->inherited) - : $this->class; - } else { - continue; - } - - $columnNames[$key] = $this->getSelectColumnSQL($key, $class); - } - - $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); - $baseTableAlias = $this->getSQLTableAlias($this->class->name); - $joinSql = $this->getJoinSql($baseTableAlias); - $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform); - foreach ($identifier as $i => $idValue) { - $identifier[$i] = $baseTableAlias . '.' . $idValue; - } - - $sql = 'SELECT ' . implode(', ', $columnNames) - . ' FROM ' . $tableName . ' ' . $baseTableAlias - . $joinSql - . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; - - $flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id); - $values = $this->conn->fetchNumeric( - $sql, - array_values($flatId), - $this->extractIdentifierTypes($id, $versionedClass), - ); - - if ($values === false) { - throw new LengthException('Unexpected empty result for database query.'); - } - - $values = array_combine(array_keys($columnNames), $values); - - if (! $values) { - throw new LengthException('Unexpected number of database columns.'); - } - - return $values; - } - - private function getJoinSql(string $baseTableAlias): string - { - $joinSql = ''; - $identifierColumn = $this->class->getIdentifierColumnNames(); - - // INNER JOIN parent tables - foreach ($this->class->parentClasses as $parentClassName) { - $conditions = []; - $parentClass = $this->em->getClassMetadata($parentClassName); - $tableAlias = $this->getSQLTableAlias($parentClassName); - $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON '; - - foreach ($identifierColumn as $idColumn) { - $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; - } - - $joinSql .= implode(' AND ', $conditions); - } - - // OUTER JOIN sub tables - foreach ($this->class->subClasses as $subClassName) { - $conditions = []; - $subClass = $this->em->getClassMetadata($subClassName); - $tableAlias = $this->getSQLTableAlias($subClassName); - $joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON '; - - foreach ($identifierColumn as $idColumn) { - $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; - } - - $joinSql .= implode(' AND ', $conditions); - } - - return $joinSql; - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Entity/SingleTablePersister.php b/vendor/doctrine/orm/src/Persisters/Entity/SingleTablePersister.php deleted file mode 100644 index 4a4d999..0000000 --- a/vendor/doctrine/orm/src/Persisters/Entity/SingleTablePersister.php +++ /dev/null @@ -1,166 +0,0 @@ -class->getTableName(); - } - - protected function getSelectColumnsSQL(): string - { - $columnList = []; - if ($this->currentPersisterContext->selectColumnListSql !== null) { - return $this->currentPersisterContext->selectColumnListSql; - } - - $columnList[] = parent::getSelectColumnsSQL(); - - $rootClass = $this->em->getClassMetadata($this->class->rootEntityName); - $tableAlias = $this->getSQLTableAlias($rootClass->name); - - // Append discriminator column - $discrColumn = $this->class->getDiscriminatorColumn(); - $discrColumnName = $discrColumn->name; - $discrColumnType = $discrColumn->type; - - $columnList[] = $tableAlias . '.' . $discrColumnName; - - $resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName); - - $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType); - - // Append subclass columns - foreach ($this->class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - - // Regular columns - foreach ($subClass->fieldMappings as $fieldName => $mapping) { - if (isset($mapping->inherited)) { - continue; - } - - $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass); - } - - // Foreign key columns - foreach ($subClass->associationMappings as $assoc) { - if (! $assoc->isToOneOwningSide() || isset($assoc->inherited)) { - continue; - } - - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - foreach ($assoc->joinColumns as $joinColumn) { - $columnList[] = $this->getSelectJoinColumnSQL( - $tableAlias, - $joinColumn->name, - $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform), - PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em), - ); - } - } - } - - $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - - return $this->currentPersisterContext->selectColumnListSql; - } - - /** - * {@inheritDoc} - */ - protected function getInsertColumnList(): array - { - $columns = parent::getInsertColumnList(); - - // Add discriminator column to the INSERT SQL - $columns[] = $this->class->getDiscriminatorColumn()->name; - - return $columns; - } - - protected function getSQLTableAlias(string $className, string $assocName = ''): string - { - return parent::getSQLTableAlias($this->class->rootEntityName, $assocName); - } - - /** - * {@inheritDoc} - */ - protected function getSelectConditionSQL(array $criteria, AssociationMapping|null $assoc = null): string - { - $conditionSql = parent::getSelectConditionSQL($criteria, $assoc); - - if ($conditionSql) { - $conditionSql .= ' AND '; - } - - return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL(); - } - - protected function getSelectConditionCriteriaSQL(Criteria $criteria): string - { - $conditionSql = parent::getSelectConditionCriteriaSQL($criteria); - - if ($conditionSql) { - $conditionSql .= ' AND '; - } - - return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL(); - } - - protected function getSelectConditionDiscriminatorValueSQL(): string - { - $values = array_map($this->conn->quote(...), array_map( - strval(...), - array_flip(array_intersect($this->class->discriminatorMap, $this->class->subClasses)), - )); - - if ($this->class->discriminatorValue !== null) { // discriminators can be 0 - array_unshift($values, $this->conn->quote((string) $this->class->discriminatorValue)); - } - - $discColumnName = $this->class->getDiscriminatorColumn()->name; - - $values = implode(', ', $values); - $tableAlias = $this->getSQLTableAlias($this->class->name); - - return $tableAlias . '.' . $discColumnName . ' IN (' . $values . ')'; - } - - protected function generateFilterConditionSQL(ClassMetadata $targetEntity, string $targetTableAlias): string - { - // Ensure that the filters are applied to the root entity of the inheritance tree - $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName); - // we don't care about the $targetTableAlias, in a STI there is only one table. - - return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias); - } -} diff --git a/vendor/doctrine/orm/src/Persisters/Exception/CantUseInOperatorOnCompositeKeys.php b/vendor/doctrine/orm/src/Persisters/Exception/CantUseInOperatorOnCompositeKeys.php deleted file mode 100644 index 5c91312..0000000 --- a/vendor/doctrine/orm/src/Persisters/Exception/CantUseInOperatorOnCompositeKeys.php +++ /dev/null @@ -1,15 +0,0 @@ -getField(); - $value = $comparison->getValue()->getValue(); // shortcut for walkValue() - - if ( - isset($this->classMetadata->associationMappings[$field]) && - $value !== null && - ! is_object($value) && - ! in_array($comparison->getOperator(), [Comparison::IN, Comparison::NIN], true) - ) { - throw MatchingAssociationFieldRequiresObject::fromClassAndAssociation( - $this->classMetadata->name, - $field, - ); - } - - return $this->persister->getSelectConditionStatementSQL($field, $value, null, $comparison->getOperator()); - } - - /** - * Converts a composite expression into the target query language output. - * - * @throws RuntimeException - */ - public function walkCompositeExpression(CompositeExpression $expr): string - { - $expressionList = []; - - foreach ($expr->getExpressionList() as $child) { - $expressionList[] = $this->dispatch($child); - } - - return match ($expr->getType()) { - CompositeExpression::TYPE_AND => '(' . implode(' AND ', $expressionList) . ')', - CompositeExpression::TYPE_OR => '(' . implode(' OR ', $expressionList) . ')', - CompositeExpression::TYPE_NOT => 'NOT (' . $expressionList[0] . ')', - default => throw new RuntimeException('Unknown composite ' . $expr->getType()), - }; - } - - /** - * Converts a value expression into the target query language part. - */ - public function walkValue(Value $value): string - { - return '?'; - } -} diff --git a/vendor/doctrine/orm/src/Persisters/SqlValueVisitor.php b/vendor/doctrine/orm/src/Persisters/SqlValueVisitor.php deleted file mode 100644 index 7f987ad..0000000 --- a/vendor/doctrine/orm/src/Persisters/SqlValueVisitor.php +++ /dev/null @@ -1,88 +0,0 @@ -getValueFromComparison($comparison); - - $this->values[] = $value; - $this->types[] = [$comparison->getField(), $value, $comparison->getOperator()]; - - return null; - } - - /** - * Converts a composite expression into the target query language output. - * - * {@inheritDoc} - */ - public function walkCompositeExpression(CompositeExpression $expr) - { - foreach ($expr->getExpressionList() as $child) { - $this->dispatch($child); - } - - return null; - } - - /** - * Converts a value expression into the target query language part. - * - * {@inheritDoc} - */ - public function walkValue(Value $value) - { - return null; - } - - /** - * Returns the Parameters and Types necessary for matching the last visited expression. - * - * @return mixed[][] - * @psalm-return array{0: array, 1: array>} - */ - public function getParamsAndTypes(): array - { - return [$this->values, $this->types]; - } - - /** - * Returns the value from a Comparison. In case of a CONTAINS comparison, - * the value is wrapped in %-signs, because it will be used in a LIKE clause. - */ - protected function getValueFromComparison(Comparison $comparison): mixed - { - $value = $comparison->getValue()->getValue(); - - return match ($comparison->getOperator()) { - Comparison::CONTAINS => '%' . $value . '%', - Comparison::STARTS_WITH => $value . '%', - Comparison::ENDS_WITH => '%' . $value, - default => $value, - }; - } -} diff --git a/vendor/doctrine/orm/src/PessimisticLockException.php b/vendor/doctrine/orm/src/PessimisticLockException.php deleted file mode 100644 index c71560f..0000000 --- a/vendor/doctrine/orm/src/PessimisticLockException.php +++ /dev/null @@ -1,16 +0,0 @@ -resolveClassName($object::class); - } -} diff --git a/vendor/doctrine/orm/src/Proxy/InternalProxy.php b/vendor/doctrine/orm/src/Proxy/InternalProxy.php deleted file mode 100644 index 7c1d833..0000000 --- a/vendor/doctrine/orm/src/Proxy/InternalProxy.php +++ /dev/null @@ -1,18 +0,0 @@ - - */ -interface InternalProxy extends Proxy -{ - public function __setInitialized(bool $initialized): void; -} diff --git a/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php b/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php deleted file mode 100644 index 689cc3e..0000000 --- a/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php +++ /dev/null @@ -1,22 +0,0 @@ -; - -/** - * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR - */ -class extends \ implements \ -{ - - - public function __isInitialized(): bool - { - return isset($this->lazyObjectState) && $this->isLazyObjectInitialized(); - } - - public function __serialize(): array - { - - } -} - -EOPHP; - - /** The UnitOfWork this factory uses to retrieve persisters */ - private readonly UnitOfWork $uow; - - /** @var self::AUTOGENERATE_* */ - private $autoGenerate; - - /** The IdentifierFlattener used for manipulating identifiers */ - private readonly IdentifierFlattener $identifierFlattener; - - /** @var array */ - private array $proxyFactories = []; - - /** - * Initializes a new instance of the ProxyFactory class that is - * connected to the given EntityManager. - * - * @param EntityManagerInterface $em The EntityManager the new factory works for. - * @param string $proxyDir The directory to use for the proxy classes. It must exist. - * @param string $proxyNs The namespace to use for the proxy classes. - * @param bool|self::AUTOGENERATE_* $autoGenerate The strategy for automatically generating proxy classes. - */ - public function __construct( - private readonly EntityManagerInterface $em, - private readonly string $proxyDir, - private readonly string $proxyNs, - bool|int $autoGenerate = self::AUTOGENERATE_NEVER, - ) { - if (! $proxyDir) { - throw ORMInvalidArgumentException::proxyDirectoryRequired(); - } - - if (! $proxyNs) { - throw ORMInvalidArgumentException::proxyNamespaceRequired(); - } - - if (is_int($autoGenerate) ? $autoGenerate < 0 || $autoGenerate > 4 : ! is_bool($autoGenerate)) { - throw ORMInvalidArgumentException::invalidAutoGenerateMode($autoGenerate); - } - - $this->uow = $em->getUnitOfWork(); - $this->autoGenerate = (int) $autoGenerate; - $this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory()); - } - - /** - * @param class-string $className - * @param array $identifier - */ - public function getProxy(string $className, array $identifier): InternalProxy - { - $proxyFactory = $this->proxyFactories[$className] ?? $this->getProxyFactory($className); - - return $proxyFactory($identifier); - } - - /** - * Generates proxy classes for all given classes. - * - * @param ClassMetadata[] $classes The classes (ClassMetadata instances) for which to generate proxies. - * @param string|null $proxyDir The target directory of the proxy classes. If not specified, the - * directory configured on the Configuration of the EntityManager used - * by this factory is used. - * - * @return int Number of generated proxies. - */ - public function generateProxyClasses(array $classes, string|null $proxyDir = null): int - { - $generated = 0; - - foreach ($classes as $class) { - if ($this->skipClass($class)) { - continue; - } - - $proxyFileName = $this->getProxyFileName($class->getName(), $proxyDir ?: $this->proxyDir); - $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); - - $this->generateProxyClass($class, $proxyFileName, $proxyClassName); - - ++$generated; - } - - return $generated; - } - - protected function skipClass(ClassMetadata $metadata): bool - { - return $metadata->isMappedSuperclass - || $metadata->isEmbeddedClass - || $metadata->getReflectionClass()->isAbstract(); - } - - /** - * Creates a closure capable of initializing a proxy - * - * @return Closure(InternalProxy, array):void - * - * @throws EntityNotFoundException - */ - private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister, IdentifierFlattener $identifierFlattener): Closure - { - return static function (InternalProxy $proxy, array $identifier) use ($entityPersister, $classMetadata, $identifierFlattener): void { - $original = $entityPersister->loadById($identifier); - - if ($original === null) { - throw EntityNotFoundException::fromClassNameAndIdentifier( - $classMetadata->getName(), - $identifierFlattener->flattenIdentifier($classMetadata, $identifier), - ); - } - - if ($proxy === $original) { - return; - } - - $class = $entityPersister->getClassMetadata(); - - foreach ($class->getReflectionProperties() as $property) { - if (! $property || isset($identifier[$property->getName()]) || ! $class->hasField($property->getName()) && ! $class->hasAssociation($property->getName())) { - continue; - } - - $property->setValue($proxy, $property->getValue($original)); - } - }; - } - - private function getProxyFileName(string $className, string $baseDirectory): string - { - $baseDirectory = $baseDirectory ?: $this->proxyDir; - - return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . InternalProxy::MARKER - . str_replace('\\', '', $className) . '.php'; - } - - private function getProxyFactory(string $className): Closure - { - $skippedProperties = []; - $class = $this->em->getClassMetadata($className); - $identifiers = array_flip($class->getIdentifierFieldNames()); - $filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE; - $reflector = $class->getReflectionClass(); - - while ($reflector) { - foreach ($reflector->getProperties($filter) as $property) { - $name = $property->name; - - if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) { - continue; - } - - $prefix = $property->isPrivate() ? "\0" . $property->class . "\0" : ($property->isProtected() ? "\0*\0" : ''); - - $skippedProperties[$prefix . $name] = true; - } - - $filter = ReflectionProperty::IS_PRIVATE; - $reflector = $reflector->getParentClass(); - } - - $className = $class->getName(); // aliases and case sensitivity - $entityPersister = $this->uow->getEntityPersister($className); - $initializer = $this->createLazyInitializer($class, $entityPersister, $this->identifierFlattener); - $proxyClassName = $this->loadProxyClass($class); - $identifierFields = array_intersect_key($class->getReflectionProperties(), $identifiers); - - $proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className): InternalProxy { - $proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void { - $initializer($object, $identifier); - }, $skippedProperties); - - foreach ($identifierFields as $idField => $reflector) { - if (! isset($identifier[$idField])) { - throw ORMInvalidArgumentException::missingPrimaryKeyValue($className, $idField); - } - - assert($reflector !== null); - $reflector->setValue($proxy, $identifier[$idField]); - } - - return $proxy; - }, null, $proxyClassName); - - return $this->proxyFactories[$className] = $proxyFactory; - } - - private function loadProxyClass(ClassMetadata $class): string - { - $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); - - if (class_exists($proxyClassName, false)) { - return $proxyClassName; - } - - if ($this->autoGenerate === self::AUTOGENERATE_EVAL) { - $this->generateProxyClass($class, null, $proxyClassName); - - return $proxyClassName; - } - - $fileName = $this->getProxyFileName($class->getName(), $this->proxyDir); - - switch ($this->autoGenerate) { - case self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED: - if (file_exists($fileName) && filemtime($fileName) >= filemtime($class->getReflectionClass()->getFileName())) { - break; - } - // no break - case self::AUTOGENERATE_FILE_NOT_EXISTS: - if (file_exists($fileName)) { - break; - } - // no break - case self::AUTOGENERATE_ALWAYS: - $this->generateProxyClass($class, $fileName, $proxyClassName); - break; - } - - require $fileName; - - return $proxyClassName; - } - - private function generateProxyClass(ClassMetadata $class, string|null $fileName, string $proxyClassName): void - { - $i = strrpos($proxyClassName, '\\'); - $placeholders = [ - '' => $class->getName(), - '' => substr($proxyClassName, 0, $i), - '' => substr($proxyClassName, 1 + $i), - '' => InternalProxy::class, - ]; - - preg_match_all('(<([a-zA-Z]+)>)', self::PROXY_CLASS_TEMPLATE, $placeholderMatches); - - foreach (array_combine($placeholderMatches[0], $placeholderMatches[1]) as $placeholder => $name) { - $placeholders[$placeholder] ?? $placeholders[$placeholder] = $this->{'generate' . ucfirst($name)}($class); - } - - $proxyCode = strtr(self::PROXY_CLASS_TEMPLATE, $placeholders); - - if (! $fileName) { - if (! class_exists($proxyClassName)) { - eval(substr($proxyCode, 5)); - } - - return; - } - - $parentDirectory = dirname($fileName); - - if (! is_dir($parentDirectory) && ! @mkdir($parentDirectory, 0775, true)) { - throw ORMInvalidArgumentException::proxyDirectoryNotWritable($this->proxyDir); - } - - if (! is_writable($parentDirectory)) { - throw ORMInvalidArgumentException::proxyDirectoryNotWritable($this->proxyDir); - } - - $tmpFileName = $fileName . '.' . bin2hex(random_bytes(12)); - - file_put_contents($tmpFileName, $proxyCode); - @chmod($tmpFileName, 0664); - rename($tmpFileName, $fileName); - } - - private function generateUseLazyGhostTrait(ClassMetadata $class): string - { - $code = ProxyHelper::generateLazyGhost($class->getReflectionClass()); - $code = substr($code, 7 + (int) strpos($code, "\n{")); - $code = substr($code, 0, (int) strpos($code, "\n}")); - $code = str_replace('LazyGhostTrait;', str_replace("\n ", "\n", 'LazyGhostTrait { - initializeLazyObject as private; - setLazyObjectAsInitialized as public __setInitialized; - isLazyObjectInitialized as private; - createLazyGhost as private; - resetLazyObject as private; - } - - public function __load(): void - { - $this->initializeLazyObject(); - } - '), $code); - - return $code; - } - - private function generateSerializeImpl(ClassMetadata $class): string - { - $reflector = $class->getReflectionClass(); - $properties = $reflector->hasMethod('__serialize') ? 'parent::__serialize()' : '(array) $this'; - - $code = '$properties = ' . $properties . '; - unset($properties["\0" . self::class . "\0lazyObjectState"]); - - '; - - if ($reflector->hasMethod('__serialize') || ! $reflector->hasMethod('__sleep')) { - return $code . 'return $properties;'; - } - - return $code . '$data = []; - - foreach (parent::__sleep() as $name) { - $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0' . $reflector->name . '\0$name"] ?? $k = null; - - if (null === $k) { - trigger_error(sprintf(\'serialize(): "%s" returned as member variable from __sleep() but does not exist\', $name), \E_USER_NOTICE); - } else { - $data[$k] = $value; - } - } - - return $data;'; - } - - private static function generateProxyClassName(string $className, string $proxyNamespace): string - { - return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\'); - } -} diff --git a/vendor/doctrine/orm/src/Query.php b/vendor/doctrine/orm/src/Query.php deleted file mode 100644 index a869316..0000000 --- a/vendor/doctrine/orm/src/Query.php +++ /dev/null @@ -1,682 +0,0 @@ - - */ - private array $parsedTypes = []; - - /** - * Cached DQL query. - */ - private string|null $dql = null; - - /** - * The parser result that holds DQL => SQL information. - */ - private ParserResult $parserResult; - - /** - * The first result to return (the "offset"). - */ - private int $firstResult = 0; - - /** - * The maximum number of results to return (the "limit"). - */ - private int|null $maxResults = null; - - /** - * The cache driver used for caching queries. - */ - private CacheItemPoolInterface|null $queryCache = null; - - /** - * Whether or not expire the query cache. - */ - private bool $expireQueryCache = false; - - /** - * The query cache lifetime. - */ - private int|null $queryCacheTTL = null; - - /** - * Whether to use a query cache, if available. Defaults to TRUE. - */ - private bool $useQueryCache = true; - - /** - * Gets the SQL query/queries that correspond to this DQL query. - * - * @return list|string The built sql query or an array of all sql queries. - */ - public function getSQL(): string|array - { - return $this->parse()->getSqlExecutor()->getSqlStatements(); - } - - /** - * Returns the corresponding AST for this DQL query. - */ - public function getAST(): SelectStatement|UpdateStatement|DeleteStatement - { - $parser = new Parser($this); - - return $parser->getAST(); - } - - protected function getResultSetMapping(): ResultSetMapping - { - // parse query or load from cache - if ($this->resultSetMapping === null) { - $this->resultSetMapping = $this->parse()->getResultSetMapping(); - } - - return $this->resultSetMapping; - } - - /** - * Parses the DQL query, if necessary, and stores the parser result. - * - * Note: Populates $this->_parserResult as a side-effect. - */ - private function parse(): ParserResult - { - $types = []; - - foreach ($this->parameters as $parameter) { - /** @var Query\Parameter $parameter */ - $types[$parameter->getName()] = $parameter->getType(); - } - - // Return previous parser result if the query and the filter collection are both clean - if ($this->state === self::STATE_CLEAN && $this->parsedTypes === $types && $this->em->isFiltersStateClean()) { - return $this->parserResult; - } - - $this->state = self::STATE_CLEAN; - $this->parsedTypes = $types; - - $queryCache = $this->queryCache ?? $this->em->getConfiguration()->getQueryCache(); - // Check query cache. - if (! ($this->useQueryCache && $queryCache)) { - $parser = new Parser($this); - - $this->parserResult = $parser->parse(); - - return $this->parserResult; - } - - $cacheItem = $queryCache->getItem($this->getQueryCacheId()); - - if (! $this->expireQueryCache && $cacheItem->isHit()) { - $cached = $cacheItem->get(); - if ($cached instanceof ParserResult) { - // Cache hit. - $this->parserResult = $cached; - - return $this->parserResult; - } - } - - // Cache miss. - $parser = new Parser($this); - - $this->parserResult = $parser->parse(); - - $queryCache->save($cacheItem->set($this->parserResult)->expiresAfter($this->queryCacheTTL)); - - return $this->parserResult; - } - - protected function _doExecute(): Result|int - { - $executor = $this->parse()->getSqlExecutor(); - - if ($this->queryCacheProfile) { - $executor->setQueryCacheProfile($this->queryCacheProfile); - } else { - $executor->removeQueryCacheProfile(); - } - - if ($this->resultSetMapping === null) { - $this->resultSetMapping = $this->parserResult->getResultSetMapping(); - } - - // Prepare parameters - $paramMappings = $this->parserResult->getParameterMappings(); - $paramCount = count($this->parameters); - $mappingCount = count($paramMappings); - - if ($paramCount > $mappingCount) { - throw QueryException::tooManyParameters($mappingCount, $paramCount); - } - - if ($paramCount < $mappingCount) { - throw QueryException::tooFewParameters($mappingCount, $paramCount); - } - - // evict all cache for the entity region - if ($this->hasCache && isset($this->hints[self::HINT_CACHE_EVICT]) && $this->hints[self::HINT_CACHE_EVICT]) { - $this->evictEntityCacheRegion(); - } - - [$sqlParams, $types] = $this->processParameterMappings($paramMappings); - - $this->evictResultSetCache( - $executor, - $sqlParams, - $types, - $this->em->getConnection()->getParams(), - ); - - return $executor->execute($this->em->getConnection(), $sqlParams, $types); - } - - /** - * @param array $sqlParams - * @param array $types - * @param array $connectionParams - */ - private function evictResultSetCache( - AbstractSqlExecutor $executor, - array $sqlParams, - array $types, - array $connectionParams, - ): void { - if ($this->queryCacheProfile === null || ! $this->getExpireResultCache()) { - return; - } - - $cache = $this->queryCacheProfile->getResultCache(); - - assert($cache !== null); - - $statements = (array) $executor->getSqlStatements(); // Type casted since it can either be a string or an array - - foreach ($statements as $statement) { - $cacheKeys = $this->queryCacheProfile->generateCacheKeys($statement, $sqlParams, $types, $connectionParams); - $cache->deleteItem(reset($cacheKeys)); - } - } - - /** - * Evict entity cache region - */ - private function evictEntityCacheRegion(): void - { - $AST = $this->getAST(); - - if ($AST instanceof SelectStatement) { - throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.'); - } - - $className = $AST instanceof DeleteStatement - ? $AST->deleteClause->abstractSchemaName - : $AST->updateClause->abstractSchemaName; - - $this->em->getCache()->evictEntityRegion($className); - } - - /** - * Processes query parameter mappings. - * - * @param array> $paramMappings - * - * @return mixed[][] - * @psalm-return array{0: list, 1: array} - * - * @throws Query\QueryException - */ - private function processParameterMappings(array $paramMappings): array - { - $sqlParams = []; - $types = []; - - foreach ($this->parameters as $parameter) { - $key = $parameter->getName(); - - if (! isset($paramMappings[$key])) { - throw QueryException::unknownParameter($key); - } - - [$value, $type] = $this->resolveParameterValue($parameter); - - foreach ($paramMappings[$key] as $position) { - $types[$position] = $type; - } - - $sqlPositions = $paramMappings[$key]; - - // optimized multi value sql positions away for now, - // they are not allowed in DQL anyways. - $value = [$value]; - $countValue = count($value); - - for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) { - $sqlParams[$sqlPositions[$i]] = $value[$i % $countValue]; - } - } - - if (count($sqlParams) !== count($types)) { - throw QueryException::parameterTypeMismatch(); - } - - if ($sqlParams) { - ksort($sqlParams); - $sqlParams = array_values($sqlParams); - - ksort($types); - $types = array_values($types); - } - - return [$sqlParams, $types]; - } - - /** - * @return mixed[] tuple of (value, type) - * @psalm-return array{0: mixed, 1: mixed} - */ - private function resolveParameterValue(Parameter $parameter): array - { - if ($parameter->typeWasSpecified()) { - return [$parameter->getValue(), $parameter->getType()]; - } - - $key = $parameter->getName(); - $originalValue = $parameter->getValue(); - $value = $originalValue; - $rsm = $this->getResultSetMapping(); - - if ($value instanceof ClassMetadata && isset($rsm->metadataParameterMapping[$key])) { - $value = $value->getMetadataValue($rsm->metadataParameterMapping[$key]); - } - - if ($value instanceof ClassMetadata && isset($rsm->discriminatorParameters[$key])) { - $value = array_keys(HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($value, $this->em)); - } - - $processedValue = $this->processParameterValue($value); - - return [ - $processedValue, - $originalValue === $processedValue - ? $parameter->getType() - : ParameterTypeInferer::inferType($processedValue), - ]; - } - - /** - * Defines a cache driver to be used for caching queries. - * - * @return $this - */ - public function setQueryCache(CacheItemPoolInterface|null $queryCache): self - { - $this->queryCache = $queryCache; - - return $this; - } - - /** - * Defines whether the query should make use of a query cache, if available. - * - * @return $this - */ - public function useQueryCache(bool $bool): self - { - $this->useQueryCache = $bool; - - return $this; - } - - /** - * Defines how long the query cache will be active before expire. - * - * @param int|null $timeToLive How long the cache entry is valid. - * - * @return $this - */ - public function setQueryCacheLifetime(int|null $timeToLive): self - { - $this->queryCacheTTL = $timeToLive; - - return $this; - } - - /** - * Retrieves the lifetime of resultset cache. - */ - public function getQueryCacheLifetime(): int|null - { - return $this->queryCacheTTL; - } - - /** - * Defines if the query cache is active or not. - * - * @return $this - */ - public function expireQueryCache(bool $expire = true): self - { - $this->expireQueryCache = $expire; - - return $this; - } - - /** - * Retrieves if the query cache is active or not. - */ - public function getExpireQueryCache(): bool - { - return $this->expireQueryCache; - } - - public function free(): void - { - parent::free(); - - $this->dql = null; - $this->state = self::STATE_CLEAN; - } - - /** - * Sets a DQL query string. - */ - public function setDQL(string $dqlQuery): self - { - $this->dql = $dqlQuery; - $this->state = self::STATE_DIRTY; - - return $this; - } - - /** - * Returns the DQL query that is represented by this query object. - */ - public function getDQL(): string|null - { - return $this->dql; - } - - /** - * Returns the state of this query object - * By default the type is Doctrine_ORM_Query_Abstract::STATE_CLEAN but if it appears any unprocessed DQL - * part, it is switched to Doctrine_ORM_Query_Abstract::STATE_DIRTY. - * - * @see AbstractQuery::STATE_CLEAN - * @see AbstractQuery::STATE_DIRTY - * - * @return int The query state. - * @psalm-return self::STATE_* The query state. - */ - public function getState(): int - { - return $this->state; - } - - /** - * Method to check if an arbitrary piece of DQL exists - * - * @param string $dql Arbitrary piece of DQL to check for. - */ - public function contains(string $dql): bool - { - return stripos($this->getDQL(), $dql) !== false; - } - - /** - * Sets the position of the first result to retrieve (the "offset"). - * - * @param int $firstResult The first result to return. - * - * @return $this - */ - public function setFirstResult(int $firstResult): self - { - $this->firstResult = $firstResult; - $this->state = self::STATE_DIRTY; - - return $this; - } - - /** - * Gets the position of the first result the query object was set to retrieve (the "offset"). - * Returns 0 if {@link setFirstResult} was not applied to this query. - * - * @return int The position of the first result. - */ - public function getFirstResult(): int - { - return $this->firstResult; - } - - /** - * Sets the maximum number of results to retrieve (the "limit"). - * - * @return $this - */ - public function setMaxResults(int|null $maxResults): self - { - $this->maxResults = $maxResults; - $this->state = self::STATE_DIRTY; - - return $this; - } - - /** - * Gets the maximum number of results the query object was set to retrieve (the "limit"). - * Returns NULL if {@link setMaxResults} was not applied to this query. - * - * @return int|null Maximum number of results. - */ - public function getMaxResults(): int|null - { - return $this->maxResults; - } - - /** {@inheritDoc} */ - public function toIterable(iterable $parameters = [], $hydrationMode = self::HYDRATE_OBJECT): iterable - { - $this->setHint(self::HINT_INTERNAL_ITERATION, true); - - return parent::toIterable($parameters, $hydrationMode); - } - - public function setHint(string $name, mixed $value): static - { - $this->state = self::STATE_DIRTY; - - return parent::setHint($name, $value); - } - - public function setHydrationMode(string|int $hydrationMode): static - { - $this->state = self::STATE_DIRTY; - - return parent::setHydrationMode($hydrationMode); - } - - /** - * Set the lock mode for this Query. - * - * @see \Doctrine\DBAL\LockMode - * - * @psalm-param LockMode::* $lockMode - * - * @return $this - * - * @throws TransactionRequiredException - */ - public function setLockMode(LockMode|int $lockMode): self - { - if (in_array($lockMode, [LockMode::NONE, LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE], true)) { - if (! $this->em->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } - } - - $this->setHint(self::HINT_LOCK_MODE, $lockMode); - - return $this; - } - - /** - * Get the current lock mode for this query. - * - * @return LockMode|int|null The current lock mode of this query or NULL if no specific lock mode is set. - * @psalm-return LockMode::*|null - */ - public function getLockMode(): LockMode|int|null - { - $lockMode = $this->getHint(self::HINT_LOCK_MODE); - - if ($lockMode === false) { - return null; - } - - return $lockMode; - } - - /** - * Generate a cache id for the query cache - reusing the Result-Cache-Id generator. - */ - protected function getQueryCacheId(): string - { - ksort($this->hints); - - return md5( - $this->getDQL() . serialize($this->hints) . - '&platform=' . get_debug_type($this->getEntityManager()->getConnection()->getDatabasePlatform()) . - ($this->em->hasFilters() ? $this->em->getFilters()->getHash() : '') . - '&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults . - '&hydrationMode=' . $this->hydrationMode . '&types=' . serialize($this->parsedTypes) . 'DOCTRINE_QUERY_CACHE_SALT', - ); - } - - protected function getHash(): string - { - return sha1(parent::getHash() . '-' . $this->firstResult . '-' . $this->maxResults); - } - - /** - * Cleanup Query resource when clone is called. - */ - public function __clone() - { - parent::__clone(); - - $this->state = self::STATE_DIRTY; - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ASTException.php b/vendor/doctrine/orm/src/Query/AST/ASTException.php deleted file mode 100644 index 1ef890a..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ASTException.php +++ /dev/null @@ -1,20 +0,0 @@ -walkAggregateExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ArithmeticExpression.php b/vendor/doctrine/orm/src/Query/AST/ArithmeticExpression.php deleted file mode 100644 index a819e05..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ArithmeticExpression.php +++ /dev/null @@ -1,34 +0,0 @@ -simpleArithmeticExpression; - } - - public function isSubselect(): bool - { - return (bool) $this->subselect; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkArithmeticExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ArithmeticFactor.php b/vendor/doctrine/orm/src/Query/AST/ArithmeticFactor.php deleted file mode 100644 index 278a921..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ArithmeticFactor.php +++ /dev/null @@ -1,36 +0,0 @@ -sign === true; - } - - public function isNegativeSigned(): bool - { - return $this->sign === false; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkArithmeticFactor($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ArithmeticTerm.php b/vendor/doctrine/orm/src/Query/AST/ArithmeticTerm.php deleted file mode 100644 index b233612..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ArithmeticTerm.php +++ /dev/null @@ -1,25 +0,0 @@ -walkArithmeticTerm($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/BetweenExpression.php b/vendor/doctrine/orm/src/Query/AST/BetweenExpression.php deleted file mode 100644 index c13292b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/BetweenExpression.php +++ /dev/null @@ -1,23 +0,0 @@ -walkBetweenExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/CoalesceExpression.php b/vendor/doctrine/orm/src/Query/AST/CoalesceExpression.php deleted file mode 100644 index 89f025f..0000000 --- a/vendor/doctrine/orm/src/Query/AST/CoalesceExpression.php +++ /dev/null @@ -1,25 +0,0 @@ -walkCoalesceExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/CollectionMemberExpression.php b/vendor/doctrine/orm/src/Query/AST/CollectionMemberExpression.php deleted file mode 100644 index a62a191..0000000 --- a/vendor/doctrine/orm/src/Query/AST/CollectionMemberExpression.php +++ /dev/null @@ -1,27 +0,0 @@ -walkCollectionMemberExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ComparisonExpression.php b/vendor/doctrine/orm/src/Query/AST/ComparisonExpression.php deleted file mode 100644 index a7d91f9..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ComparisonExpression.php +++ /dev/null @@ -1,32 +0,0 @@ -" | "!=") (BooleanExpression | QuantifiedExpression) | - * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | - * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | - * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) - * - * @link www.doctrine-project.org - */ -class ComparisonExpression extends Node -{ - public function __construct( - public Node|string $leftExpression, - public string $operator, - public Node|string $rightExpression, - ) { - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkComparisonExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ConditionalExpression.php b/vendor/doctrine/orm/src/Query/AST/ConditionalExpression.php deleted file mode 100644 index 26a98e5..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ConditionalExpression.php +++ /dev/null @@ -1,25 +0,0 @@ -walkConditionalExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ConditionalFactor.php b/vendor/doctrine/orm/src/Query/AST/ConditionalFactor.php deleted file mode 100644 index 7881743..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ConditionalFactor.php +++ /dev/null @@ -1,26 +0,0 @@ -walkConditionalFactor($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ConditionalPrimary.php b/vendor/doctrine/orm/src/Query/AST/ConditionalPrimary.php deleted file mode 100644 index 9344cd9..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ConditionalPrimary.php +++ /dev/null @@ -1,34 +0,0 @@ -simpleConditionalExpression; - } - - public function isConditionalExpression(): bool - { - return (bool) $this->conditionalExpression; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkConditionalPrimary($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ConditionalTerm.php b/vendor/doctrine/orm/src/Query/AST/ConditionalTerm.php deleted file mode 100644 index dcea50b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ConditionalTerm.php +++ /dev/null @@ -1,25 +0,0 @@ -walkConditionalTerm($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/DeleteClause.php b/vendor/doctrine/orm/src/Query/AST/DeleteClause.php deleted file mode 100644 index 25e9085..0000000 --- a/vendor/doctrine/orm/src/Query/AST/DeleteClause.php +++ /dev/null @@ -1,26 +0,0 @@ -walkDeleteClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/DeleteStatement.php b/vendor/doctrine/orm/src/Query/AST/DeleteStatement.php deleted file mode 100644 index f367d09..0000000 --- a/vendor/doctrine/orm/src/Query/AST/DeleteStatement.php +++ /dev/null @@ -1,26 +0,0 @@ -walkDeleteStatement($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/EmptyCollectionComparisonExpression.php b/vendor/doctrine/orm/src/Query/AST/EmptyCollectionComparisonExpression.php deleted file mode 100644 index 9978800..0000000 --- a/vendor/doctrine/orm/src/Query/AST/EmptyCollectionComparisonExpression.php +++ /dev/null @@ -1,26 +0,0 @@ -walkEmptyCollectionComparisonExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ExistsExpression.php b/vendor/doctrine/orm/src/Query/AST/ExistsExpression.php deleted file mode 100644 index 72757f4..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ExistsExpression.php +++ /dev/null @@ -1,26 +0,0 @@ -walkExistsExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/FromClause.php b/vendor/doctrine/orm/src/Query/AST/FromClause.php deleted file mode 100644 index 0b74393..0000000 --- a/vendor/doctrine/orm/src/Query/AST/FromClause.php +++ /dev/null @@ -1,25 +0,0 @@ -walkFromClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/AbsFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/AbsFunction.php deleted file mode 100644 index 4edff06..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/AbsFunction.php +++ /dev/null @@ -1,37 +0,0 @@ -walkSimpleArithmeticExpression( - $this->simpleArithmeticExpression, - ) . ')'; - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/AvgFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/AvgFunction.php deleted file mode 100644 index ba7b7f3..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/AvgFunction.php +++ /dev/null @@ -1,27 +0,0 @@ -aggregateExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $this->aggregateExpression = $parser->AggregateExpression(); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/BitAndFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/BitAndFunction.php deleted file mode 100644 index f2d3146..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/BitAndFunction.php +++ /dev/null @@ -1,43 +0,0 @@ -getConnection()->getDatabasePlatform(); - - return $platform->getBitAndComparisonExpression( - $this->firstArithmetic->dispatch($sqlWalker), - $this->secondArithmetic->dispatch($sqlWalker), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstArithmetic = $parser->ArithmeticPrimary(); - $parser->match(TokenType::T_COMMA); - $this->secondArithmetic = $parser->ArithmeticPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/BitOrFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/BitOrFunction.php deleted file mode 100644 index f3f84da..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/BitOrFunction.php +++ /dev/null @@ -1,43 +0,0 @@ -getConnection()->getDatabasePlatform(); - - return $platform->getBitOrComparisonExpression( - $this->firstArithmetic->dispatch($sqlWalker), - $this->secondArithmetic->dispatch($sqlWalker), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstArithmetic = $parser->ArithmeticPrimary(); - $parser->match(TokenType::T_COMMA); - $this->secondArithmetic = $parser->ArithmeticPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/ConcatFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/ConcatFunction.php deleted file mode 100644 index 5b8d696..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/ConcatFunction.php +++ /dev/null @@ -1,58 +0,0 @@ - */ - public array $concatExpressions = []; - - public function getSql(SqlWalker $sqlWalker): string - { - $platform = $sqlWalker->getConnection()->getDatabasePlatform(); - - $args = []; - - foreach ($this->concatExpressions as $expression) { - $args[] = $sqlWalker->walkStringPrimary($expression); - } - - return $platform->getConcatExpression(...$args); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstStringPrimary = $parser->StringPrimary(); - $this->concatExpressions[] = $this->firstStringPrimary; - - $parser->match(TokenType::T_COMMA); - - $this->secondStringPrimary = $parser->StringPrimary(); - $this->concatExpressions[] = $this->secondStringPrimary; - - while ($parser->getLexer()->isNextToken(TokenType::T_COMMA)) { - $parser->match(TokenType::T_COMMA); - $this->concatExpressions[] = $parser->StringPrimary(); - } - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/CountFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/CountFunction.php deleted file mode 100644 index dc926a5..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/CountFunction.php +++ /dev/null @@ -1,35 +0,0 @@ -aggregateExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $this->aggregateExpression = $parser->AggregateExpression(); - } - - public function getReturnType(): Type - { - return Type::getType(Types::INTEGER); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentDateFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/CurrentDateFunction.php deleted file mode 100644 index cec9632..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentDateFunction.php +++ /dev/null @@ -1,29 +0,0 @@ -getConnection()->getDatabasePlatform()->getCurrentDateSQL(); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimeFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimeFunction.php deleted file mode 100644 index 6473fce..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimeFunction.php +++ /dev/null @@ -1,29 +0,0 @@ -getConnection()->getDatabasePlatform()->getCurrentTimeSQL(); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimestampFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimestampFunction.php deleted file mode 100644 index edcd27c..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/CurrentTimestampFunction.php +++ /dev/null @@ -1,29 +0,0 @@ -getConnection()->getDatabasePlatform()->getCurrentTimestampSQL(); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/DateAddFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/DateAddFunction.php deleted file mode 100644 index 12920dc..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/DateAddFunction.php +++ /dev/null @@ -1,83 +0,0 @@ -unit->value)) { - 'second' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddSecondsExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'minute' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMinutesExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'hour' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddHourExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'day' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddDaysExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'week' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddWeeksExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'month' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMonthExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'year' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddYearsExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - default => throw QueryException::semanticalError( - 'DATE_ADD() only supports units of type second, minute, hour, day, week, month and year.', - ), - }; - } - - /** @throws ASTException */ - private function dispatchIntervalExpression(SqlWalker $sqlWalker): string - { - return $this->intervalExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstDateExpression = $parser->ArithmeticPrimary(); - $parser->match(TokenType::T_COMMA); - $this->intervalExpression = $parser->ArithmeticPrimary(); - $parser->match(TokenType::T_COMMA); - $this->unit = $parser->StringPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/DateDiffFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/DateDiffFunction.php deleted file mode 100644 index 55598c0..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/DateDiffFunction.php +++ /dev/null @@ -1,41 +0,0 @@ -getConnection()->getDatabasePlatform()->getDateDiffExpression( - $this->date1->dispatch($sqlWalker), - $this->date2->dispatch($sqlWalker), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->date1 = $parser->ArithmeticPrimary(); - $parser->match(TokenType::T_COMMA); - $this->date2 = $parser->ArithmeticPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/DateSubFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/DateSubFunction.php deleted file mode 100644 index 5363680..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/DateSubFunction.php +++ /dev/null @@ -1,62 +0,0 @@ -unit->value)) { - 'second' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubSecondsExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'minute' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMinutesExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'hour' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubHourExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'day' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubDaysExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'week' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubWeeksExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'month' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMonthExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - 'year' => $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubYearsExpression( - $this->firstDateExpression->dispatch($sqlWalker), - $this->dispatchIntervalExpression($sqlWalker), - ), - default => throw QueryException::semanticalError( - 'DATE_SUB() only supports units of type second, minute, hour, day, week, month and year.', - ), - }; - } - - /** @throws ASTException */ - private function dispatchIntervalExpression(SqlWalker $sqlWalker): string - { - return $this->intervalExpression->dispatch($sqlWalker); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/FunctionNode.php b/vendor/doctrine/orm/src/Query/AST/Functions/FunctionNode.php deleted file mode 100644 index 4cc549e..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/FunctionNode.php +++ /dev/null @@ -1,32 +0,0 @@ -walkFunction($this); - } - - abstract public function parse(Parser $parser): void; -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/IdentityFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/IdentityFunction.php deleted file mode 100644 index 1dd1bf5..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/IdentityFunction.php +++ /dev/null @@ -1,90 +0,0 @@ -pathExpression->field !== null); - $entityManager = $sqlWalker->getEntityManager(); - $platform = $entityManager->getConnection()->getDatabasePlatform(); - $quoteStrategy = $entityManager->getConfiguration()->getQuoteStrategy(); - $dqlAlias = $this->pathExpression->identificationVariable; - $assocField = $this->pathExpression->field; - $assoc = $sqlWalker->getMetadataForDqlAlias($dqlAlias)->associationMappings[$assocField]; - $targetEntity = $entityManager->getClassMetadata($assoc->targetEntity); - - assert($assoc->isToOneOwningSide()); - $joinColumn = reset($assoc->joinColumns); - - if ($this->fieldMapping !== null) { - if (! isset($targetEntity->fieldMappings[$this->fieldMapping])) { - throw new QueryException(sprintf('Undefined reference field mapping "%s"', $this->fieldMapping)); - } - - $field = $targetEntity->fieldMappings[$this->fieldMapping]; - $joinColumn = null; - - foreach ($assoc->joinColumns as $mapping) { - if ($mapping->referencedColumnName === $field->columnName) { - $joinColumn = $mapping; - - break; - } - } - - if ($joinColumn === null) { - throw new QueryException(sprintf('Unable to resolve the reference field mapping "%s"', $this->fieldMapping)); - } - } - - // The table with the relation may be a subclass, so get the table name from the association definition - $tableName = $entityManager->getClassMetadata($assoc->sourceEntity)->getTableName(); - - $tableAlias = $sqlWalker->getSQLTableAlias($tableName, $dqlAlias); - $columnName = $quoteStrategy->getJoinColumnName($joinColumn, $targetEntity, $platform); - - return $tableAlias . '.' . $columnName; - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->pathExpression = $parser->SingleValuedAssociationPathExpression(); - - if ($parser->getLexer()->isNextToken(TokenType::T_COMMA)) { - $parser->match(TokenType::T_COMMA); - $parser->match(TokenType::T_STRING); - - $token = $parser->getLexer()->token; - assert($token !== null); - $this->fieldMapping = $token->value; - } - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/LengthFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/LengthFunction.php deleted file mode 100644 index 3994918..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/LengthFunction.php +++ /dev/null @@ -1,45 +0,0 @@ -getConnection()->getDatabasePlatform()->getLengthExpression( - $sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->stringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } - - public function getReturnType(): Type - { - return Type::getType(Types::INTEGER); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/LocateFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/LocateFunction.php deleted file mode 100644 index c0d3b4a..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/LocateFunction.php +++ /dev/null @@ -1,62 +0,0 @@ -getConnection()->getDatabasePlatform(); - - $firstString = $sqlWalker->walkStringPrimary($this->firstStringPrimary); - $secondString = $sqlWalker->walkStringPrimary($this->secondStringPrimary); - - if ($this->simpleArithmeticExpression) { - return $platform->getLocateExpression( - $secondString, - $firstString, - $sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression), - ); - } - - return $platform->getLocateExpression($secondString, $firstString); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstStringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_COMMA); - - $this->secondStringPrimary = $parser->StringPrimary(); - - $lexer = $parser->getLexer(); - if ($lexer->isNextToken(TokenType::T_COMMA)) { - $parser->match(TokenType::T_COMMA); - - $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - } - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/LowerFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/LowerFunction.php deleted file mode 100644 index 8ae337a..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/LowerFunction.php +++ /dev/null @@ -1,40 +0,0 @@ -walkSimpleArithmeticExpression($this->stringPrimary), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->stringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/MaxFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/MaxFunction.php deleted file mode 100644 index 8a6eecf..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/MaxFunction.php +++ /dev/null @@ -1,27 +0,0 @@ -aggregateExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $this->aggregateExpression = $parser->AggregateExpression(); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/MinFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/MinFunction.php deleted file mode 100644 index 98d73a2..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/MinFunction.php +++ /dev/null @@ -1,27 +0,0 @@ -aggregateExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $this->aggregateExpression = $parser->AggregateExpression(); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/ModFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/ModFunction.php deleted file mode 100644 index 7c1af0b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/ModFunction.php +++ /dev/null @@ -1,43 +0,0 @@ -getConnection()->getDatabasePlatform()->getModExpression( - $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression), - $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - - $parser->match(TokenType::T_COMMA); - - $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/SizeFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/SizeFunction.php deleted file mode 100644 index 87ee713..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/SizeFunction.php +++ /dev/null @@ -1,113 +0,0 @@ -collectionPathExpression->field !== null); - $entityManager = $sqlWalker->getEntityManager(); - $platform = $entityManager->getConnection()->getDatabasePlatform(); - $quoteStrategy = $entityManager->getConfiguration()->getQuoteStrategy(); - $dqlAlias = $this->collectionPathExpression->identificationVariable; - $assocField = $this->collectionPathExpression->field; - - $class = $sqlWalker->getMetadataForDqlAlias($dqlAlias); - $assoc = $class->associationMappings[$assocField]; - $sql = 'SELECT COUNT(*) FROM '; - - if ($assoc->isOneToMany()) { - $targetClass = $entityManager->getClassMetadata($assoc->targetEntity); - $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName()); - $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); - - $sql .= $quoteStrategy->getTableName($targetClass, $platform) . ' ' . $targetTableAlias . ' WHERE '; - - $owningAssoc = $targetClass->associationMappings[$assoc->mappedBy]; - assert($owningAssoc->isManyToOne()); - - $first = true; - - foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) { - if ($first) { - $first = false; - } else { - $sql .= ' AND '; - } - - $sql .= $targetTableAlias . '.' . $sourceColumn - . ' = ' - . $sourceTableAlias . '.' . $quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $platform); - } - } else { // many-to-many - assert($assoc->isManyToMany()); - $owningAssoc = $entityManager->getMetadataFactory()->getOwningSide($assoc); - $joinTable = $owningAssoc->joinTable; - - // SQL table aliases - $joinTableAlias = $sqlWalker->getSQLTableAlias($joinTable->name); - $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); - - // join to target table - $targetClass = $entityManager->getClassMetadata($assoc->targetEntity); - $sql .= $quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $platform) . ' ' . $joinTableAlias . ' WHERE '; - - $joinColumns = $assoc->isOwningSide() - ? $joinTable->joinColumns - : $joinTable->inverseJoinColumns; - - $first = true; - - foreach ($joinColumns as $joinColumn) { - if ($first) { - $first = false; - } else { - $sql .= ' AND '; - } - - $sourceColumnName = $quoteStrategy->getColumnName( - $class->fieldNames[$joinColumn->referencedColumnName], - $class, - $platform, - ); - - $sql .= $joinTableAlias . '.' . $joinColumn->name - . ' = ' - . $sourceTableAlias . '.' . $sourceColumnName; - } - } - - return '(' . $sql . ')'; - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->collectionPathExpression = $parser->CollectionValuedPathExpression(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/SqrtFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/SqrtFunction.php deleted file mode 100644 index e643663..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/SqrtFunction.php +++ /dev/null @@ -1,40 +0,0 @@ -walkSimpleArithmeticExpression($this->simpleArithmeticExpression), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/SubstringFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/SubstringFunction.php deleted file mode 100644 index 5744f08..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/SubstringFunction.php +++ /dev/null @@ -1,58 +0,0 @@ -secondSimpleArithmeticExpression !== null) { - $optionalSecondSimpleArithmeticExpression = $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression); - } - - return $sqlWalker->getConnection()->getDatabasePlatform()->getSubstringExpression( - $sqlWalker->walkStringPrimary($this->stringPrimary), - $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression), - $optionalSecondSimpleArithmeticExpression, - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->stringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_COMMA); - - $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - - $lexer = $parser->getLexer(); - if ($lexer->isNextToken(TokenType::T_COMMA)) { - $parser->match(TokenType::T_COMMA); - - $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - } - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/SumFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/SumFunction.php deleted file mode 100644 index 588dce9..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/SumFunction.php +++ /dev/null @@ -1,27 +0,0 @@ -aggregateExpression->dispatch($sqlWalker); - } - - public function parse(Parser $parser): void - { - $this->aggregateExpression = $parser->AggregateExpression(); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/TrimFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/TrimFunction.php deleted file mode 100644 index e0a3e99..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/TrimFunction.php +++ /dev/null @@ -1,119 +0,0 @@ -walkStringPrimary($this->stringPrimary); - $platform = $sqlWalker->getConnection()->getDatabasePlatform(); - $trimMode = $this->getTrimMode(); - - if ($this->trimChar !== false) { - return $platform->getTrimExpression( - $stringPrimary, - $trimMode, - $platform->quoteStringLiteral($this->trimChar), - ); - } - - return $platform->getTrimExpression($stringPrimary, $trimMode); - } - - public function parse(Parser $parser): void - { - $lexer = $parser->getLexer(); - - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->parseTrimMode($parser); - - if ($lexer->isNextToken(TokenType::T_STRING)) { - $parser->match(TokenType::T_STRING); - - assert($lexer->token !== null); - $this->trimChar = $lexer->token->value; - } - - if ($this->leading || $this->trailing || $this->both || ($this->trimChar !== false)) { - $parser->match(TokenType::T_FROM); - } - - $this->stringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } - - /** @psalm-return TrimMode::* */ - private function getTrimMode(): TrimMode|int - { - if ($this->leading) { - return TrimMode::LEADING; - } - - if ($this->trailing) { - return TrimMode::TRAILING; - } - - if ($this->both) { - return TrimMode::BOTH; - } - - return TrimMode::UNSPECIFIED; - } - - private function parseTrimMode(Parser $parser): void - { - $lexer = $parser->getLexer(); - assert($lexer->lookahead !== null); - $value = $lexer->lookahead->value; - - if (strcasecmp('leading', $value) === 0) { - $parser->match(TokenType::T_LEADING); - - $this->leading = true; - - return; - } - - if (strcasecmp('trailing', $value) === 0) { - $parser->match(TokenType::T_TRAILING); - - $this->trailing = true; - - return; - } - - if (strcasecmp('both', $value) === 0) { - $parser->match(TokenType::T_BOTH); - - $this->both = true; - - return; - } - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Functions/UpperFunction.php b/vendor/doctrine/orm/src/Query/AST/Functions/UpperFunction.php deleted file mode 100644 index 1ecef66..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Functions/UpperFunction.php +++ /dev/null @@ -1,40 +0,0 @@ -walkSimpleArithmeticExpression($this->stringPrimary), - ); - } - - public function parse(Parser $parser): void - { - $parser->match(TokenType::T_IDENTIFIER); - $parser->match(TokenType::T_OPEN_PARENTHESIS); - - $this->stringPrimary = $parser->StringPrimary(); - - $parser->match(TokenType::T_CLOSE_PARENTHESIS); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/GeneralCaseExpression.php b/vendor/doctrine/orm/src/Query/AST/GeneralCaseExpression.php deleted file mode 100644 index 39d760a..0000000 --- a/vendor/doctrine/orm/src/Query/AST/GeneralCaseExpression.php +++ /dev/null @@ -1,27 +0,0 @@ -walkGeneralCaseExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/GroupByClause.php b/vendor/doctrine/orm/src/Query/AST/GroupByClause.php deleted file mode 100644 index eb0f1b9..0000000 --- a/vendor/doctrine/orm/src/Query/AST/GroupByClause.php +++ /dev/null @@ -1,20 +0,0 @@ -walkGroupByClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/HavingClause.php b/vendor/doctrine/orm/src/Query/AST/HavingClause.php deleted file mode 100644 index 0d4d821..0000000 --- a/vendor/doctrine/orm/src/Query/AST/HavingClause.php +++ /dev/null @@ -1,19 +0,0 @@ -walkHavingClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/IdentificationVariableDeclaration.php b/vendor/doctrine/orm/src/Query/AST/IdentificationVariableDeclaration.php deleted file mode 100644 index c4c7cca..0000000 --- a/vendor/doctrine/orm/src/Query/AST/IdentificationVariableDeclaration.php +++ /dev/null @@ -1,28 +0,0 @@ -walkIdentificationVariableDeclaration($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/InListExpression.php b/vendor/doctrine/orm/src/Query/AST/InListExpression.php deleted file mode 100644 index dc0f32b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/InListExpression.php +++ /dev/null @@ -1,23 +0,0 @@ - $literals */ - public function __construct( - public ArithmeticExpression $expression, - public array $literals, - public bool $not = false, - ) { - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkInListExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/InSubselectExpression.php b/vendor/doctrine/orm/src/Query/AST/InSubselectExpression.php deleted file mode 100644 index 1128285..0000000 --- a/vendor/doctrine/orm/src/Query/AST/InSubselectExpression.php +++ /dev/null @@ -1,22 +0,0 @@ -walkInSubselectExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/IndexBy.php b/vendor/doctrine/orm/src/Query/AST/IndexBy.php deleted file mode 100644 index 3d90265..0000000 --- a/vendor/doctrine/orm/src/Query/AST/IndexBy.php +++ /dev/null @@ -1,26 +0,0 @@ -walkIndexBy($this); - - return ''; - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/InputParameter.php b/vendor/doctrine/orm/src/Query/AST/InputParameter.php deleted file mode 100644 index a8e0a3b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/InputParameter.php +++ /dev/null @@ -1,35 +0,0 @@ -isNamed = ! is_numeric($param); - $this->name = $param; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkInputParameter($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/InstanceOfExpression.php b/vendor/doctrine/orm/src/Query/AST/InstanceOfExpression.php deleted file mode 100644 index 3a4e75f..0000000 --- a/vendor/doctrine/orm/src/Query/AST/InstanceOfExpression.php +++ /dev/null @@ -1,29 +0,0 @@ - $value */ - public function __construct( - public string $identificationVariable, - public array $value, - public bool $not = false, - ) { - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkInstanceOfExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Join.php b/vendor/doctrine/orm/src/Query/AST/Join.php deleted file mode 100644 index 34ce830..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Join.php +++ /dev/null @@ -1,34 +0,0 @@ -walkJoin($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/JoinAssociationDeclaration.php b/vendor/doctrine/orm/src/Query/AST/JoinAssociationDeclaration.php deleted file mode 100644 index e08d7f5..0000000 --- a/vendor/doctrine/orm/src/Query/AST/JoinAssociationDeclaration.php +++ /dev/null @@ -1,27 +0,0 @@ -walkJoinAssociationDeclaration($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/JoinAssociationPathExpression.php b/vendor/doctrine/orm/src/Query/AST/JoinAssociationPathExpression.php deleted file mode 100644 index 230be36..0000000 --- a/vendor/doctrine/orm/src/Query/AST/JoinAssociationPathExpression.php +++ /dev/null @@ -1,19 +0,0 @@ -walkJoinPathExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/JoinVariableDeclaration.php b/vendor/doctrine/orm/src/Query/AST/JoinVariableDeclaration.php deleted file mode 100644 index bf76695..0000000 --- a/vendor/doctrine/orm/src/Query/AST/JoinVariableDeclaration.php +++ /dev/null @@ -1,24 +0,0 @@ -walkJoinVariableDeclaration($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/LikeExpression.php b/vendor/doctrine/orm/src/Query/AST/LikeExpression.php deleted file mode 100644 index e3f67f8..0000000 --- a/vendor/doctrine/orm/src/Query/AST/LikeExpression.php +++ /dev/null @@ -1,29 +0,0 @@ -walkLikeExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Literal.php b/vendor/doctrine/orm/src/Query/AST/Literal.php deleted file mode 100644 index 9ec2036..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Literal.php +++ /dev/null @@ -1,26 +0,0 @@ -walkLiteral($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/NewObjectExpression.php b/vendor/doctrine/orm/src/Query/AST/NewObjectExpression.php deleted file mode 100644 index 7383c48..0000000 --- a/vendor/doctrine/orm/src/Query/AST/NewObjectExpression.php +++ /dev/null @@ -1,25 +0,0 @@ -walkNewObject($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Node.php b/vendor/doctrine/orm/src/Query/AST/Node.php deleted file mode 100644 index cdb5855..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Node.php +++ /dev/null @@ -1,85 +0,0 @@ -dump($this); - } - - public function dump(mixed $value): string - { - static $ident = 0; - - $str = ''; - - if ($value instanceof Node) { - $str .= get_debug_type($value) . '(' . PHP_EOL; - $props = get_object_vars($value); - - foreach ($props as $name => $prop) { - $ident += 4; - $str .= str_repeat(' ', $ident) . '"' . $name . '": ' - . $this->dump($prop) . ',' . PHP_EOL; - $ident -= 4; - } - - $str .= str_repeat(' ', $ident) . ')'; - } elseif (is_array($value)) { - $ident += 4; - $str .= 'array('; - $some = false; - - foreach ($value as $k => $v) { - $str .= PHP_EOL . str_repeat(' ', $ident) . '"' - . $k . '" => ' . $this->dump($v) . ','; - $some = true; - } - - $ident -= 4; - $str .= ($some ? PHP_EOL . str_repeat(' ', $ident) : '') . ')'; - } elseif (is_object($value)) { - $str .= 'instanceof(' . get_debug_type($value) . ')'; - } else { - $str .= var_export($value, true); - } - - return $str; - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/NullComparisonExpression.php b/vendor/doctrine/orm/src/Query/AST/NullComparisonExpression.php deleted file mode 100644 index e60cb04..0000000 --- a/vendor/doctrine/orm/src/Query/AST/NullComparisonExpression.php +++ /dev/null @@ -1,26 +0,0 @@ -walkNullComparisonExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/NullIfExpression.php b/vendor/doctrine/orm/src/Query/AST/NullIfExpression.php deleted file mode 100644 index 6fffeeb..0000000 --- a/vendor/doctrine/orm/src/Query/AST/NullIfExpression.php +++ /dev/null @@ -1,24 +0,0 @@ -walkNullIfExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/OrderByClause.php b/vendor/doctrine/orm/src/Query/AST/OrderByClause.php deleted file mode 100644 index f6d7a67..0000000 --- a/vendor/doctrine/orm/src/Query/AST/OrderByClause.php +++ /dev/null @@ -1,25 +0,0 @@ -walkOrderByClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/OrderByItem.php b/vendor/doctrine/orm/src/Query/AST/OrderByItem.php deleted file mode 100644 index 64b3f40..0000000 --- a/vendor/doctrine/orm/src/Query/AST/OrderByItem.php +++ /dev/null @@ -1,38 +0,0 @@ -type) === 'ASC'; - } - - public function isDesc(): bool - { - return strtoupper($this->type) === 'DESC'; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkOrderByItem($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/ParenthesisExpression.php b/vendor/doctrine/orm/src/Query/AST/ParenthesisExpression.php deleted file mode 100644 index cda6d19..0000000 --- a/vendor/doctrine/orm/src/Query/AST/ParenthesisExpression.php +++ /dev/null @@ -1,22 +0,0 @@ -walkParenthesisExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/PathExpression.php b/vendor/doctrine/orm/src/Query/AST/PathExpression.php deleted file mode 100644 index 4a56fcd..0000000 --- a/vendor/doctrine/orm/src/Query/AST/PathExpression.php +++ /dev/null @@ -1,39 +0,0 @@ - $expectedType */ - public function __construct( - public int $expectedType, - public string $identificationVariable, - public string|null $field = null, - ) { - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkPathExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Phase2OptimizableConditional.php b/vendor/doctrine/orm/src/Query/AST/Phase2OptimizableConditional.php deleted file mode 100644 index 276f8f8..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Phase2OptimizableConditional.php +++ /dev/null @@ -1,17 +0,0 @@ -type) === 'ALL'; - } - - public function isAny(): bool - { - return strtoupper($this->type) === 'ANY'; - } - - public function isSome(): bool - { - return strtoupper($this->type) === 'SOME'; - } - - public function dispatch(SqlWalker $walker): string - { - return $walker->walkQuantifiedExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/RangeVariableDeclaration.php b/vendor/doctrine/orm/src/Query/AST/RangeVariableDeclaration.php deleted file mode 100644 index 59bd5c8..0000000 --- a/vendor/doctrine/orm/src/Query/AST/RangeVariableDeclaration.php +++ /dev/null @@ -1,27 +0,0 @@ -walkRangeVariableDeclaration($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SelectClause.php b/vendor/doctrine/orm/src/Query/AST/SelectClause.php deleted file mode 100644 index ad50e67..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SelectClause.php +++ /dev/null @@ -1,27 +0,0 @@ -walkSelectClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SelectExpression.php b/vendor/doctrine/orm/src/Query/AST/SelectExpression.php deleted file mode 100644 index f09f3cd..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SelectExpression.php +++ /dev/null @@ -1,28 +0,0 @@ -walkSelectExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SelectStatement.php b/vendor/doctrine/orm/src/Query/AST/SelectStatement.php deleted file mode 100644 index 399462f..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SelectStatement.php +++ /dev/null @@ -1,32 +0,0 @@ -walkSelectStatement($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SimpleArithmeticExpression.php b/vendor/doctrine/orm/src/Query/AST/SimpleArithmeticExpression.php deleted file mode 100644 index ae7ca44..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SimpleArithmeticExpression.php +++ /dev/null @@ -1,25 +0,0 @@ -walkSimpleArithmeticExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SimpleCaseExpression.php b/vendor/doctrine/orm/src/Query/AST/SimpleCaseExpression.php deleted file mode 100644 index b3764ba..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SimpleCaseExpression.php +++ /dev/null @@ -1,28 +0,0 @@ -walkSimpleCaseExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SimpleSelectClause.php b/vendor/doctrine/orm/src/Query/AST/SimpleSelectClause.php deleted file mode 100644 index 0259e3b..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SimpleSelectClause.php +++ /dev/null @@ -1,26 +0,0 @@ -walkSimpleSelectClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SimpleSelectExpression.php b/vendor/doctrine/orm/src/Query/AST/SimpleSelectExpression.php deleted file mode 100644 index 97e8f08..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SimpleSelectExpression.php +++ /dev/null @@ -1,27 +0,0 @@ -walkSimpleSelectExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SimpleWhenClause.php b/vendor/doctrine/orm/src/Query/AST/SimpleWhenClause.php deleted file mode 100644 index 892165a..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SimpleWhenClause.php +++ /dev/null @@ -1,26 +0,0 @@ -walkWhenClauseExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/Subselect.php b/vendor/doctrine/orm/src/Query/AST/Subselect.php deleted file mode 100644 index 8ff8595..0000000 --- a/vendor/doctrine/orm/src/Query/AST/Subselect.php +++ /dev/null @@ -1,32 +0,0 @@ -walkSubselect($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SubselectFromClause.php b/vendor/doctrine/orm/src/Query/AST/SubselectFromClause.php deleted file mode 100644 index 7cf01e2..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SubselectFromClause.php +++ /dev/null @@ -1,25 +0,0 @@ -walkSubselectFromClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/SubselectIdentificationVariableDeclaration.php b/vendor/doctrine/orm/src/Query/AST/SubselectIdentificationVariableDeclaration.php deleted file mode 100644 index eadf6bc..0000000 --- a/vendor/doctrine/orm/src/Query/AST/SubselectIdentificationVariableDeclaration.php +++ /dev/null @@ -1,19 +0,0 @@ -walkUpdateClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/UpdateItem.php b/vendor/doctrine/orm/src/Query/AST/UpdateItem.php deleted file mode 100644 index b540593..0000000 --- a/vendor/doctrine/orm/src/Query/AST/UpdateItem.php +++ /dev/null @@ -1,26 +0,0 @@ -walkUpdateItem($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/UpdateStatement.php b/vendor/doctrine/orm/src/Query/AST/UpdateStatement.php deleted file mode 100644 index 7ea5076..0000000 --- a/vendor/doctrine/orm/src/Query/AST/UpdateStatement.php +++ /dev/null @@ -1,26 +0,0 @@ -walkUpdateStatement($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/WhenClause.php b/vendor/doctrine/orm/src/Query/AST/WhenClause.php deleted file mode 100644 index 9bf194e..0000000 --- a/vendor/doctrine/orm/src/Query/AST/WhenClause.php +++ /dev/null @@ -1,26 +0,0 @@ -walkWhenClauseExpression($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/AST/WhereClause.php b/vendor/doctrine/orm/src/Query/AST/WhereClause.php deleted file mode 100644 index e4d7b66..0000000 --- a/vendor/doctrine/orm/src/Query/AST/WhereClause.php +++ /dev/null @@ -1,24 +0,0 @@ -walkWhereClause($this); - } -} diff --git a/vendor/doctrine/orm/src/Query/Exec/AbstractSqlExecutor.php b/vendor/doctrine/orm/src/Query/Exec/AbstractSqlExecutor.php deleted file mode 100644 index 101bf26..0000000 --- a/vendor/doctrine/orm/src/Query/Exec/AbstractSqlExecutor.php +++ /dev/null @@ -1,61 +0,0 @@ -, WrapperParameterType>|array - */ -abstract class AbstractSqlExecutor -{ - /** @var list|string */ - protected array|string $sqlStatements; - - protected QueryCacheProfile|null $queryCacheProfile = null; - - /** - * Gets the SQL statements that are executed by the executor. - * - * @return list|string All the SQL update statements. - */ - public function getSqlStatements(): array|string - { - return $this->sqlStatements; - } - - public function setQueryCacheProfile(QueryCacheProfile $qcp): void - { - $this->queryCacheProfile = $qcp; - } - - /** - * Do not use query cache - */ - public function removeQueryCacheProfile(): void - { - $this->queryCacheProfile = null; - } - - /** - * Executes all sql statements. - * - * @param Connection $conn The database connection that is used to execute the queries. - * @param list|array $params The parameters. - * @psalm-param WrapperParameterTypeArray $types The parameter types. - */ - abstract public function execute(Connection $conn, array $params, array $types): Result|int; -} diff --git a/vendor/doctrine/orm/src/Query/Exec/MultiTableDeleteExecutor.php b/vendor/doctrine/orm/src/Query/Exec/MultiTableDeleteExecutor.php deleted file mode 100644 index 6096462..0000000 --- a/vendor/doctrine/orm/src/Query/Exec/MultiTableDeleteExecutor.php +++ /dev/null @@ -1,131 +0,0 @@ -MultiTableDeleteExecutor. - * - * Internal note: Any SQL construction and preparation takes place in the constructor for - * best performance. With a query cache the executor will be cached. - * - * @param DeleteStatement $AST The root AST node of the DQL query. - * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST. - */ - public function __construct(AST\Node $AST, SqlWalker $sqlWalker) - { - $em = $sqlWalker->getEntityManager(); - $conn = $em->getConnection(); - $platform = $conn->getDatabasePlatform(); - $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - - if ($conn instanceof PrimaryReadReplicaConnection) { - $conn->ensureConnectedToPrimary(); - } - - $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); - $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; - $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); - - $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); - $idColumnNames = $rootClass->getIdentifierColumnNames(); - $idColumnList = implode(', ', $idColumnNames); - - // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() - $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias); - - $insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' - . ' SELECT t0.' . implode(', t0.', $idColumnNames); - - $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias); - $fromClause = new AST\FromClause([new AST\IdentificationVariableDeclaration($rangeDecl, null, [])]); - $insertSql .= $sqlWalker->walkFromClause($fromClause); - - // Append WHERE clause, if there is one. - if ($AST->whereClause) { - $insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); - } - - $this->insertSql = $insertSql; - - // 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect) - $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; - - // 3. Create and store DELETE statements - $classNames = [...$primaryClass->parentClasses, ...[$primaryClass->name], ...$primaryClass->subClasses]; - foreach (array_reverse($classNames) as $className) { - $tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform); - $this->sqlStatements[] = 'DELETE FROM ' . $tableName - . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; - } - - // 4. Store DDL for temporary identifier table. - $columnDefinitions = []; - foreach ($idColumnNames as $idColumnName) { - $columnDefinitions[$idColumnName] = [ - 'name' => $idColumnName, - 'notnull' => true, - 'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)), - ]; - } - - $this->createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' - . $platform->getColumnDeclarationListSQL($columnDefinitions) . ', PRIMARY KEY(' . implode(',', $idColumnNames) . '))'; - $this->dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); - } - - /** - * {@inheritDoc} - */ - public function execute(Connection $conn, array $params, array $types): int - { - // Create temporary id table - $conn->executeStatement($this->createTempTableSql); - - try { - // Insert identifiers - $numDeleted = $conn->executeStatement($this->insertSql, $params, $types); - - // Execute DELETE statements - foreach ($this->sqlStatements as $sql) { - $conn->executeStatement($sql); - } - } catch (Throwable $exception) { - // FAILURE! Drop temporary table to avoid possible collisions - $conn->executeStatement($this->dropTempTableSql); - - // Re-throw exception - throw $exception; - } - - // Drop temporary table - $conn->executeStatement($this->dropTempTableSql); - - return $numDeleted; - } -} diff --git a/vendor/doctrine/orm/src/Query/Exec/MultiTableUpdateExecutor.php b/vendor/doctrine/orm/src/Query/Exec/MultiTableUpdateExecutor.php deleted file mode 100644 index dab1b61..0000000 --- a/vendor/doctrine/orm/src/Query/Exec/MultiTableUpdateExecutor.php +++ /dev/null @@ -1,180 +0,0 @@ -MultiTableUpdateExecutor. - * - * Internal note: Any SQL construction and preparation takes place in the constructor for - * best performance. With a query cache the executor will be cached. - * - * @param UpdateStatement $AST The root AST node of the DQL query. - * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST. - */ - public function __construct(AST\Node $AST, SqlWalker $sqlWalker) - { - $em = $sqlWalker->getEntityManager(); - $conn = $em->getConnection(); - $platform = $conn->getDatabasePlatform(); - $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $this->sqlStatements = []; - - if ($conn instanceof PrimaryReadReplicaConnection) { - $conn->ensureConnectedToPrimary(); - } - - $updateClause = $AST->updateClause; - $primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName); - $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); - - $updateItems = $updateClause->updateItems; - - $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); - $idColumnNames = $rootClass->getIdentifierColumnNames(); - $idColumnList = implode(', ', $idColumnNames); - - // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() - $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable); - - $insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' - . ' SELECT t0.' . implode(', t0.', $idColumnNames); - - $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $updateClause->aliasIdentificationVariable); - $fromClause = new AST\FromClause([new AST\IdentificationVariableDeclaration($rangeDecl, null, [])]); - - $insertSql .= $sqlWalker->walkFromClause($fromClause); - - // 2. Create ID subselect statement used in UPDATE ... WHERE ... IN (subselect) - $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; - - // 3. Create and store UPDATE statements - $classNames = [...$primaryClass->parentClasses, ...[$primaryClass->name], ...$primaryClass->subClasses]; - - foreach (array_reverse($classNames) as $className) { - $affected = false; - $class = $em->getClassMetadata($className); - $updateSql = 'UPDATE ' . $quoteStrategy->getTableName($class, $platform) . ' SET '; - - $sqlParameters = []; - foreach ($updateItems as $updateItem) { - $field = $updateItem->pathExpression->field; - - if ( - (isset($class->fieldMappings[$field]) && ! isset($class->fieldMappings[$field]->inherited)) || - (isset($class->associationMappings[$field]) && ! isset($class->associationMappings[$field]->inherited)) - ) { - $newValue = $updateItem->newValue; - - if (! $affected) { - $affected = true; - } else { - $updateSql .= ', '; - } - - $updateSql .= $sqlWalker->walkUpdateItem($updateItem); - - if ($newValue instanceof AST\InputParameter) { - $sqlParameters[] = $newValue->name; - - ++$this->numParametersInUpdateClause; - } - } - } - - if ($affected) { - $this->sqlParameters[] = $sqlParameters; - $this->sqlStatements[] = $updateSql . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; - } - } - - // Append WHERE clause to insertSql, if there is one. - if ($AST->whereClause) { - $insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); - } - - $this->insertSql = $insertSql; - - // 4. Store DDL for temporary identifier table. - $columnDefinitions = []; - - foreach ($idColumnNames as $idColumnName) { - $columnDefinitions[$idColumnName] = [ - 'name' => $idColumnName, - 'notnull' => true, - 'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)), - ]; - } - - $this->createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' - . $platform->getColumnDeclarationListSQL($columnDefinitions) . ', PRIMARY KEY(' . implode(',', $idColumnNames) . '))'; - - $this->dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); - } - - /** - * {@inheritDoc} - */ - public function execute(Connection $conn, array $params, array $types): int - { - // Create temporary id table - $conn->executeStatement($this->createTempTableSql); - - try { - // Insert identifiers. Parameters from the update clause are cut off. - $numUpdated = $conn->executeStatement( - $this->insertSql, - array_slice($params, $this->numParametersInUpdateClause), - array_slice($types, $this->numParametersInUpdateClause), - ); - - // Execute UPDATE statements - foreach ($this->sqlStatements as $key => $statement) { - $paramValues = []; - $paramTypes = []; - - if (isset($this->sqlParameters[$key])) { - foreach ($this->sqlParameters[$key] as $parameterKey => $parameterName) { - $paramValues[] = $params[$parameterKey]; - $paramTypes[] = $types[$parameterKey] ?? ParameterTypeInferer::inferType($params[$parameterKey]); - } - } - - $conn->executeStatement($statement, $paramValues, $paramTypes); - } - } finally { - // Drop temporary table - $conn->executeStatement($this->dropTempTableSql); - } - - return $numUpdated; - } -} diff --git a/vendor/doctrine/orm/src/Query/Exec/SingleSelectExecutor.php b/vendor/doctrine/orm/src/Query/Exec/SingleSelectExecutor.php deleted file mode 100644 index 5445edb..0000000 --- a/vendor/doctrine/orm/src/Query/Exec/SingleSelectExecutor.php +++ /dev/null @@ -1,31 +0,0 @@ -sqlStatements = $sqlWalker->walkSelectStatement($AST); - } - - /** - * {@inheritDoc} - */ - public function execute(Connection $conn, array $params, array $types): Result - { - return $conn->executeQuery($this->sqlStatements, $params, $types, $this->queryCacheProfile); - } -} diff --git a/vendor/doctrine/orm/src/Query/Exec/SingleTableDeleteUpdateExecutor.php b/vendor/doctrine/orm/src/Query/Exec/SingleTableDeleteUpdateExecutor.php deleted file mode 100644 index 66696db..0000000 --- a/vendor/doctrine/orm/src/Query/Exec/SingleTableDeleteUpdateExecutor.php +++ /dev/null @@ -1,42 +0,0 @@ -sqlStatements = $sqlWalker->walkUpdateStatement($AST); - } elseif ($AST instanceof AST\DeleteStatement) { - $this->sqlStatements = $sqlWalker->walkDeleteStatement($AST); - } - } - - /** - * {@inheritDoc} - */ - public function execute(Connection $conn, array $params, array $types): int - { - if ($conn instanceof PrimaryReadReplicaConnection) { - $conn->ensureConnectedToPrimary(); - } - - return $conn->executeStatement($this->sqlStatements, $params, $types); - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr.php b/vendor/doctrine/orm/src/Query/Expr.php deleted file mode 100644 index 65f3082..0000000 --- a/vendor/doctrine/orm/src/Query/Expr.php +++ /dev/null @@ -1,615 +0,0 @@ -andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2')); - * - * @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x Optional clause. Defaults to null, - * but requires at least one defined - * when converting to string. - */ - public function andX(Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x): Expr\Andx - { - self::validateVariadicParameter($x); - - return new Expr\Andx($x); - } - - /** - * Creates a disjunction of the given boolean expressions. - * - * Example: - * - * [php] - * // (u.type = ?1) OR (u.role = ?2) - * $q->where($q->expr()->orX('u.type = ?1', 'u.role = ?2')); - * - * @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x Optional clause. Defaults to null, - * but requires at least one defined - * when converting to string. - */ - public function orX(Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x): Expr\Orx - { - self::validateVariadicParameter($x); - - return new Expr\Orx($x); - } - - /** - * Creates an ASCending order expression. - */ - public function asc(mixed $expr): Expr\OrderBy - { - return new Expr\OrderBy($expr, 'ASC'); - } - - /** - * Creates a DESCending order expression. - */ - public function desc(mixed $expr): Expr\OrderBy - { - return new Expr\OrderBy($expr, 'DESC'); - } - - /** - * Creates an equality comparison expression with the given arguments. - * - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a = . Example: - * - * [php] - * // u.id = ?1 - * $expr->eq('u.id', '?1'); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function eq(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::EQ, $y); - } - - /** - * Creates an instance of Expr\Comparison, with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <> . Example: - * - * [php] - * // u.id <> ?1 - * $q->where($q->expr()->neq('u.id', '?1')); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function neq(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::NEQ, $y); - } - - /** - * Creates an instance of Expr\Comparison, with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a < . Example: - * - * [php] - * // u.id < ?1 - * $q->where($q->expr()->lt('u.id', '?1')); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function lt(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::LT, $y); - } - - /** - * Creates an instance of Expr\Comparison, with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <= . Example: - * - * [php] - * // u.id <= ?1 - * $q->where($q->expr()->lte('u.id', '?1')); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function lte(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::LTE, $y); - } - - /** - * Creates an instance of Expr\Comparison, with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a > . Example: - * - * [php] - * // u.id > ?1 - * $q->where($q->expr()->gt('u.id', '?1')); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function gt(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::GT, $y); - } - - /** - * Creates an instance of Expr\Comparison, with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a >= . Example: - * - * [php] - * // u.id >= ?1 - * $q->where($q->expr()->gte('u.id', '?1')); - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function gte(mixed $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, Expr\Comparison::GTE, $y); - } - - /** - * Creates an instance of AVG() function, with the given argument. - * - * @param mixed $x Argument to be used in AVG() function. - */ - public function avg(mixed $x): Expr\Func - { - return new Expr\Func('AVG', [$x]); - } - - /** - * Creates an instance of MAX() function, with the given argument. - * - * @param mixed $x Argument to be used in MAX() function. - */ - public function max(mixed $x): Expr\Func - { - return new Expr\Func('MAX', [$x]); - } - - /** - * Creates an instance of MIN() function, with the given argument. - * - * @param mixed $x Argument to be used in MIN() function. - */ - public function min(mixed $x): Expr\Func - { - return new Expr\Func('MIN', [$x]); - } - - /** - * Creates an instance of COUNT() function, with the given argument. - * - * @param mixed $x Argument to be used in COUNT() function. - */ - public function count(mixed $x): Expr\Func - { - return new Expr\Func('COUNT', [$x]); - } - - /** - * Creates an instance of COUNT(DISTINCT) function, with the given argument. - * - * @param mixed ...$x Argument to be used in COUNT(DISTINCT) function. - */ - public function countDistinct(mixed ...$x): string - { - self::validateVariadicParameter($x); - - return 'COUNT(DISTINCT ' . implode(', ', $x) . ')'; - } - - /** - * Creates an instance of EXISTS() function, with the given DQL Subquery. - * - * @param mixed $subquery DQL Subquery to be used in EXISTS() function. - */ - public function exists(mixed $subquery): Expr\Func - { - return new Expr\Func('EXISTS', [$subquery]); - } - - /** - * Creates an instance of ALL() function, with the given DQL Subquery. - * - * @param mixed $subquery DQL Subquery to be used in ALL() function. - */ - public function all(mixed $subquery): Expr\Func - { - return new Expr\Func('ALL', [$subquery]); - } - - /** - * Creates a SOME() function expression with the given DQL subquery. - * - * @param mixed $subquery DQL Subquery to be used in SOME() function. - */ - public function some(mixed $subquery): Expr\Func - { - return new Expr\Func('SOME', [$subquery]); - } - - /** - * Creates an ANY() function expression with the given DQL subquery. - * - * @param mixed $subquery DQL Subquery to be used in ANY() function. - */ - public function any(mixed $subquery): Expr\Func - { - return new Expr\Func('ANY', [$subquery]); - } - - /** - * Creates a negation expression of the given restriction. - * - * @param mixed $restriction Restriction to be used in NOT() function. - */ - public function not(mixed $restriction): Expr\Func - { - return new Expr\Func('NOT', [$restriction]); - } - - /** - * Creates an ABS() function expression with the given argument. - * - * @param mixed $x Argument to be used in ABS() function. - */ - public function abs(mixed $x): Expr\Func - { - return new Expr\Func('ABS', [$x]); - } - - /** - * Creates a MOD($x, $y) function expression to return the remainder of $x divided by $y. - */ - public function mod(mixed $x, mixed $y): Expr\Func - { - return new Expr\Func('MOD', [$x, $y]); - } - - /** - * Creates a product mathematical expression with the given arguments. - * - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a * . Example: - * - * [php] - * // u.salary * u.percentAnnualSalaryIncrease - * $q->expr()->prod('u.salary', 'u.percentAnnualSalaryIncrease') - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function prod(mixed $x, mixed $y): Expr\Math - { - return new Expr\Math($x, '*', $y); - } - - /** - * Creates a difference mathematical expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a - . Example: - * - * [php] - * // u.monthlySubscriptionCount - 1 - * $q->expr()->diff('u.monthlySubscriptionCount', '1') - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function diff(mixed $x, mixed $y): Expr\Math - { - return new Expr\Math($x, '-', $y); - } - - /** - * Creates a sum mathematical expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a + . Example: - * - * [php] - * // u.numChildren + 1 - * $q->expr()->sum('u.numChildren', '1') - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function sum(mixed $x, mixed $y): Expr\Math - { - return new Expr\Math($x, '+', $y); - } - - /** - * Creates a quotient mathematical expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a / . Example: - * - * [php] - * // u.total / u.period - * $expr->quot('u.total', 'u.period') - * - * @param mixed $x Left expression. - * @param mixed $y Right expression. - */ - public function quot(mixed $x, mixed $y): Expr\Math - { - return new Expr\Math($x, '/', $y); - } - - /** - * Creates a SQRT() function expression with the given argument. - * - * @param mixed $x Argument to be used in SQRT() function. - */ - public function sqrt(mixed $x): Expr\Func - { - return new Expr\Func('SQRT', [$x]); - } - - /** - * Creates an IN() expression with the given arguments. - * - * @param string $x Field in string format to be restricted by IN() function. - * @param mixed $y Argument to be used in IN() function. - */ - public function in(string $x, mixed $y): Expr\Func - { - if (is_iterable($y)) { - if ($y instanceof Traversable) { - $y = iterator_to_array($y); - } - - foreach ($y as &$literal) { - if (! ($literal instanceof Expr\Literal)) { - $literal = $this->quoteLiteral($literal); - } - } - } - - return new Expr\Func($x . ' IN', (array) $y); - } - - /** - * Creates a NOT IN() expression with the given arguments. - * - * @param string $x Field in string format to be restricted by NOT IN() function. - * @param mixed $y Argument to be used in NOT IN() function. - */ - public function notIn(string $x, mixed $y): Expr\Func - { - if (is_iterable($y)) { - if ($y instanceof Traversable) { - $y = iterator_to_array($y); - } - - foreach ($y as &$literal) { - if (! ($literal instanceof Expr\Literal)) { - $literal = $this->quoteLiteral($literal); - } - } - } - - return new Expr\Func($x . ' NOT IN', (array) $y); - } - - /** - * Creates an IS NULL expression with the given arguments. - * - * @param string $x Field in string format to be restricted by IS NULL. - */ - public function isNull(string $x): string - { - return $x . ' IS NULL'; - } - - /** - * Creates an IS NOT NULL expression with the given arguments. - * - * @param string $x Field in string format to be restricted by IS NOT NULL. - */ - public function isNotNull(string $x): string - { - return $x . ' IS NOT NULL'; - } - - /** - * Creates a LIKE() comparison expression with the given arguments. - * - * @param string $x Field in string format to be inspected by LIKE() comparison. - * @param mixed $y Argument to be used in LIKE() comparison. - */ - public function like(string $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, 'LIKE', $y); - } - - /** - * Creates a NOT LIKE() comparison expression with the given arguments. - * - * @param string $x Field in string format to be inspected by LIKE() comparison. - * @param mixed $y Argument to be used in LIKE() comparison. - */ - public function notLike(string $x, mixed $y): Expr\Comparison - { - return new Expr\Comparison($x, 'NOT LIKE', $y); - } - - /** - * Creates a CONCAT() function expression with the given arguments. - * - * @param mixed ...$x Arguments to be used in CONCAT() function. - */ - public function concat(mixed ...$x): Expr\Func - { - self::validateVariadicParameter($x); - - return new Expr\Func('CONCAT', $x); - } - - /** - * Creates a SUBSTRING() function expression with the given arguments. - * - * @param mixed $x Argument to be used as string to be cropped by SUBSTRING() function. - * @param int $from Initial offset to start cropping string. May accept negative values. - * @param int|null $len Length of crop. May accept negative values. - */ - public function substring(mixed $x, int $from, int|null $len = null): Expr\Func - { - $args = [$x, $from]; - if ($len !== null) { - $args[] = $len; - } - - return new Expr\Func('SUBSTRING', $args); - } - - /** - * Creates a LOWER() function expression with the given argument. - * - * @param mixed $x Argument to be used in LOWER() function. - * - * @return Expr\Func A LOWER function expression. - */ - public function lower(mixed $x): Expr\Func - { - return new Expr\Func('LOWER', [$x]); - } - - /** - * Creates an UPPER() function expression with the given argument. - * - * @param mixed $x Argument to be used in UPPER() function. - * - * @return Expr\Func An UPPER function expression. - */ - public function upper(mixed $x): Expr\Func - { - return new Expr\Func('UPPER', [$x]); - } - - /** - * Creates a LENGTH() function expression with the given argument. - * - * @param mixed $x Argument to be used as argument of LENGTH() function. - * - * @return Expr\Func A LENGTH function expression. - */ - public function length(mixed $x): Expr\Func - { - return new Expr\Func('LENGTH', [$x]); - } - - /** - * Creates a literal expression of the given argument. - * - * @param scalar $literal Argument to be converted to literal. - */ - public function literal(bool|string|int|float $literal): Expr\Literal - { - return new Expr\Literal($this->quoteLiteral($literal)); - } - - /** - * Quotes a literal value, if necessary, according to the DQL syntax. - * - * @param scalar $literal The literal value. - */ - private function quoteLiteral(bool|string|int|float $literal): string - { - if (is_int($literal) || is_float($literal)) { - return (string) $literal; - } - - if (is_bool($literal)) { - return $literal ? 'true' : 'false'; - } - - return "'" . str_replace("'", "''", $literal) . "'"; - } - - /** - * Creates an instance of BETWEEN() function, with the given argument. - * - * @param mixed $val Valued to be inspected by range values. - * @param int|string $x Starting range value to be used in BETWEEN() function. - * @param int|string $y End point value to be used in BETWEEN() function. - * - * @return string A BETWEEN expression. - */ - public function between(mixed $val, int|string $x, int|string $y): string - { - return $val . ' BETWEEN ' . $x . ' AND ' . $y; - } - - /** - * Creates an instance of TRIM() function, with the given argument. - * - * @param mixed $x Argument to be used as argument of TRIM() function. - * - * @return Expr\Func a TRIM expression. - */ - public function trim(mixed $x): Expr\Func - { - return new Expr\Func('TRIM', $x); - } - - /** - * Creates an instance of MEMBER OF function, with the given arguments. - * - * @param string $x Value to be checked - * @param string $y Value to be checked against - */ - public function isMemberOf(string $x, string $y): Expr\Comparison - { - return new Expr\Comparison($x, 'MEMBER OF', $y); - } - - /** - * Creates an instance of INSTANCE OF function, with the given arguments. - * - * @param string $x Value to be checked - * @param string $y Value to be checked against - */ - public function isInstanceOf(string $x, string $y): Expr\Comparison - { - return new Expr\Comparison($x, 'INSTANCE OF', $y); - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Andx.php b/vendor/doctrine/orm/src/Query/Expr/Andx.php deleted file mode 100644 index a20bcef..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Andx.php +++ /dev/null @@ -1,32 +0,0 @@ - */ - protected array $parts = []; - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Base.php b/vendor/doctrine/orm/src/Query/Expr/Base.php deleted file mode 100644 index e0f2572..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Base.php +++ /dev/null @@ -1,96 +0,0 @@ - */ - protected array $allowedClasses = []; - - /** @var list */ - protected array $parts = []; - - public function __construct(mixed $args = []) - { - if (is_array($args) && array_key_exists(0, $args) && is_array($args[0])) { - $args = $args[0]; - } - - $this->addMultiple($args); - } - - /** - * @param string[]|object[]|string|object $args - * @psalm-param list|string|object $args - * - * @return $this - */ - public function addMultiple(array|string|object $args = []): static - { - foreach ((array) $args as $arg) { - $this->add($arg); - } - - return $this; - } - - /** - * @return $this - * - * @throws InvalidArgumentException - */ - public function add(mixed $arg): static - { - if ($arg !== null && (! $arg instanceof self || $arg->count() > 0)) { - // If we decide to keep Expr\Base instances, we can use this check - if (! is_string($arg) && ! in_array($arg::class, $this->allowedClasses, true)) { - throw new InvalidArgumentException(sprintf( - "Expression of type '%s' not allowed in this context.", - get_debug_type($arg), - )); - } - - $this->parts[] = $arg; - } - - return $this; - } - - /** @psalm-return 0|positive-int */ - public function count(): int - { - return count($this->parts); - } - - public function __toString(): string - { - if ($this->count() === 1) { - return (string) $this->parts[0]; - } - - return $this->preSeparator . implode($this->separator, $this->parts) . $this->postSeparator; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Comparison.php b/vendor/doctrine/orm/src/Query/Expr/Comparison.php deleted file mode 100644 index ec8ef21..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Comparison.php +++ /dev/null @@ -1,47 +0,0 @@ -'; - final public const LT = '<'; - final public const LTE = '<='; - final public const GT = '>'; - final public const GTE = '>='; - - /** Creates a comparison expression with the given arguments. */ - public function __construct(protected mixed $leftExpr, protected string $operator, protected mixed $rightExpr) - { - } - - public function getLeftExpr(): mixed - { - return $this->leftExpr; - } - - public function getOperator(): string - { - return $this->operator; - } - - public function getRightExpr(): mixed - { - return $this->rightExpr; - } - - public function __toString(): string - { - return $this->leftExpr . ' ' . $this->operator . ' ' . $this->rightExpr; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Composite.php b/vendor/doctrine/orm/src/Query/Expr/Composite.php deleted file mode 100644 index f3007a7..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Composite.php +++ /dev/null @@ -1,50 +0,0 @@ -count() === 1) { - return (string) $this->parts[0]; - } - - $components = []; - - foreach ($this->parts as $part) { - $components[] = $this->processQueryPart($part); - } - - return implode($this->separator, $components); - } - - private function processQueryPart(string|Stringable $part): string - { - $queryPart = (string) $part; - - if (is_object($part) && $part instanceof self && $part->count() > 1) { - return $this->preSeparator . $queryPart . $this->postSeparator; - } - - // Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND") - if (preg_match('/\s(OR|AND)\s/i', $queryPart)) { - return $this->preSeparator . $queryPart . $this->postSeparator; - } - - return $queryPart; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/From.php b/vendor/doctrine/orm/src/Query/Expr/From.php deleted file mode 100644 index 21af078..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/From.php +++ /dev/null @@ -1,48 +0,0 @@ -from; - } - - public function getAlias(): string - { - return $this->alias; - } - - public function getIndexBy(): string|null - { - return $this->indexBy; - } - - public function __toString(): string - { - return $this->from . ' ' . $this->alias . - ($this->indexBy ? ' INDEX BY ' . $this->indexBy : ''); - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Func.php b/vendor/doctrine/orm/src/Query/Expr/Func.php deleted file mode 100644 index cd9e8e0..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Func.php +++ /dev/null @@ -1,48 +0,0 @@ -|mixed $arguments - */ - public function __construct( - protected string $name, - mixed $arguments, - ) { - $this->arguments = (array) $arguments; - } - - public function getName(): string - { - return $this->name; - } - - /** @psalm-return list */ - public function getArguments(): array - { - return $this->arguments; - } - - public function __toString(): string - { - return $this->name . '(' . implode(', ', $this->arguments) . ')'; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/GroupBy.php b/vendor/doctrine/orm/src/Query/Expr/GroupBy.php deleted file mode 100644 index fa4625a..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/GroupBy.php +++ /dev/null @@ -1,25 +0,0 @@ - */ - protected array $parts = []; - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Join.php b/vendor/doctrine/orm/src/Query/Expr/Join.php deleted file mode 100644 index c3b6dc9..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Join.php +++ /dev/null @@ -1,77 +0,0 @@ -joinType; - } - - public function getJoin(): string - { - return $this->join; - } - - public function getAlias(): string|null - { - return $this->alias; - } - - /** @psalm-return self::ON|self::WITH|null */ - public function getConditionType(): string|null - { - return $this->conditionType; - } - - public function getCondition(): string|Comparison|Composite|Func|null - { - return $this->condition; - } - - public function getIndexBy(): string|null - { - return $this->indexBy; - } - - public function __toString(): string - { - return strtoupper($this->joinType) . ' JOIN ' . $this->join - . ($this->alias ? ' ' . $this->alias : '') - . ($this->indexBy ? ' INDEX BY ' . $this->indexBy : '') - . ($this->condition ? ' ' . strtoupper($this->conditionType) . ' ' . $this->condition : ''); - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Literal.php b/vendor/doctrine/orm/src/Query/Expr/Literal.php deleted file mode 100644 index 0c13030..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Literal.php +++ /dev/null @@ -1,25 +0,0 @@ - */ - protected array $parts = []; - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Math.php b/vendor/doctrine/orm/src/Query/Expr/Math.php deleted file mode 100644 index 05e0b39..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Math.php +++ /dev/null @@ -1,59 +0,0 @@ -leftExpr; - } - - public function getOperator(): string - { - return $this->operator; - } - - public function getRightExpr(): mixed - { - return $this->rightExpr; - } - - public function __toString(): string - { - // Adjusting Left Expression - $leftExpr = (string) $this->leftExpr; - - if ($this->leftExpr instanceof Math) { - $leftExpr = '(' . $leftExpr . ')'; - } - - // Adjusting Right Expression - $rightExpr = (string) $this->rightExpr; - - if ($this->rightExpr instanceof Math) { - $rightExpr = '(' . $rightExpr . ')'; - } - - return $leftExpr . ' ' . $this->operator . ' ' . $rightExpr; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/OrderBy.php b/vendor/doctrine/orm/src/Query/Expr/OrderBy.php deleted file mode 100644 index ac9e160..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/OrderBy.php +++ /dev/null @@ -1,60 +0,0 @@ - */ - protected array $parts = []; - - public function __construct( - string|null $sort = null, - string|null $order = null, - ) { - if ($sort) { - $this->add($sort, $order); - } - } - - public function add(string $sort, string|null $order = null): void - { - $order = ! $order ? 'ASC' : $order; - $this->parts[] = $sort . ' ' . $order; - } - - /** @psalm-return 0|positive-int */ - public function count(): int - { - return count($this->parts); - } - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } - - public function __toString(): string - { - return $this->preSeparator . implode($this->separator, $this->parts) . $this->postSeparator; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Orx.php b/vendor/doctrine/orm/src/Query/Expr/Orx.php deleted file mode 100644 index 2ae2332..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Orx.php +++ /dev/null @@ -1,32 +0,0 @@ - */ - protected array $parts = []; - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } -} diff --git a/vendor/doctrine/orm/src/Query/Expr/Select.php b/vendor/doctrine/orm/src/Query/Expr/Select.php deleted file mode 100644 index 91b0b60..0000000 --- a/vendor/doctrine/orm/src/Query/Expr/Select.php +++ /dev/null @@ -1,28 +0,0 @@ - */ - protected array $parts = []; - - /** @psalm-return list */ - public function getParts(): array - { - return $this->parts; - } -} diff --git a/vendor/doctrine/orm/src/Query/Filter/FilterException.php b/vendor/doctrine/orm/src/Query/Filter/FilterException.php deleted file mode 100644 index 37f12bc..0000000 --- a/vendor/doctrine/orm/src/Query/Filter/FilterException.php +++ /dev/null @@ -1,23 +0,0 @@ - - */ - private array $parameters = []; - - final public function __construct( - private readonly EntityManagerInterface $em, - ) { - } - - /** - * Sets a parameter list that can be used by the filter. - * - * @param array $values List of parameter values. - * @param string $type The parameter type. If specified, the given value will be run through - * the type conversion of this type. - * - * @return $this - */ - final public function setParameterList(string $name, array $values, string $type = Types::STRING): static - { - $this->parameters[$name] = ['value' => $values, 'type' => $type, 'is_list' => true]; - - // Keep the parameters sorted for the hash - ksort($this->parameters); - - // The filter collection of the EM is now dirty - $this->em->getFilters()->setFiltersStateDirty(); - - return $this; - } - - /** - * Sets a parameter that can be used by the filter. - * - * @param string|null $type The parameter type. If specified, the given value will be run through - * the type conversion of this type. This is usually not needed for - * strings and numeric types. - * - * @return $this - */ - final public function setParameter(string $name, mixed $value, string|null $type = null): static - { - if ($type === null) { - $type = ParameterTypeInferer::inferType($value); - } - - $this->parameters[$name] = ['value' => $value, 'type' => $type, 'is_list' => false]; - - // Keep the parameters sorted for the hash - ksort($this->parameters); - - // The filter collection of the EM is now dirty - $this->em->getFilters()->setFiltersStateDirty(); - - return $this; - } - - /** - * Gets a parameter to use in a query. - * - * The function is responsible for the right output escaping to use the - * value in a query. - * - * @return string The SQL escaped parameter to use in a query. - * - * @throws InvalidArgumentException - */ - final public function getParameter(string $name): string - { - if (! isset($this->parameters[$name])) { - throw new InvalidArgumentException("Parameter '" . $name . "' does not exist."); - } - - if ($this->parameters[$name]['is_list']) { - throw FilterException::cannotConvertListParameterIntoSingleValue($name); - } - - return $this->em->getConnection()->quote((string) $this->parameters[$name]['value']); - } - - /** - * Gets a parameter to use in a query assuming it's a list of entries. - * - * The function is responsible for the right output escaping to use the - * value in a query, separating each entry by comma to inline it into - * an IN() query part. - * - * @throws InvalidArgumentException - */ - final public function getParameterList(string $name): string - { - if (! isset($this->parameters[$name])) { - throw new InvalidArgumentException("Parameter '" . $name . "' does not exist."); - } - - if ($this->parameters[$name]['is_list'] === false) { - throw FilterException::cannotConvertSingleParameterIntoListValue($name); - } - - $param = $this->parameters[$name]; - $connection = $this->em->getConnection(); - - $quoted = array_map( - static fn (mixed $value): string => $connection->quote((string) $value), - $param['value'], - ); - - return implode(',', $quoted); - } - - /** - * Checks if a parameter was set for the filter. - */ - final public function hasParameter(string $name): bool - { - return isset($this->parameters[$name]); - } - - /** - * Returns as string representation of the SQLFilter parameters (the state). - */ - final public function __toString(): string - { - return serialize($this->parameters); - } - - /** - * Returns the database connection used by the entity manager - */ - final protected function getConnection(): Connection - { - return $this->em->getConnection(); - } - - /** - * Gets the SQL query part to add to a query. - * - * @psalm-param ClassMetadata $targetEntity - * - * @return string The constraint SQL if there is available, empty string otherwise. - */ - abstract public function addFilterConstraint(ClassMetadata $targetEntity, string $targetTableAlias): string; -} diff --git a/vendor/doctrine/orm/src/Query/FilterCollection.php b/vendor/doctrine/orm/src/Query/FilterCollection.php deleted file mode 100644 index 3d3c576..0000000 --- a/vendor/doctrine/orm/src/Query/FilterCollection.php +++ /dev/null @@ -1,260 +0,0 @@ - - */ - private array $enabledFilters = []; - - /** The filter hash from the last time the query was parsed. */ - private string $filterHash = ''; - - /** - * Instances of suspended filters. - * - * @var SQLFilter[] - * @psalm-var array - */ - private array $suspendedFilters = []; - - /** - * The current state of this filter. - * - * @psalm-var self::FILTERS_STATE_* - */ - private int $filtersState = self::FILTERS_STATE_CLEAN; - - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->config = $em->getConfiguration(); - } - - /** - * Gets all the enabled filters. - * - * @return array The enabled filters. - */ - public function getEnabledFilters(): array - { - return $this->enabledFilters; - } - - /** - * Gets all the suspended filters. - * - * @return SQLFilter[] The suspended filters. - * @psalm-return array - */ - public function getSuspendedFilters(): array - { - return $this->suspendedFilters; - } - - /** - * Enables a filter from the collection. - * - * @throws InvalidArgumentException If the filter does not exist. - */ - public function enable(string $name): SQLFilter - { - if (! $this->has($name)) { - throw new InvalidArgumentException("Filter '" . $name . "' does not exist."); - } - - if (! $this->isEnabled($name)) { - $filterClass = $this->config->getFilterClassName($name); - - assert($filterClass !== null); - - $this->enabledFilters[$name] = new $filterClass($this->em); - - // In case a suspended filter with the same name was forgotten - unset($this->suspendedFilters[$name]); - - // Keep the enabled filters sorted for the hash - ksort($this->enabledFilters); - - $this->setFiltersStateDirty(); - } - - return $this->enabledFilters[$name]; - } - - /** - * Disables a filter. - * - * @throws InvalidArgumentException If the filter does not exist. - */ - public function disable(string $name): SQLFilter - { - // Get the filter to return it - $filter = $this->getFilter($name); - - unset($this->enabledFilters[$name]); - - $this->setFiltersStateDirty(); - - return $filter; - } - - /** - * Suspend a filter. - * - * @param string $name Name of the filter. - * - * @return SQLFilter The suspended filter. - * - * @throws InvalidArgumentException If the filter does not exist. - */ - public function suspend(string $name): SQLFilter - { - // Get the filter to return it - $filter = $this->getFilter($name); - - $this->suspendedFilters[$name] = $filter; - unset($this->enabledFilters[$name]); - - $this->setFiltersStateDirty(); - - return $filter; - } - - /** - * Restore a disabled filter from the collection. - * - * @param string $name Name of the filter. - * - * @return SQLFilter The restored filter. - * - * @throws InvalidArgumentException If the filter does not exist. - */ - public function restore(string $name): SQLFilter - { - if (! $this->isSuspended($name)) { - throw new InvalidArgumentException("Filter '" . $name . "' is not suspended."); - } - - $this->enabledFilters[$name] = $this->suspendedFilters[$name]; - unset($this->suspendedFilters[$name]); - - // Keep the enabled filters sorted for the hash - ksort($this->enabledFilters); - - $this->setFiltersStateDirty(); - - return $this->enabledFilters[$name]; - } - - /** - * Gets an enabled filter from the collection. - * - * @throws InvalidArgumentException If the filter is not enabled. - */ - public function getFilter(string $name): SQLFilter - { - if (! $this->isEnabled($name)) { - throw new InvalidArgumentException("Filter '" . $name . "' is not enabled."); - } - - return $this->enabledFilters[$name]; - } - - /** - * Checks whether filter with given name is defined. - */ - public function has(string $name): bool - { - return $this->config->getFilterClassName($name) !== null; - } - - /** - * Checks if a filter is enabled. - */ - public function isEnabled(string $name): bool - { - return isset($this->enabledFilters[$name]); - } - - /** - * Checks if a filter is suspended. - * - * @param string $name Name of the filter. - * - * @return bool True if the filter is suspended, false otherwise. - */ - public function isSuspended(string $name): bool - { - return isset($this->suspendedFilters[$name]); - } - - /** - * Checks if the filter collection is clean. - */ - public function isClean(): bool - { - return $this->filtersState === self::FILTERS_STATE_CLEAN; - } - - /** - * Generates a string of currently enabled filters to use for the cache id. - */ - public function getHash(): string - { - // If there are only clean filters, the previous hash can be returned - if ($this->filtersState === self::FILTERS_STATE_CLEAN) { - return $this->filterHash; - } - - $filterHash = ''; - - foreach ($this->enabledFilters as $name => $filter) { - $filterHash .= $name . $filter; - } - - $this->filterHash = $filterHash; - $this->filtersState = self::FILTERS_STATE_CLEAN; - - return $filterHash; - } - - /** - * Sets the filter state to dirty. - */ - public function setFiltersStateDirty(): void - { - $this->filtersState = self::FILTERS_STATE_DIRTY; - } -} diff --git a/vendor/doctrine/orm/src/Query/Lexer.php b/vendor/doctrine/orm/src/Query/Lexer.php deleted file mode 100644 index c446675..0000000 --- a/vendor/doctrine/orm/src/Query/Lexer.php +++ /dev/null @@ -1,150 +0,0 @@ - - */ -class Lexer extends AbstractLexer -{ - /** - * Creates a new query scanner object. - * - * @param string $input A query string. - */ - public function __construct(string $input) - { - $this->setInput($input); - } - - /** - * {@inheritDoc} - */ - protected function getCatchablePatterns(): array - { - return [ - '[a-z_][a-z0-9_]*\:[a-z_][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // aliased name - '[a-z_\\\][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // identifier or qualified name - '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', // numbers - "'(?:[^']|'')*'", // quoted strings - '\?[0-9]*|:[a-z_][a-z0-9_]*', // parameters - ]; - } - - /** - * {@inheritDoc} - */ - protected function getNonCatchablePatterns(): array - { - return ['\s+', '--.*', '(.)']; - } - - protected function getType(string &$value): TokenType - { - $type = TokenType::T_NONE; - - switch (true) { - // Recognize numeric values - case is_numeric($value): - if (str_contains($value, '.') || stripos($value, 'e') !== false) { - return TokenType::T_FLOAT; - } - - return TokenType::T_INTEGER; - - // Recognize quoted strings - case $value[0] === "'": - $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2)); - - return TokenType::T_STRING; - - // Recognize identifiers, aliased or qualified names - case ctype_alpha($value[0]) || $value[0] === '_' || $value[0] === '\\': - $name = 'Doctrine\ORM\Query\TokenType::T_' . strtoupper($value); - - if (defined($name)) { - $type = constant($name); - - if ($type->value > 100) { - return $type; - } - } - - if (str_contains($value, '\\')) { - return TokenType::T_FULLY_QUALIFIED_NAME; - } - - return TokenType::T_IDENTIFIER; - - // Recognize input parameters - case $value[0] === '?' || $value[0] === ':': - return TokenType::T_INPUT_PARAMETER; - - // Recognize symbols - case $value === '.': - return TokenType::T_DOT; - - case $value === ',': - return TokenType::T_COMMA; - - case $value === '(': - return TokenType::T_OPEN_PARENTHESIS; - - case $value === ')': - return TokenType::T_CLOSE_PARENTHESIS; - - case $value === '=': - return TokenType::T_EQUALS; - - case $value === '>': - return TokenType::T_GREATER_THAN; - - case $value === '<': - return TokenType::T_LOWER_THAN; - - case $value === '+': - return TokenType::T_PLUS; - - case $value === '-': - return TokenType::T_MINUS; - - case $value === '*': - return TokenType::T_MULTIPLY; - - case $value === '/': - return TokenType::T_DIVIDE; - - case $value === '!': - return TokenType::T_NEGATE; - - case $value === '{': - return TokenType::T_OPEN_CURLY_BRACE; - - case $value === '}': - return TokenType::T_CLOSE_CURLY_BRACE; - - // Default - default: - // Do nothing - } - - return $type; - } -} diff --git a/vendor/doctrine/orm/src/Query/Parameter.php b/vendor/doctrine/orm/src/Query/Parameter.php deleted file mode 100644 index 43eb7a4..0000000 --- a/vendor/doctrine/orm/src/Query/Parameter.php +++ /dev/null @@ -1,89 +0,0 @@ -name = self::normalizeName($name); - $this->typeSpecified = $type !== null; - - $this->setValue($value, $type); - } - - /** - * Retrieves the Parameter name. - */ - public function getName(): string - { - return $this->name; - } - - /** - * Retrieves the Parameter value. - */ - public function getValue(): mixed - { - return $this->value; - } - - /** - * Retrieves the Parameter type. - */ - public function getType(): mixed - { - return $this->type; - } - - /** - * Defines the Parameter value. - */ - public function setValue(mixed $value, mixed $type = null): void - { - $this->value = $value; - $this->type = $type ?: ParameterTypeInferer::inferType($value); - } - - public function typeWasSpecified(): bool - { - return $this->typeSpecified; - } -} diff --git a/vendor/doctrine/orm/src/Query/ParameterTypeInferer.php b/vendor/doctrine/orm/src/Query/ParameterTypeInferer.php deleted file mode 100644 index dae28fa..0000000 --- a/vendor/doctrine/orm/src/Query/ParameterTypeInferer.php +++ /dev/null @@ -1,77 +0,0 @@ -value) - ? Types::INTEGER - : Types::STRING; - } - - if (is_array($value)) { - $firstValue = current($value); - if ($firstValue instanceof BackedEnum) { - $firstValue = $firstValue->value; - } - - return is_int($firstValue) - ? ArrayParameterType::INTEGER - : ArrayParameterType::STRING; - } - - return ParameterType::STRING; - } - - private function __construct() - { - } -} diff --git a/vendor/doctrine/orm/src/Query/Parser.php b/vendor/doctrine/orm/src/Query/Parser.php deleted file mode 100644 index e948f2c..0000000 --- a/vendor/doctrine/orm/src/Query/Parser.php +++ /dev/null @@ -1,3269 +0,0 @@ - - * @psalm-type QueryComponent = array{ - * metadata?: ClassMetadata, - * parent?: string|null, - * relation?: AssociationMapping|null, - * map?: string|null, - * resultVariable?: AST\Node|string, - * nestingLevel: int, - * token: DqlToken, - * } - */ -final class Parser -{ - /** - * @readonly Maps BUILT-IN string function names to AST class names. - * @psalm-var array> - */ - private static array $stringFunctions = [ - 'concat' => Functions\ConcatFunction::class, - 'substring' => Functions\SubstringFunction::class, - 'trim' => Functions\TrimFunction::class, - 'lower' => Functions\LowerFunction::class, - 'upper' => Functions\UpperFunction::class, - 'identity' => Functions\IdentityFunction::class, - ]; - - /** - * @readonly Maps BUILT-IN numeric function names to AST class names. - * @psalm-var array> - */ - private static array $numericFunctions = [ - 'length' => Functions\LengthFunction::class, - 'locate' => Functions\LocateFunction::class, - 'abs' => Functions\AbsFunction::class, - 'sqrt' => Functions\SqrtFunction::class, - 'mod' => Functions\ModFunction::class, - 'size' => Functions\SizeFunction::class, - 'date_diff' => Functions\DateDiffFunction::class, - 'bit_and' => Functions\BitAndFunction::class, - 'bit_or' => Functions\BitOrFunction::class, - - // Aggregate functions - 'min' => Functions\MinFunction::class, - 'max' => Functions\MaxFunction::class, - 'avg' => Functions\AvgFunction::class, - 'sum' => Functions\SumFunction::class, - 'count' => Functions\CountFunction::class, - ]; - - /** - * @readonly Maps BUILT-IN datetime function names to AST class names. - * @psalm-var array> - */ - private static array $datetimeFunctions = [ - 'current_date' => Functions\CurrentDateFunction::class, - 'current_time' => Functions\CurrentTimeFunction::class, - 'current_timestamp' => Functions\CurrentTimestampFunction::class, - 'date_add' => Functions\DateAddFunction::class, - 'date_sub' => Functions\DateSubFunction::class, - ]; - - /* - * Expressions that were encountered during parsing of identifiers and expressions - * and still need to be validated. - */ - - /** @psalm-var list */ - private array $deferredIdentificationVariables = []; - - /** @psalm-var list */ - private array $deferredPathExpressions = []; - - /** @psalm-var list */ - private array $deferredResultVariables = []; - - /** @psalm-var list */ - private array $deferredNewObjectExpressions = []; - - /** - * The lexer. - */ - private readonly Lexer $lexer; - - /** - * The parser result. - */ - private readonly ParserResult $parserResult; - - /** - * The EntityManager. - */ - private readonly EntityManagerInterface $em; - - /** - * Map of declared query components in the parsed query. - * - * @psalm-var array - */ - private array $queryComponents = []; - - /** - * Keeps the nesting level of defined ResultVariables. - */ - private int $nestingLevel = 0; - - /** - * Any additional custom tree walkers that modify the AST. - * - * @psalm-var list> - */ - private array $customTreeWalkers = []; - - /** - * The custom last tree walker, if any, that is responsible for producing the output. - * - * @var class-string|null - */ - private $customOutputWalker; - - /** @psalm-var array */ - private array $identVariableExpressions = []; - - /** - * Creates a new query parser object. - * - * @param Query $query The Query to parse. - */ - public function __construct(private readonly Query $query) - { - $this->em = $query->getEntityManager(); - $this->lexer = new Lexer((string) $query->getDQL()); - $this->parserResult = new ParserResult(); - } - - /** - * Sets a custom tree walker that produces output. - * This tree walker will be run last over the AST, after any other walkers. - * - * @psalm-param class-string $className - */ - public function setCustomOutputTreeWalker(string $className): void - { - $this->customOutputWalker = $className; - } - - /** - * Adds a custom tree walker for modifying the AST. - * - * @psalm-param class-string $className - */ - public function addCustomTreeWalker(string $className): void - { - $this->customTreeWalkers[] = $className; - } - - /** - * Gets the lexer used by the parser. - */ - public function getLexer(): Lexer - { - return $this->lexer; - } - - /** - * Gets the ParserResult that is being filled with information during parsing. - */ - public function getParserResult(): ParserResult - { - return $this->parserResult; - } - - /** - * Gets the EntityManager used by the parser. - */ - public function getEntityManager(): EntityManagerInterface - { - return $this->em; - } - - /** - * Parses and builds AST for the given Query. - */ - public function getAST(): AST\SelectStatement|AST\UpdateStatement|AST\DeleteStatement - { - // Parse & build AST - $AST = $this->QueryLanguage(); - - // Process any deferred validations of some nodes in the AST. - // This also allows post-processing of the AST for modification purposes. - $this->processDeferredIdentificationVariables(); - - if ($this->deferredPathExpressions) { - $this->processDeferredPathExpressions(); - } - - if ($this->deferredResultVariables) { - $this->processDeferredResultVariables(); - } - - if ($this->deferredNewObjectExpressions) { - $this->processDeferredNewObjectExpressions($AST); - } - - $this->processRootEntityAliasSelected(); - - // TODO: Is there a way to remove this? It may impact the mixed hydration resultset a lot! - $this->fixIdentificationVariableOrder($AST); - - return $AST; - } - - /** - * Attempts to match the given token with the current lookahead token. - * - * If they match, updates the lookahead token; otherwise raises a syntax - * error. - * - * @throws QueryException If the tokens don't match. - */ - public function match(TokenType $token): void - { - $lookaheadType = $this->lexer->lookahead->type ?? null; - - // Short-circuit on first condition, usually types match - if ($lookaheadType === $token) { - $this->lexer->moveNext(); - - return; - } - - // If parameter is not identifier (1-99) must be exact match - if ($token->value < TokenType::T_IDENTIFIER->value) { - $this->syntaxError($this->lexer->getLiteral($token)); - } - - // If parameter is keyword (200+) must be exact match - if ($token->value > TokenType::T_IDENTIFIER->value) { - $this->syntaxError($this->lexer->getLiteral($token)); - } - - // If parameter is T_IDENTIFIER, then matches T_IDENTIFIER (100) and keywords (200+) - if ($token->value === TokenType::T_IDENTIFIER->value && $lookaheadType->value < TokenType::T_IDENTIFIER->value) { - $this->syntaxError($this->lexer->getLiteral($token)); - } - - $this->lexer->moveNext(); - } - - /** - * Frees this parser, enabling it to be reused. - * - * @param bool $deep Whether to clean peek and reset errors. - * @param int $position Position to reset. - */ - public function free(bool $deep = false, int $position = 0): void - { - // WARNING! Use this method with care. It resets the scanner! - $this->lexer->resetPosition($position); - - // Deep = true cleans peek and also any previously defined errors - if ($deep) { - $this->lexer->resetPeek(); - } - - $this->lexer->token = null; - $this->lexer->lookahead = null; - } - - /** - * Parses a query string. - */ - public function parse(): ParserResult - { - $AST = $this->getAST(); - - $customWalkers = $this->query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); - if ($customWalkers !== false) { - $this->customTreeWalkers = $customWalkers; - } - - $customOutputWalker = $this->query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER); - if ($customOutputWalker !== false) { - $this->customOutputWalker = $customOutputWalker; - } - - // Run any custom tree walkers over the AST - if ($this->customTreeWalkers) { - $treeWalkerChain = new TreeWalkerChain($this->query, $this->parserResult, $this->queryComponents); - - foreach ($this->customTreeWalkers as $walker) { - $treeWalkerChain->addTreeWalker($walker); - } - - match (true) { - $AST instanceof AST\UpdateStatement => $treeWalkerChain->walkUpdateStatement($AST), - $AST instanceof AST\DeleteStatement => $treeWalkerChain->walkDeleteStatement($AST), - $AST instanceof AST\SelectStatement => $treeWalkerChain->walkSelectStatement($AST), - }; - - $this->queryComponents = $treeWalkerChain->getQueryComponents(); - } - - $outputWalkerClass = $this->customOutputWalker ?: SqlWalker::class; - $outputWalker = new $outputWalkerClass($this->query, $this->parserResult, $this->queryComponents); - - // Assign an SQL executor to the parser result - $this->parserResult->setSqlExecutor($outputWalker->getExecutor($AST)); - - return $this->parserResult; - } - - /** - * Fixes order of identification variables. - * - * They have to appear in the select clause in the same order as the - * declarations (from ... x join ... y join ... z ...) appear in the query - * as the hydration process relies on that order for proper operation. - */ - private function fixIdentificationVariableOrder(AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST): void - { - if (count($this->identVariableExpressions) <= 1) { - return; - } - - assert($AST instanceof AST\SelectStatement); - - foreach ($this->queryComponents as $dqlAlias => $qComp) { - if (! isset($this->identVariableExpressions[$dqlAlias])) { - continue; - } - - $expr = $this->identVariableExpressions[$dqlAlias]; - $key = array_search($expr, $AST->selectClause->selectExpressions, true); - - unset($AST->selectClause->selectExpressions[$key]); - - $AST->selectClause->selectExpressions[] = $expr; - } - } - - /** - * Generates a new syntax error. - * - * @param string $expected Expected string. - * @param DqlToken|null $token Got token. - * - * @throws QueryException - */ - public function syntaxError(string $expected = '', Token|null $token = null): never - { - if ($token === null) { - $token = $this->lexer->lookahead; - } - - $tokenPos = $token->position ?? '-1'; - - $message = sprintf('line 0, col %d: Error: ', $tokenPos); - $message .= $expected !== '' ? sprintf('Expected %s, got ', $expected) : 'Unexpected '; - $message .= $this->lexer->lookahead === null ? 'end of string.' : sprintf("'%s'", $token->value); - - throw QueryException::syntaxError($message, QueryException::dqlError($this->query->getDQL() ?? '')); - } - - /** - * Generates a new semantical error. - * - * @param string $message Optional message. - * @psalm-param DqlToken|null $token - * - * @throws QueryException - */ - public function semanticalError(string $message = '', Token|null $token = null): never - { - if ($token === null) { - $token = $this->lexer->lookahead ?? new Token('fake token', 42, 0); - } - - // Minimum exposed chars ahead of token - $distance = 12; - - // Find a position of a final word to display in error string - $dql = $this->query->getDQL(); - $length = strlen($dql); - $pos = $token->position + $distance; - $pos = strpos($dql, ' ', $length > $pos ? $pos : $length); - $length = $pos !== false ? $pos - $token->position : $distance; - - $tokenPos = $token->position > 0 ? $token->position : '-1'; - $tokenStr = substr($dql, $token->position, $length); - - // Building informative message - $message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message; - - throw QueryException::semanticalError($message, QueryException::dqlError($this->query->getDQL())); - } - - /** - * Peeks beyond the matched closing parenthesis and returns the first token after that one. - * - * @param bool $resetPeek Reset peek after finding the closing parenthesis. - * - * @psalm-return DqlToken|null - */ - private function peekBeyondClosingParenthesis(bool $resetPeek = true): Token|null - { - $token = $this->lexer->peek(); - $numUnmatched = 1; - - while ($numUnmatched > 0 && $token !== null) { - switch ($token->type) { - case TokenType::T_OPEN_PARENTHESIS: - ++$numUnmatched; - break; - - case TokenType::T_CLOSE_PARENTHESIS: - --$numUnmatched; - break; - - default: - // Do nothing - } - - $token = $this->lexer->peek(); - } - - if ($resetPeek) { - $this->lexer->resetPeek(); - } - - return $token; - } - - /** - * Checks if the given token indicates a mathematical operator. - * - * @psalm-param DqlToken|null $token - */ - private function isMathOperator(Token|null $token): bool - { - return $token !== null && in_array($token->type, [TokenType::T_PLUS, TokenType::T_MINUS, TokenType::T_DIVIDE, TokenType::T_MULTIPLY], true); - } - - /** - * Checks if the next-next (after lookahead) token starts a function. - * - * @return bool TRUE if the next-next tokens start a function, FALSE otherwise. - */ - private function isFunction(): bool - { - assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead->type; - $peek = $this->lexer->peek(); - - $this->lexer->resetPeek(); - - return $lookaheadType->value >= TokenType::T_IDENTIFIER->value && $peek !== null && $peek->type === TokenType::T_OPEN_PARENTHESIS; - } - - /** - * Checks whether the given token type indicates an aggregate function. - * - * @return bool TRUE if the token type is an aggregate function, FALSE otherwise. - */ - private function isAggregateFunction(TokenType $tokenType): bool - { - return in_array( - $tokenType, - [TokenType::T_AVG, TokenType::T_MIN, TokenType::T_MAX, TokenType::T_SUM, TokenType::T_COUNT], - true, - ); - } - - /** - * Checks whether the current lookahead token of the lexer has the type T_ALL, T_ANY or T_SOME. - */ - private function isNextAllAnySome(): bool - { - assert($this->lexer->lookahead !== null); - - return in_array( - $this->lexer->lookahead->type, - [TokenType::T_ALL, TokenType::T_ANY, TokenType::T_SOME], - true, - ); - } - - /** - * Validates that the given IdentificationVariable is semantically correct. - * It must exist in query components list. - */ - private function processDeferredIdentificationVariables(): void - { - foreach ($this->deferredIdentificationVariables as $deferredItem) { - $identVariable = $deferredItem['expression']; - - // Check if IdentificationVariable exists in queryComponents - if (! isset($this->queryComponents[$identVariable])) { - $this->semanticalError( - sprintf("'%s' is not defined.", $identVariable), - $deferredItem['token'], - ); - } - - $qComp = $this->queryComponents[$identVariable]; - - // Check if queryComponent points to an AbstractSchemaName or a ResultVariable - if (! isset($qComp['metadata'])) { - $this->semanticalError( - sprintf("'%s' does not point to a Class.", $identVariable), - $deferredItem['token'], - ); - } - - // Validate if identification variable nesting level is lower or equal than the current one - if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) { - $this->semanticalError( - sprintf("'%s' is used outside the scope of its declaration.", $identVariable), - $deferredItem['token'], - ); - } - } - } - - /** - * Validates that the given NewObjectExpression. - */ - private function processDeferredNewObjectExpressions(AST\SelectStatement $AST): void - { - foreach ($this->deferredNewObjectExpressions as $deferredItem) { - $expression = $deferredItem['expression']; - $token = $deferredItem['token']; - $className = $expression->className; - $args = $expression->args; - $fromClassName = $AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName ?? null; - - // If the namespace is not given then assumes the first FROM entity namespace - if (! str_contains($className, '\\') && ! class_exists($className) && is_string($fromClassName) && str_contains($fromClassName, '\\')) { - $namespace = substr($fromClassName, 0, strrpos($fromClassName, '\\')); - $fqcn = $namespace . '\\' . $className; - - if (class_exists($fqcn)) { - $expression->className = $fqcn; - $className = $fqcn; - } - } - - if (! class_exists($className)) { - $this->semanticalError(sprintf('Class "%s" is not defined.', $className), $token); - } - - $class = new ReflectionClass($className); - - if (! $class->isInstantiable()) { - $this->semanticalError(sprintf('Class "%s" can not be instantiated.', $className), $token); - } - - if ($class->getConstructor() === null) { - $this->semanticalError(sprintf('Class "%s" has not a valid constructor.', $className), $token); - } - - if ($class->getConstructor()->getNumberOfRequiredParameters() > count($args)) { - $this->semanticalError(sprintf('Number of arguments does not match with "%s" constructor declaration.', $className), $token); - } - } - } - - /** - * Validates that the given ResultVariable is semantically correct. - * It must exist in query components list. - */ - private function processDeferredResultVariables(): void - { - foreach ($this->deferredResultVariables as $deferredItem) { - $resultVariable = $deferredItem['expression']; - - // Check if ResultVariable exists in queryComponents - if (! isset($this->queryComponents[$resultVariable])) { - $this->semanticalError( - sprintf("'%s' is not defined.", $resultVariable), - $deferredItem['token'], - ); - } - - $qComp = $this->queryComponents[$resultVariable]; - - // Check if queryComponent points to an AbstractSchemaName or a ResultVariable - if (! isset($qComp['resultVariable'])) { - $this->semanticalError( - sprintf("'%s' does not point to a ResultVariable.", $resultVariable), - $deferredItem['token'], - ); - } - - // Validate if identification variable nesting level is lower or equal than the current one - if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) { - $this->semanticalError( - sprintf("'%s' is used outside the scope of its declaration.", $resultVariable), - $deferredItem['token'], - ); - } - } - } - - /** - * Validates that the given PathExpression is semantically correct for grammar rules: - * - * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression - * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression - * StateFieldPathExpression ::= IdentificationVariable "." StateField - * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField - * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField - */ - private function processDeferredPathExpressions(): void - { - foreach ($this->deferredPathExpressions as $deferredItem) { - $pathExpression = $deferredItem['expression']; - - $class = $this->getMetadataForDqlAlias($pathExpression->identificationVariable); - - $field = $pathExpression->field; - if ($field === null) { - $field = $pathExpression->field = $class->identifier[0]; - } - - // Check if field or association exists - if (! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) { - $this->semanticalError( - 'Class ' . $class->name . ' has no field or association named ' . $field, - $deferredItem['token'], - ); - } - - $fieldType = AST\PathExpression::TYPE_STATE_FIELD; - - if (isset($class->associationMappings[$field])) { - $assoc = $class->associationMappings[$field]; - - $fieldType = $assoc->isToOne() - ? AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION - : AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION; - } - - // Validate if PathExpression is one of the expected types - $expectedType = $pathExpression->expectedType; - - if (! ($expectedType & $fieldType)) { - // We need to recognize which was expected type(s) - $expectedStringTypes = []; - - // Validate state field type - if ($expectedType & AST\PathExpression::TYPE_STATE_FIELD) { - $expectedStringTypes[] = 'StateFieldPathExpression'; - } - - // Validate single valued association (*-to-one) - if ($expectedType & AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) { - $expectedStringTypes[] = 'SingleValuedAssociationField'; - } - - // Validate single valued association (*-to-many) - if ($expectedType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) { - $expectedStringTypes[] = 'CollectionValuedAssociationField'; - } - - // Build the error message - $semanticalError = 'Invalid PathExpression. '; - $semanticalError .= count($expectedStringTypes) === 1 - ? 'Must be a ' . $expectedStringTypes[0] . '.' - : implode(' or ', $expectedStringTypes) . ' expected.'; - - $this->semanticalError($semanticalError, $deferredItem['token']); - } - - // We need to force the type in PathExpression - $pathExpression->type = $fieldType; - } - } - - private function processRootEntityAliasSelected(): void - { - if (! count($this->identVariableExpressions)) { - return; - } - - foreach ($this->identVariableExpressions as $dqlAlias => $expr) { - if (isset($this->queryComponents[$dqlAlias]) && ! isset($this->queryComponents[$dqlAlias]['parent'])) { - return; - } - } - - $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.'); - } - - /** - * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement - */ - public function QueryLanguage(): AST\SelectStatement|AST\UpdateStatement|AST\DeleteStatement - { - $statement = null; - - $this->lexer->moveNext(); - - switch ($this->lexer->lookahead->type ?? null) { - case TokenType::T_SELECT: - $statement = $this->SelectStatement(); - break; - - case TokenType::T_UPDATE: - $statement = $this->UpdateStatement(); - break; - - case TokenType::T_DELETE: - $statement = $this->DeleteStatement(); - break; - - default: - $this->syntaxError('SELECT, UPDATE or DELETE'); - break; - } - - // Check for end of string - if ($this->lexer->lookahead !== null) { - $this->syntaxError('end of string'); - } - - return $statement; - } - - /** - * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - */ - public function SelectStatement(): AST\SelectStatement - { - $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause()); - - $selectStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; - $selectStatement->groupByClause = $this->lexer->isNextToken(TokenType::T_GROUP) ? $this->GroupByClause() : null; - $selectStatement->havingClause = $this->lexer->isNextToken(TokenType::T_HAVING) ? $this->HavingClause() : null; - $selectStatement->orderByClause = $this->lexer->isNextToken(TokenType::T_ORDER) ? $this->OrderByClause() : null; - - return $selectStatement; - } - - /** - * UpdateStatement ::= UpdateClause [WhereClause] - */ - public function UpdateStatement(): AST\UpdateStatement - { - $updateStatement = new AST\UpdateStatement($this->UpdateClause()); - - $updateStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; - - return $updateStatement; - } - - /** - * DeleteStatement ::= DeleteClause [WhereClause] - */ - public function DeleteStatement(): AST\DeleteStatement - { - $deleteStatement = new AST\DeleteStatement($this->DeleteClause()); - - $deleteStatement->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; - - return $deleteStatement; - } - - /** - * IdentificationVariable ::= identifier - */ - public function IdentificationVariable(): string - { - $this->match(TokenType::T_IDENTIFIER); - - assert($this->lexer->token !== null); - $identVariable = $this->lexer->token->value; - - $this->deferredIdentificationVariables[] = [ - 'expression' => $identVariable, - 'nestingLevel' => $this->nestingLevel, - 'token' => $this->lexer->token, - ]; - - return $identVariable; - } - - /** - * AliasIdentificationVariable = identifier - */ - public function AliasIdentificationVariable(): string - { - $this->match(TokenType::T_IDENTIFIER); - - assert($this->lexer->token !== null); - $aliasIdentVariable = $this->lexer->token->value; - $exists = isset($this->queryComponents[$aliasIdentVariable]); - - if ($exists) { - $this->semanticalError( - sprintf("'%s' is already defined.", $aliasIdentVariable), - $this->lexer->token, - ); - } - - return $aliasIdentVariable; - } - - /** - * AbstractSchemaName ::= fully_qualified_name | identifier - */ - public function AbstractSchemaName(): string - { - if ($this->lexer->isNextToken(TokenType::T_FULLY_QUALIFIED_NAME)) { - $this->match(TokenType::T_FULLY_QUALIFIED_NAME); - assert($this->lexer->token !== null); - - return $this->lexer->token->value; - } - - $this->match(TokenType::T_IDENTIFIER); - assert($this->lexer->token !== null); - - return $this->lexer->token->value; - } - - /** - * Validates an AbstractSchemaName, making sure the class exists. - * - * @param string $schemaName The name to validate. - * - * @throws QueryException if the name does not exist. - */ - private function validateAbstractSchemaName(string $schemaName): void - { - assert($this->lexer->token !== null); - if (! (class_exists($schemaName, true) || interface_exists($schemaName, true))) { - $this->semanticalError( - sprintf("Class '%s' is not defined.", $schemaName), - $this->lexer->token, - ); - } - } - - /** - * AliasResultVariable ::= identifier - */ - public function AliasResultVariable(): string - { - $this->match(TokenType::T_IDENTIFIER); - - assert($this->lexer->token !== null); - $resultVariable = $this->lexer->token->value; - $exists = isset($this->queryComponents[$resultVariable]); - - if ($exists) { - $this->semanticalError( - sprintf("'%s' is already defined.", $resultVariable), - $this->lexer->token, - ); - } - - return $resultVariable; - } - - /** - * ResultVariable ::= identifier - */ - public function ResultVariable(): string - { - $this->match(TokenType::T_IDENTIFIER); - - assert($this->lexer->token !== null); - $resultVariable = $this->lexer->token->value; - - // Defer ResultVariable validation - $this->deferredResultVariables[] = [ - 'expression' => $resultVariable, - 'nestingLevel' => $this->nestingLevel, - 'token' => $this->lexer->token, - ]; - - return $resultVariable; - } - - /** - * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField) - */ - public function JoinAssociationPathExpression(): AST\JoinAssociationPathExpression - { - $identVariable = $this->IdentificationVariable(); - - if (! isset($this->queryComponents[$identVariable])) { - $this->semanticalError( - 'Identification Variable ' . $identVariable . ' used in join path expression but was not defined before.', - ); - } - - $this->match(TokenType::T_DOT); - $this->match(TokenType::T_IDENTIFIER); - - assert($this->lexer->token !== null); - $field = $this->lexer->token->value; - - // Validate association field - $class = $this->getMetadataForDqlAlias($identVariable); - - if (! $class->hasAssociation($field)) { - $this->semanticalError('Class ' . $class->name . ' has no association named ' . $field); - } - - return new AST\JoinAssociationPathExpression($identVariable, $field); - } - - /** - * Parses an arbitrary path expression and defers semantical validation - * based on expected types. - * - * PathExpression ::= IdentificationVariable {"." identifier}* - * - * @psalm-param int-mask-of $expectedTypes - */ - public function PathExpression(int $expectedTypes): AST\PathExpression - { - $identVariable = $this->IdentificationVariable(); - $field = null; - - assert($this->lexer->token !== null); - if ($this->lexer->isNextToken(TokenType::T_DOT)) { - $this->match(TokenType::T_DOT); - $this->match(TokenType::T_IDENTIFIER); - - $field = $this->lexer->token->value; - - while ($this->lexer->isNextToken(TokenType::T_DOT)) { - $this->match(TokenType::T_DOT); - $this->match(TokenType::T_IDENTIFIER); - $field .= '.' . $this->lexer->token->value; - } - } - - // Creating AST node - $pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field); - - // Defer PathExpression validation if requested to be deferred - $this->deferredPathExpressions[] = [ - 'expression' => $pathExpr, - 'nestingLevel' => $this->nestingLevel, - 'token' => $this->lexer->token, - ]; - - return $pathExpr; - } - - /** - * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression - */ - public function AssociationPathExpression(): AST\PathExpression - { - return $this->PathExpression( - AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION | - AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION, - ); - } - - /** - * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression - */ - public function SingleValuedPathExpression(): AST\PathExpression - { - return $this->PathExpression( - AST\PathExpression::TYPE_STATE_FIELD | - AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, - ); - } - - /** - * StateFieldPathExpression ::= IdentificationVariable "." StateField - */ - public function StateFieldPathExpression(): AST\PathExpression - { - return $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD); - } - - /** - * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField - */ - public function SingleValuedAssociationPathExpression(): AST\PathExpression - { - return $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION); - } - - /** - * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField - */ - public function CollectionValuedPathExpression(): AST\PathExpression - { - return $this->PathExpression(AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION); - } - - /** - * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} - */ - public function SelectClause(): AST\SelectClause - { - $isDistinct = false; - $this->match(TokenType::T_SELECT); - - // Check for DISTINCT - if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { - $this->match(TokenType::T_DISTINCT); - - $isDistinct = true; - } - - // Process SelectExpressions (1..N) - $selectExpressions = []; - $selectExpressions[] = $this->SelectExpression(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $selectExpressions[] = $this->SelectExpression(); - } - - return new AST\SelectClause($selectExpressions, $isDistinct); - } - - /** - * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression - */ - public function SimpleSelectClause(): AST\SimpleSelectClause - { - $isDistinct = false; - $this->match(TokenType::T_SELECT); - - if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { - $this->match(TokenType::T_DISTINCT); - - $isDistinct = true; - } - - return new AST\SimpleSelectClause($this->SimpleSelectExpression(), $isDistinct); - } - - /** - * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}* - */ - public function UpdateClause(): AST\UpdateClause - { - $this->match(TokenType::T_UPDATE); - assert($this->lexer->lookahead !== null); - - $token = $this->lexer->lookahead; - $abstractSchemaName = $this->AbstractSchemaName(); - - $this->validateAbstractSchemaName($abstractSchemaName); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - $aliasIdentificationVariable = $this->AliasIdentificationVariable(); - - $class = $this->em->getClassMetadata($abstractSchemaName); - - // Building queryComponent - $queryComponent = [ - 'metadata' => $class, - 'parent' => null, - 'relation' => null, - 'map' => null, - 'nestingLevel' => $this->nestingLevel, - 'token' => $token, - ]; - - $this->queryComponents[$aliasIdentificationVariable] = $queryComponent; - - $this->match(TokenType::T_SET); - - $updateItems = []; - $updateItems[] = $this->UpdateItem(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $updateItems[] = $this->UpdateItem(); - } - - $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems); - $updateClause->aliasIdentificationVariable = $aliasIdentificationVariable; - - return $updateClause; - } - - /** - * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable - */ - public function DeleteClause(): AST\DeleteClause - { - $this->match(TokenType::T_DELETE); - - if ($this->lexer->isNextToken(TokenType::T_FROM)) { - $this->match(TokenType::T_FROM); - } - - assert($this->lexer->lookahead !== null); - $token = $this->lexer->lookahead; - $abstractSchemaName = $this->AbstractSchemaName(); - - $this->validateAbstractSchemaName($abstractSchemaName); - - $deleteClause = new AST\DeleteClause($abstractSchemaName); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - $aliasIdentificationVariable = $this->lexer->isNextToken(TokenType::T_IDENTIFIER) - ? $this->AliasIdentificationVariable() - : 'alias_should_have_been_set'; - - $deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable; - $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName); - - // Building queryComponent - $queryComponent = [ - 'metadata' => $class, - 'parent' => null, - 'relation' => null, - 'map' => null, - 'nestingLevel' => $this->nestingLevel, - 'token' => $token, - ]; - - $this->queryComponents[$aliasIdentificationVariable] = $queryComponent; - - return $deleteClause; - } - - /** - * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* - */ - public function FromClause(): AST\FromClause - { - $this->match(TokenType::T_FROM); - - $identificationVariableDeclarations = []; - $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); - } - - return new AST\FromClause($identificationVariableDeclarations); - } - - /** - * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* - */ - public function SubselectFromClause(): AST\SubselectFromClause - { - $this->match(TokenType::T_FROM); - - $identificationVariables = []; - $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); - } - - return new AST\SubselectFromClause($identificationVariables); - } - - /** - * WhereClause ::= "WHERE" ConditionalExpression - */ - public function WhereClause(): AST\WhereClause - { - $this->match(TokenType::T_WHERE); - - return new AST\WhereClause($this->ConditionalExpression()); - } - - /** - * HavingClause ::= "HAVING" ConditionalExpression - */ - public function HavingClause(): AST\HavingClause - { - $this->match(TokenType::T_HAVING); - - return new AST\HavingClause($this->ConditionalExpression()); - } - - /** - * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* - */ - public function GroupByClause(): AST\GroupByClause - { - $this->match(TokenType::T_GROUP); - $this->match(TokenType::T_BY); - - $groupByItems = [$this->GroupByItem()]; - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $groupByItems[] = $this->GroupByItem(); - } - - return new AST\GroupByClause($groupByItems); - } - - /** - * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* - */ - public function OrderByClause(): AST\OrderByClause - { - $this->match(TokenType::T_ORDER); - $this->match(TokenType::T_BY); - - $orderByItems = []; - $orderByItems[] = $this->OrderByItem(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $orderByItems[] = $this->OrderByItem(); - } - - return new AST\OrderByClause($orderByItems); - } - - /** - * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - */ - public function Subselect(): AST\Subselect - { - // Increase query nesting level - $this->nestingLevel++; - - $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause()); - - $subselect->whereClause = $this->lexer->isNextToken(TokenType::T_WHERE) ? $this->WhereClause() : null; - $subselect->groupByClause = $this->lexer->isNextToken(TokenType::T_GROUP) ? $this->GroupByClause() : null; - $subselect->havingClause = $this->lexer->isNextToken(TokenType::T_HAVING) ? $this->HavingClause() : null; - $subselect->orderByClause = $this->lexer->isNextToken(TokenType::T_ORDER) ? $this->OrderByClause() : null; - - // Decrease query nesting level - $this->nestingLevel--; - - return $subselect; - } - - /** - * UpdateItem ::= SingleValuedPathExpression "=" NewValue - */ - public function UpdateItem(): AST\UpdateItem - { - $pathExpr = $this->SingleValuedPathExpression(); - - $this->match(TokenType::T_EQUALS); - - return new AST\UpdateItem($pathExpr, $this->NewValue()); - } - - /** - * GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression - */ - public function GroupByItem(): string|AST\PathExpression - { - // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression - $glimpse = $this->lexer->glimpse(); - - if ($glimpse !== null && $glimpse->type === TokenType::T_DOT) { - return $this->SingleValuedPathExpression(); - } - - assert($this->lexer->lookahead !== null); - // Still need to decide between IdentificationVariable or ResultVariable - $lookaheadValue = $this->lexer->lookahead->value; - - if (! isset($this->queryComponents[$lookaheadValue])) { - $this->semanticalError('Cannot group by undefined identification or result variable.'); - } - - return isset($this->queryComponents[$lookaheadValue]['metadata']) - ? $this->IdentificationVariable() - : $this->ResultVariable(); - } - - /** - * OrderByItem ::= ( - * SimpleArithmeticExpression | SingleValuedPathExpression | CaseExpression | - * ScalarExpression | ResultVariable | FunctionDeclaration - * ) ["ASC" | "DESC"] - */ - public function OrderByItem(): AST\OrderByItem - { - $this->lexer->peek(); // lookahead => '.' - $this->lexer->peek(); // lookahead => token after '.' - - $peek = $this->lexer->peek(); // lookahead => token after the token after the '.' - - $this->lexer->resetPeek(); - - $glimpse = $this->lexer->glimpse(); - - assert($this->lexer->lookahead !== null); - $expr = match (true) { - $this->isMathOperator($peek) => $this->SimpleArithmeticExpression(), - $glimpse !== null && $glimpse->type === TokenType::T_DOT => $this->SingleValuedPathExpression(), - $this->lexer->peek() && $this->isMathOperator($this->peekBeyondClosingParenthesis()) => $this->ScalarExpression(), - $this->lexer->lookahead->type === TokenType::T_CASE => $this->CaseExpression(), - $this->isFunction() => $this->FunctionDeclaration(), - default => $this->ResultVariable(), - }; - - $type = 'ASC'; - $item = new AST\OrderByItem($expr); - - switch (true) { - case $this->lexer->isNextToken(TokenType::T_DESC): - $this->match(TokenType::T_DESC); - $type = 'DESC'; - break; - - case $this->lexer->isNextToken(TokenType::T_ASC): - $this->match(TokenType::T_ASC); - break; - - default: - // Do nothing - } - - $item->type = $type; - - return $item; - } - - /** - * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | - * EnumPrimary | SimpleEntityExpression | "NULL" - * - * NOTE: Since it is not possible to correctly recognize individual types, here is the full - * grammar that needs to be supported: - * - * NewValue ::= SimpleArithmeticExpression | "NULL" - * - * SimpleArithmeticExpression covers all *Primary grammar rules and also SimpleEntityExpression - */ - public function NewValue(): AST\ArithmeticExpression|AST\InputParameter|null - { - if ($this->lexer->isNextToken(TokenType::T_NULL)) { - $this->match(TokenType::T_NULL); - - return null; - } - - if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { - $this->match(TokenType::T_INPUT_PARAMETER); - assert($this->lexer->token !== null); - - return new AST\InputParameter($this->lexer->token->value); - } - - return $this->ArithmeticExpression(); - } - - /** - * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}* - */ - public function IdentificationVariableDeclaration(): AST\IdentificationVariableDeclaration - { - $joins = []; - $rangeVariableDeclaration = $this->RangeVariableDeclaration(); - $indexBy = $this->lexer->isNextToken(TokenType::T_INDEX) - ? $this->IndexBy() - : null; - - $rangeVariableDeclaration->isRoot = true; - - while ( - $this->lexer->isNextToken(TokenType::T_LEFT) || - $this->lexer->isNextToken(TokenType::T_INNER) || - $this->lexer->isNextToken(TokenType::T_JOIN) - ) { - $joins[] = $this->Join(); - } - - return new AST\IdentificationVariableDeclaration( - $rangeVariableDeclaration, - $indexBy, - $joins, - ); - } - - /** - * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration - * - * {Internal note: WARNING: Solution is harder than a bare implementation. - * Desired EBNF support: - * - * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable) - * - * It demands that entire SQL generation to become programmatical. This is - * needed because association based subselect requires "WHERE" conditional - * expressions to be injected, but there is no scope to do that. Only scope - * accessible is "FROM", prohibiting an easy implementation without larger - * changes.} - */ - public function SubselectIdentificationVariableDeclaration(): AST\IdentificationVariableDeclaration - { - /* - NOT YET IMPLEMENTED! - - $glimpse = $this->lexer->glimpse(); - - if ($glimpse->type == TokenType::T_DOT) { - $associationPathExpression = $this->AssociationPathExpression(); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - $aliasIdentificationVariable = $this->AliasIdentificationVariable(); - $identificationVariable = $associationPathExpression->identificationVariable; - $field = $associationPathExpression->associationField; - - $class = $this->queryComponents[$identificationVariable]['metadata']; - $targetClass = $this->em->getClassMetadata($class->associationMappings[$field]['targetEntity']); - - // Building queryComponent - $joinQueryComponent = array( - 'metadata' => $targetClass, - 'parent' => $identificationVariable, - 'relation' => $class->getAssociationMapping($field), - 'map' => null, - 'nestingLevel' => $this->nestingLevel, - 'token' => $this->lexer->lookahead - ); - - $this->queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; - - return new AST\SubselectIdentificationVariableDeclaration( - $associationPathExpression, $aliasIdentificationVariable - ); - } - */ - - return $this->IdentificationVariableDeclaration(); - } - - /** - * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" - * (JoinAssociationDeclaration | RangeVariableDeclaration) - * ["WITH" ConditionalExpression] - */ - public function Join(): AST\Join - { - // Check Join type - $joinType = AST\Join::JOIN_TYPE_INNER; - - switch (true) { - case $this->lexer->isNextToken(TokenType::T_LEFT): - $this->match(TokenType::T_LEFT); - - $joinType = AST\Join::JOIN_TYPE_LEFT; - - // Possible LEFT OUTER join - if ($this->lexer->isNextToken(TokenType::T_OUTER)) { - $this->match(TokenType::T_OUTER); - - $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; - } - - break; - - case $this->lexer->isNextToken(TokenType::T_INNER): - $this->match(TokenType::T_INNER); - break; - - default: - // Do nothing - } - - $this->match(TokenType::T_JOIN); - - $next = $this->lexer->glimpse(); - assert($next !== null); - $joinDeclaration = $next->type === TokenType::T_DOT ? $this->JoinAssociationDeclaration() : $this->RangeVariableDeclaration(); - $adhocConditions = $this->lexer->isNextToken(TokenType::T_WITH); - $join = new AST\Join($joinType, $joinDeclaration); - - // Describe non-root join declaration - if ($joinDeclaration instanceof AST\RangeVariableDeclaration) { - $joinDeclaration->isRoot = false; - } - - // Check for ad-hoc Join conditions - if ($adhocConditions) { - $this->match(TokenType::T_WITH); - - $join->conditionalExpression = $this->ConditionalExpression(); - } - - return $join; - } - - /** - * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable - * - * @throws QueryException - */ - public function RangeVariableDeclaration(): AST\RangeVariableDeclaration - { - if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) && $this->lexer->glimpse()->type === TokenType::T_SELECT) { - $this->semanticalError('Subquery is not supported here', $this->lexer->token); - } - - $abstractSchemaName = $this->AbstractSchemaName(); - - $this->validateAbstractSchemaName($abstractSchemaName); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - assert($this->lexer->lookahead !== null); - $token = $this->lexer->lookahead; - $aliasIdentificationVariable = $this->AliasIdentificationVariable(); - $classMetadata = $this->em->getClassMetadata($abstractSchemaName); - - // Building queryComponent - $queryComponent = [ - 'metadata' => $classMetadata, - 'parent' => null, - 'relation' => null, - 'map' => null, - 'nestingLevel' => $this->nestingLevel, - 'token' => $token, - ]; - - $this->queryComponents[$aliasIdentificationVariable] = $queryComponent; - - return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable); - } - - /** - * JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy] - */ - public function JoinAssociationDeclaration(): AST\JoinAssociationDeclaration - { - $joinAssociationPathExpression = $this->JoinAssociationPathExpression(); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - assert($this->lexer->lookahead !== null); - - $aliasIdentificationVariable = $this->AliasIdentificationVariable(); - $indexBy = $this->lexer->isNextToken(TokenType::T_INDEX) ? $this->IndexBy() : null; - - $identificationVariable = $joinAssociationPathExpression->identificationVariable; - $field = $joinAssociationPathExpression->associationField; - - $class = $this->getMetadataForDqlAlias($identificationVariable); - $targetClass = $this->em->getClassMetadata($class->associationMappings[$field]->targetEntity); - - // Building queryComponent - $joinQueryComponent = [ - 'metadata' => $targetClass, - 'parent' => $joinAssociationPathExpression->identificationVariable, - 'relation' => $class->getAssociationMapping($field), - 'map' => null, - 'nestingLevel' => $this->nestingLevel, - 'token' => $this->lexer->lookahead, - ]; - - $this->queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; - - return new AST\JoinAssociationDeclaration($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy); - } - - /** - * NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")" - */ - public function NewObjectExpression(): AST\NewObjectExpression - { - $args = []; - $this->match(TokenType::T_NEW); - - $className = $this->AbstractSchemaName(); // note that this is not yet validated - $token = $this->lexer->token; - - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $args[] = $this->NewObjectArg(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $args[] = $this->NewObjectArg(); - } - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - $expression = new AST\NewObjectExpression($className, $args); - - // Defer NewObjectExpression validation - $this->deferredNewObjectExpressions[] = [ - 'token' => $token, - 'expression' => $expression, - 'nestingLevel' => $this->nestingLevel, - ]; - - return $expression; - } - - /** - * NewObjectArg ::= ScalarExpression | "(" Subselect ")" - */ - public function NewObjectArg(): mixed - { - assert($this->lexer->lookahead !== null); - $token = $this->lexer->lookahead; - $peek = $this->lexer->glimpse(); - - assert($peek !== null); - if ($token->type === TokenType::T_OPEN_PARENTHESIS && $peek->type === TokenType::T_SELECT) { - $this->match(TokenType::T_OPEN_PARENTHESIS); - $expression = $this->Subselect(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $expression; - } - - return $this->ScalarExpression(); - } - - /** - * IndexBy ::= "INDEX" "BY" SingleValuedPathExpression - */ - public function IndexBy(): AST\IndexBy - { - $this->match(TokenType::T_INDEX); - $this->match(TokenType::T_BY); - $pathExpr = $this->SingleValuedPathExpression(); - - // Add the INDEX BY info to the query component - $this->queryComponents[$pathExpr->identificationVariable]['map'] = $pathExpr->field; - - return new AST\IndexBy($pathExpr); - } - - /** - * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | - * StateFieldPathExpression | BooleanPrimary | CaseExpression | - * InstanceOfExpression - * - * @return mixed One of the possible expressions or subexpressions. - */ - public function ScalarExpression(): mixed - { - assert($this->lexer->token !== null); - assert($this->lexer->lookahead !== null); - $lookahead = $this->lexer->lookahead->type; - $peek = $this->lexer->glimpse(); - - switch (true) { - case $lookahead === TokenType::T_INTEGER: - case $lookahead === TokenType::T_FLOAT: - // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) or ( - 1 ) or ( + 1 ) - case $lookahead === TokenType::T_MINUS: - case $lookahead === TokenType::T_PLUS: - return $this->SimpleArithmeticExpression(); - - case $lookahead === TokenType::T_STRING: - return $this->StringPrimary(); - - case $lookahead === TokenType::T_TRUE: - case $lookahead === TokenType::T_FALSE: - $this->match($lookahead); - - return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token->value); - - case $lookahead === TokenType::T_INPUT_PARAMETER: - return match (true) { - $this->isMathOperator($peek) => $this->SimpleArithmeticExpression(), - default => $this->InputParameter(), - }; - - case $lookahead === TokenType::T_CASE: - case $lookahead === TokenType::T_COALESCE: - case $lookahead === TokenType::T_NULLIF: - // Since NULLIF and COALESCE can be identified as a function, - // we need to check these before checking for FunctionDeclaration - return $this->CaseExpression(); - - case $lookahead === TokenType::T_OPEN_PARENTHESIS: - return $this->SimpleArithmeticExpression(); - - // this check must be done before checking for a filed path expression - case $this->isFunction(): - $this->lexer->peek(); - - return match (true) { - $this->isMathOperator($this->peekBeyondClosingParenthesis()) => $this->SimpleArithmeticExpression(), - default => $this->FunctionDeclaration(), - }; - - // it is no function, so it must be a field path - case $lookahead === TokenType::T_IDENTIFIER: - $this->lexer->peek(); // lookahead => '.' - $this->lexer->peek(); // lookahead => token after '.' - $peek = $this->lexer->peek(); // lookahead => token after the token after the '.' - $this->lexer->resetPeek(); - - if ($this->isMathOperator($peek)) { - return $this->SimpleArithmeticExpression(); - } - - return $this->StateFieldPathExpression(); - - default: - $this->syntaxError(); - } - } - - /** - * CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpression - * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" - * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression - * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" - * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator - * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression - * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" - * NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" - * - * @return mixed One of the possible expressions or subexpressions. - */ - public function CaseExpression(): mixed - { - assert($this->lexer->lookahead !== null); - $lookahead = $this->lexer->lookahead->type; - - switch ($lookahead) { - case TokenType::T_NULLIF: - return $this->NullIfExpression(); - - case TokenType::T_COALESCE: - return $this->CoalesceExpression(); - - case TokenType::T_CASE: - $this->lexer->resetPeek(); - $peek = $this->lexer->peek(); - - assert($peek !== null); - if ($peek->type === TokenType::T_WHEN) { - return $this->GeneralCaseExpression(); - } - - return $this->SimpleCaseExpression(); - - default: - // Do nothing - break; - } - - $this->syntaxError(); - } - - /** - * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" - */ - public function CoalesceExpression(): AST\CoalesceExpression - { - $this->match(TokenType::T_COALESCE); - $this->match(TokenType::T_OPEN_PARENTHESIS); - - // Process ScalarExpressions (1..N) - $scalarExpressions = []; - $scalarExpressions[] = $this->ScalarExpression(); - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $scalarExpressions[] = $this->ScalarExpression(); - } - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\CoalesceExpression($scalarExpressions); - } - - /** - * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" - */ - public function NullIfExpression(): AST\NullIfExpression - { - $this->match(TokenType::T_NULLIF); - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $firstExpression = $this->ScalarExpression(); - $this->match(TokenType::T_COMMA); - $secondExpression = $this->ScalarExpression(); - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\NullIfExpression($firstExpression, $secondExpression); - } - - /** - * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" - */ - public function GeneralCaseExpression(): AST\GeneralCaseExpression - { - $this->match(TokenType::T_CASE); - - // Process WhenClause (1..N) - $whenClauses = []; - - do { - $whenClauses[] = $this->WhenClause(); - } while ($this->lexer->isNextToken(TokenType::T_WHEN)); - - $this->match(TokenType::T_ELSE); - $scalarExpression = $this->ScalarExpression(); - $this->match(TokenType::T_END); - - return new AST\GeneralCaseExpression($whenClauses, $scalarExpression); - } - - /** - * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" - * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator - */ - public function SimpleCaseExpression(): AST\SimpleCaseExpression - { - $this->match(TokenType::T_CASE); - $caseOperand = $this->StateFieldPathExpression(); - - // Process SimpleWhenClause (1..N) - $simpleWhenClauses = []; - - do { - $simpleWhenClauses[] = $this->SimpleWhenClause(); - } while ($this->lexer->isNextToken(TokenType::T_WHEN)); - - $this->match(TokenType::T_ELSE); - $scalarExpression = $this->ScalarExpression(); - $this->match(TokenType::T_END); - - return new AST\SimpleCaseExpression($caseOperand, $simpleWhenClauses, $scalarExpression); - } - - /** - * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression - */ - public function WhenClause(): AST\WhenClause - { - $this->match(TokenType::T_WHEN); - $conditionalExpression = $this->ConditionalExpression(); - $this->match(TokenType::T_THEN); - - return new AST\WhenClause($conditionalExpression, $this->ScalarExpression()); - } - - /** - * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression - */ - public function SimpleWhenClause(): AST\SimpleWhenClause - { - $this->match(TokenType::T_WHEN); - $conditionalExpression = $this->ScalarExpression(); - $this->match(TokenType::T_THEN); - - return new AST\SimpleWhenClause($conditionalExpression, $this->ScalarExpression()); - } - - /** - * SelectExpression ::= ( - * IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | - * "(" Subselect ")" | CaseExpression | NewObjectExpression - * ) [["AS"] ["HIDDEN"] AliasResultVariable] - */ - public function SelectExpression(): AST\SelectExpression - { - assert($this->lexer->lookahead !== null); - $expression = null; - $identVariable = null; - $peek = $this->lexer->glimpse(); - $lookaheadType = $this->lexer->lookahead->type; - assert($peek !== null); - - switch (true) { - // ScalarExpression (u.name) - case $lookaheadType === TokenType::T_IDENTIFIER && $peek->type === TokenType::T_DOT: - $expression = $this->ScalarExpression(); - break; - - // IdentificationVariable (u) - case $lookaheadType === TokenType::T_IDENTIFIER && $peek->type !== TokenType::T_OPEN_PARENTHESIS: - $expression = $identVariable = $this->IdentificationVariable(); - break; - - // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...)) - case $lookaheadType === TokenType::T_CASE: - case $lookaheadType === TokenType::T_COALESCE: - case $lookaheadType === TokenType::T_NULLIF: - $expression = $this->CaseExpression(); - break; - - // DQL Function (SUM(u.value) or SUM(u.value) + 1) - case $this->isFunction(): - $this->lexer->peek(); // "(" - - $expression = match (true) { - $this->isMathOperator($this->peekBeyondClosingParenthesis()) => $this->ScalarExpression(), - default => $this->FunctionDeclaration(), - }; - - break; - - // Subselect - case $lookaheadType === TokenType::T_OPEN_PARENTHESIS && $peek->type === TokenType::T_SELECT: - $this->match(TokenType::T_OPEN_PARENTHESIS); - $expression = $this->Subselect(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - break; - - // Shortcut: ScalarExpression => SimpleArithmeticExpression - case $lookaheadType === TokenType::T_OPEN_PARENTHESIS: - case $lookaheadType === TokenType::T_INTEGER: - case $lookaheadType === TokenType::T_STRING: - case $lookaheadType === TokenType::T_FLOAT: - // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) - case $lookaheadType === TokenType::T_MINUS: - case $lookaheadType === TokenType::T_PLUS: - $expression = $this->SimpleArithmeticExpression(); - break; - - // NewObjectExpression (New ClassName(id, name)) - case $lookaheadType === TokenType::T_NEW: - $expression = $this->NewObjectExpression(); - break; - - default: - $this->syntaxError( - 'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | "(" Subselect ")" | CaseExpression', - $this->lexer->lookahead, - ); - } - - // [["AS"] ["HIDDEN"] AliasResultVariable] - $mustHaveAliasResultVariable = false; - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - - $mustHaveAliasResultVariable = true; - } - - $hiddenAliasResultVariable = false; - - if ($this->lexer->isNextToken(TokenType::T_HIDDEN)) { - $this->match(TokenType::T_HIDDEN); - - $hiddenAliasResultVariable = true; - } - - $aliasResultVariable = null; - - if ($mustHaveAliasResultVariable || $this->lexer->isNextToken(TokenType::T_IDENTIFIER)) { - assert($expression instanceof AST\Node || is_string($expression)); - $token = $this->lexer->lookahead; - $aliasResultVariable = $this->AliasResultVariable(); - - // Include AliasResultVariable in query components. - $this->queryComponents[$aliasResultVariable] = [ - 'resultVariable' => $expression, - 'nestingLevel' => $this->nestingLevel, - 'token' => $token, - ]; - } - - // AST - - $expr = new AST\SelectExpression($expression, $aliasResultVariable, $hiddenAliasResultVariable); - - if ($identVariable) { - $this->identVariableExpressions[$identVariable] = $expr; - } - - return $expr; - } - - /** - * SimpleSelectExpression ::= ( - * StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | - * AggregateExpression | "(" Subselect ")" | ScalarExpression - * ) [["AS"] AliasResultVariable] - */ - public function SimpleSelectExpression(): AST\SimpleSelectExpression - { - assert($this->lexer->lookahead !== null); - $peek = $this->lexer->glimpse(); - assert($peek !== null); - - switch ($this->lexer->lookahead->type) { - case TokenType::T_IDENTIFIER: - switch (true) { - case $peek->type === TokenType::T_DOT: - $expression = $this->StateFieldPathExpression(); - - return new AST\SimpleSelectExpression($expression); - - case $peek->type !== TokenType::T_OPEN_PARENTHESIS: - $expression = $this->IdentificationVariable(); - - return new AST\SimpleSelectExpression($expression); - - case $this->isFunction(): - // SUM(u.id) + COUNT(u.id) - if ($this->isMathOperator($this->peekBeyondClosingParenthesis())) { - return new AST\SimpleSelectExpression($this->ScalarExpression()); - } - - // COUNT(u.id) - if ($this->isAggregateFunction($this->lexer->lookahead->type)) { - return new AST\SimpleSelectExpression($this->AggregateExpression()); - } - - // IDENTITY(u) - return new AST\SimpleSelectExpression($this->FunctionDeclaration()); - - default: - // Do nothing - } - - break; - - case TokenType::T_OPEN_PARENTHESIS: - if ($peek->type !== TokenType::T_SELECT) { - // Shortcut: ScalarExpression => SimpleArithmeticExpression - $expression = $this->SimpleArithmeticExpression(); - - return new AST\SimpleSelectExpression($expression); - } - - // Subselect - $this->match(TokenType::T_OPEN_PARENTHESIS); - $expression = $this->Subselect(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\SimpleSelectExpression($expression); - - default: - // Do nothing - } - - $this->lexer->peek(); - - $expression = $this->ScalarExpression(); - $expr = new AST\SimpleSelectExpression($expression); - - if ($this->lexer->isNextToken(TokenType::T_AS)) { - $this->match(TokenType::T_AS); - } - - if ($this->lexer->isNextToken(TokenType::T_IDENTIFIER)) { - $token = $this->lexer->lookahead; - $resultVariable = $this->AliasResultVariable(); - $expr->fieldIdentificationVariable = $resultVariable; - - // Include AliasResultVariable in query components. - $this->queryComponents[$resultVariable] = [ - 'resultvariable' => $expr, - 'nestingLevel' => $this->nestingLevel, - 'token' => $token, - ]; - } - - return $expr; - } - - /** - * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* - */ - public function ConditionalExpression(): AST\ConditionalExpression|AST\ConditionalFactor|AST\ConditionalPrimary|AST\ConditionalTerm - { - $conditionalTerms = []; - $conditionalTerms[] = $this->ConditionalTerm(); - - while ($this->lexer->isNextToken(TokenType::T_OR)) { - $this->match(TokenType::T_OR); - - $conditionalTerms[] = $this->ConditionalTerm(); - } - - // Phase 1 AST optimization: Prevent AST\ConditionalExpression - // if only one AST\ConditionalTerm is defined - if (count($conditionalTerms) === 1) { - return $conditionalTerms[0]; - } - - return new AST\ConditionalExpression($conditionalTerms); - } - - /** - * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* - */ - public function ConditionalTerm(): AST\ConditionalFactor|AST\ConditionalPrimary|AST\ConditionalTerm - { - $conditionalFactors = []; - $conditionalFactors[] = $this->ConditionalFactor(); - - while ($this->lexer->isNextToken(TokenType::T_AND)) { - $this->match(TokenType::T_AND); - - $conditionalFactors[] = $this->ConditionalFactor(); - } - - // Phase 1 AST optimization: Prevent AST\ConditionalTerm - // if only one AST\ConditionalFactor is defined - if (count($conditionalFactors) === 1) { - return $conditionalFactors[0]; - } - - return new AST\ConditionalTerm($conditionalFactors); - } - - /** - * ConditionalFactor ::= ["NOT"] ConditionalPrimary - */ - public function ConditionalFactor(): AST\ConditionalFactor|AST\ConditionalPrimary - { - $not = false; - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - - $not = true; - } - - $conditionalPrimary = $this->ConditionalPrimary(); - - // Phase 1 AST optimization: Prevent AST\ConditionalFactor - // if only one AST\ConditionalPrimary is defined - if (! $not) { - return $conditionalPrimary; - } - - return new AST\ConditionalFactor($conditionalPrimary, $not); - } - - /** - * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" - */ - public function ConditionalPrimary(): AST\ConditionalPrimary - { - $condPrimary = new AST\ConditionalPrimary(); - - if (! $this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { - $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); - - return $condPrimary; - } - - // Peek beyond the matching closing parenthesis ')' - $peek = $this->peekBeyondClosingParenthesis(); - - if ( - $peek !== null && ( - in_array($peek->value, ['=', '<', '<=', '<>', '>', '>=', '!='], true) || - in_array($peek->type, [TokenType::T_NOT, TokenType::T_BETWEEN, TokenType::T_LIKE, TokenType::T_IN, TokenType::T_IS, TokenType::T_EXISTS], true) || - $this->isMathOperator($peek) - ) - ) { - $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); - - return $condPrimary; - } - - $this->match(TokenType::T_OPEN_PARENTHESIS); - $condPrimary->conditionalExpression = $this->ConditionalExpression(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $condPrimary; - } - - /** - * SimpleConditionalExpression ::= - * ComparisonExpression | BetweenExpression | LikeExpression | - * InExpression | NullComparisonExpression | ExistsExpression | - * EmptyCollectionComparisonExpression | CollectionMemberExpression | - * InstanceOfExpression - */ - public function SimpleConditionalExpression(): AST\ExistsExpression|AST\BetweenExpression|AST\LikeExpression|AST\InListExpression|AST\InSubselectExpression|AST\InstanceOfExpression|AST\CollectionMemberExpression|AST\NullComparisonExpression|AST\EmptyCollectionComparisonExpression|AST\ComparisonExpression - { - assert($this->lexer->lookahead !== null); - if ($this->lexer->isNextToken(TokenType::T_EXISTS)) { - return $this->ExistsExpression(); - } - - $token = $this->lexer->lookahead; - $peek = $this->lexer->glimpse(); - $lookahead = $token; - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $token = $this->lexer->glimpse(); - } - - assert($token !== null); - assert($peek !== null); - if ($token->type === TokenType::T_IDENTIFIER || $token->type === TokenType::T_INPUT_PARAMETER || $this->isFunction()) { - // Peek beyond the matching closing parenthesis. - $beyond = $this->lexer->peek(); - - switch ($peek->value) { - case '(': - // Peeks beyond the matched closing parenthesis. - $token = $this->peekBeyondClosingParenthesis(false); - assert($token !== null); - - if ($token->type === TokenType::T_NOT) { - $token = $this->lexer->peek(); - assert($token !== null); - } - - if ($token->type === TokenType::T_IS) { - $lookahead = $this->lexer->peek(); - } - - break; - - default: - // Peek beyond the PathExpression or InputParameter. - $token = $beyond; - - while ($token->value === '.') { - $this->lexer->peek(); - - $token = $this->lexer->peek(); - assert($token !== null); - } - - // Also peek beyond a NOT if there is one. - assert($token !== null); - if ($token->type === TokenType::T_NOT) { - $token = $this->lexer->peek(); - assert($token !== null); - } - - // We need to go even further in case of IS (differentiate between NULL and EMPTY) - $lookahead = $this->lexer->peek(); - } - - assert($lookahead !== null); - // Also peek beyond a NOT if there is one. - if ($lookahead->type === TokenType::T_NOT) { - $lookahead = $this->lexer->peek(); - } - - $this->lexer->resetPeek(); - } - - if ($token->type === TokenType::T_BETWEEN) { - return $this->BetweenExpression(); - } - - if ($token->type === TokenType::T_LIKE) { - return $this->LikeExpression(); - } - - if ($token->type === TokenType::T_IN) { - return $this->InExpression(); - } - - if ($token->type === TokenType::T_INSTANCE) { - return $this->InstanceOfExpression(); - } - - if ($token->type === TokenType::T_MEMBER) { - return $this->CollectionMemberExpression(); - } - - assert($lookahead !== null); - if ($token->type === TokenType::T_IS && $lookahead->type === TokenType::T_NULL) { - return $this->NullComparisonExpression(); - } - - if ($token->type === TokenType::T_IS && $lookahead->type === TokenType::T_EMPTY) { - return $this->EmptyCollectionComparisonExpression(); - } - - return $this->ComparisonExpression(); - } - - /** - * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY" - */ - public function EmptyCollectionComparisonExpression(): AST\EmptyCollectionComparisonExpression - { - $pathExpression = $this->CollectionValuedPathExpression(); - $this->match(TokenType::T_IS); - - $not = false; - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_EMPTY); - - return new AST\EmptyCollectionComparisonExpression( - $pathExpression, - $not, - ); - } - - /** - * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression - * - * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression - * SimpleEntityExpression ::= IdentificationVariable | InputParameter - */ - public function CollectionMemberExpression(): AST\CollectionMemberExpression - { - $not = false; - $entityExpr = $this->EntityExpression(); - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - - $not = true; - } - - $this->match(TokenType::T_MEMBER); - - if ($this->lexer->isNextToken(TokenType::T_OF)) { - $this->match(TokenType::T_OF); - } - - return new AST\CollectionMemberExpression( - $entityExpr, - $this->CollectionValuedPathExpression(), - $not, - ); - } - - /** - * Literal ::= string | char | integer | float | boolean - */ - public function Literal(): AST\Literal - { - assert($this->lexer->lookahead !== null); - assert($this->lexer->token !== null); - switch ($this->lexer->lookahead->type) { - case TokenType::T_STRING: - $this->match(TokenType::T_STRING); - - return new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); - - case TokenType::T_INTEGER: - case TokenType::T_FLOAT: - $this->match( - $this->lexer->isNextToken(TokenType::T_INTEGER) ? TokenType::T_INTEGER : TokenType::T_FLOAT, - ); - - return new AST\Literal(AST\Literal::NUMERIC, $this->lexer->token->value); - - case TokenType::T_TRUE: - case TokenType::T_FALSE: - $this->match( - $this->lexer->isNextToken(TokenType::T_TRUE) ? TokenType::T_TRUE : TokenType::T_FALSE, - ); - - return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token->value); - - default: - $this->syntaxError('Literal'); - } - } - - /** - * InParameter ::= ArithmeticExpression | InputParameter - */ - public function InParameter(): AST\InputParameter|AST\ArithmeticExpression - { - assert($this->lexer->lookahead !== null); - if ($this->lexer->lookahead->type === TokenType::T_INPUT_PARAMETER) { - return $this->InputParameter(); - } - - return $this->ArithmeticExpression(); - } - - /** - * InputParameter ::= PositionalParameter | NamedParameter - */ - public function InputParameter(): AST\InputParameter - { - $this->match(TokenType::T_INPUT_PARAMETER); - assert($this->lexer->token !== null); - - return new AST\InputParameter($this->lexer->token->value); - } - - /** - * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" - */ - public function ArithmeticExpression(): AST\ArithmeticExpression - { - $expr = new AST\ArithmeticExpression(); - - if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { - $peek = $this->lexer->glimpse(); - assert($peek !== null); - - if ($peek->type === TokenType::T_SELECT) { - $this->match(TokenType::T_OPEN_PARENTHESIS); - $expr->subselect = $this->Subselect(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $expr; - } - } - - $expr->simpleArithmeticExpression = $this->SimpleArithmeticExpression(); - - return $expr; - } - - /** - * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* - */ - public function SimpleArithmeticExpression(): AST\Node|string - { - $terms = []; - $terms[] = $this->ArithmeticTerm(); - - while (($isPlus = $this->lexer->isNextToken(TokenType::T_PLUS)) || $this->lexer->isNextToken(TokenType::T_MINUS)) { - $this->match($isPlus ? TokenType::T_PLUS : TokenType::T_MINUS); - - assert($this->lexer->token !== null); - $terms[] = $this->lexer->token->value; - $terms[] = $this->ArithmeticTerm(); - } - - // Phase 1 AST optimization: Prevent AST\SimpleArithmeticExpression - // if only one AST\ArithmeticTerm is defined - if (count($terms) === 1) { - return $terms[0]; - } - - return new AST\SimpleArithmeticExpression($terms); - } - - /** - * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* - */ - public function ArithmeticTerm(): AST\Node|string - { - $factors = []; - $factors[] = $this->ArithmeticFactor(); - - while (($isMult = $this->lexer->isNextToken(TokenType::T_MULTIPLY)) || $this->lexer->isNextToken(TokenType::T_DIVIDE)) { - $this->match($isMult ? TokenType::T_MULTIPLY : TokenType::T_DIVIDE); - - assert($this->lexer->token !== null); - $factors[] = $this->lexer->token->value; - $factors[] = $this->ArithmeticFactor(); - } - - // Phase 1 AST optimization: Prevent AST\ArithmeticTerm - // if only one AST\ArithmeticFactor is defined - if (count($factors) === 1) { - return $factors[0]; - } - - return new AST\ArithmeticTerm($factors); - } - - /** - * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary - */ - public function ArithmeticFactor(): AST\Node|string|AST\ArithmeticFactor - { - $sign = null; - - $isPlus = $this->lexer->isNextToken(TokenType::T_PLUS); - if ($isPlus || $this->lexer->isNextToken(TokenType::T_MINUS)) { - $this->match($isPlus ? TokenType::T_PLUS : TokenType::T_MINUS); - $sign = $isPlus; - } - - $primary = $this->ArithmeticPrimary(); - - // Phase 1 AST optimization: Prevent AST\ArithmeticFactor - // if only one AST\ArithmeticPrimary is defined - if ($sign === null) { - return $primary; - } - - return new AST\ArithmeticFactor($primary, $sign); - } - - /** - * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | ParenthesisExpression - * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings - * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable - * | InputParameter | CaseExpression - */ - public function ArithmeticPrimary(): AST\Node|string - { - if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS)) { - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $expr = $this->SimpleArithmeticExpression(); - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\ParenthesisExpression($expr); - } - - if ($this->lexer->lookahead === null) { - $this->syntaxError('ArithmeticPrimary'); - } - - switch ($this->lexer->lookahead->type) { - case TokenType::T_COALESCE: - case TokenType::T_NULLIF: - case TokenType::T_CASE: - return $this->CaseExpression(); - - case TokenType::T_IDENTIFIER: - $peek = $this->lexer->glimpse(); - - if ($peek !== null && $peek->value === '(') { - return $this->FunctionDeclaration(); - } - - if ($peek !== null && $peek->value === '.') { - return $this->SingleValuedPathExpression(); - } - - if (isset($this->queryComponents[$this->lexer->lookahead->value]['resultVariable'])) { - return $this->ResultVariable(); - } - - return $this->StateFieldPathExpression(); - - case TokenType::T_INPUT_PARAMETER: - return $this->InputParameter(); - - default: - $peek = $this->lexer->glimpse(); - - if ($peek !== null && $peek->value === '(') { - return $this->FunctionDeclaration(); - } - - return $this->Literal(); - } - } - - /** - * StringExpression ::= StringPrimary | ResultVariable | "(" Subselect ")" - */ - public function StringExpression(): AST\Subselect|AST\Node|string - { - $peek = $this->lexer->glimpse(); - assert($peek !== null); - - // Subselect - if ($this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) && $peek->type === TokenType::T_SELECT) { - $this->match(TokenType::T_OPEN_PARENTHESIS); - $expr = $this->Subselect(); - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $expr; - } - - assert($this->lexer->lookahead !== null); - // ResultVariable (string) - if ( - $this->lexer->isNextToken(TokenType::T_IDENTIFIER) && - isset($this->queryComponents[$this->lexer->lookahead->value]['resultVariable']) - ) { - return $this->ResultVariable(); - } - - return $this->StringPrimary(); - } - - /** - * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression - */ - public function StringPrimary(): AST\Node - { - assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead->type; - - switch ($lookaheadType) { - case TokenType::T_IDENTIFIER: - $peek = $this->lexer->glimpse(); - assert($peek !== null); - - if ($peek->value === '.') { - return $this->StateFieldPathExpression(); - } - - if ($peek->value === '(') { - // do NOT directly go to FunctionsReturningString() because it doesn't check for custom functions. - return $this->FunctionDeclaration(); - } - - $this->syntaxError("'.' or '('"); - break; - - case TokenType::T_STRING: - $this->match(TokenType::T_STRING); - assert($this->lexer->token !== null); - - return new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); - - case TokenType::T_INPUT_PARAMETER: - return $this->InputParameter(); - - case TokenType::T_CASE: - case TokenType::T_COALESCE: - case TokenType::T_NULLIF: - return $this->CaseExpression(); - - default: - assert($lookaheadType !== null); - if ($this->isAggregateFunction($lookaheadType)) { - return $this->AggregateExpression(); - } - } - - $this->syntaxError( - 'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression', - ); - } - - /** - * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression - */ - public function EntityExpression(): AST\InputParameter|AST\PathExpression - { - $glimpse = $this->lexer->glimpse(); - assert($glimpse !== null); - - if ($this->lexer->isNextToken(TokenType::T_IDENTIFIER) && $glimpse->value === '.') { - return $this->SingleValuedAssociationPathExpression(); - } - - return $this->SimpleEntityExpression(); - } - - /** - * SimpleEntityExpression ::= IdentificationVariable | InputParameter - */ - public function SimpleEntityExpression(): AST\InputParameter|AST\PathExpression - { - if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { - return $this->InputParameter(); - } - - return $this->StateFieldPathExpression(); - } - - /** - * AggregateExpression ::= - * ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")" - */ - public function AggregateExpression(): AST\AggregateExpression - { - assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead->type; - $isDistinct = false; - - if (! in_array($lookaheadType, [TokenType::T_COUNT, TokenType::T_AVG, TokenType::T_MAX, TokenType::T_MIN, TokenType::T_SUM], true)) { - $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); - } - - $this->match($lookaheadType); - assert($this->lexer->token !== null); - $functionName = $this->lexer->token->value; - $this->match(TokenType::T_OPEN_PARENTHESIS); - - if ($this->lexer->isNextToken(TokenType::T_DISTINCT)) { - $this->match(TokenType::T_DISTINCT); - $isDistinct = true; - } - - $pathExp = $this->SimpleArithmeticExpression(); - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); - } - - /** - * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" - */ - public function QuantifiedExpression(): AST\QuantifiedExpression - { - assert($this->lexer->lookahead !== null); - $lookaheadType = $this->lexer->lookahead->type; - $value = $this->lexer->lookahead->value; - - if (! in_array($lookaheadType, [TokenType::T_ALL, TokenType::T_ANY, TokenType::T_SOME], true)) { - $this->syntaxError('ALL, ANY or SOME'); - } - - $this->match($lookaheadType); - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $qExpr = new AST\QuantifiedExpression($this->Subselect()); - $qExpr->type = $value; - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $qExpr; - } - - /** - * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression - */ - public function BetweenExpression(): AST\BetweenExpression - { - $not = false; - $arithExpr1 = $this->ArithmeticExpression(); - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_BETWEEN); - $arithExpr2 = $this->ArithmeticExpression(); - $this->match(TokenType::T_AND); - $arithExpr3 = $this->ArithmeticExpression(); - - return new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3, $not); - } - - /** - * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) - */ - public function ComparisonExpression(): AST\ComparisonExpression - { - $this->lexer->glimpse(); - - $leftExpr = $this->ArithmeticExpression(); - $operator = $this->ComparisonOperator(); - $rightExpr = $this->isNextAllAnySome() - ? $this->QuantifiedExpression() - : $this->ArithmeticExpression(); - - return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); - } - - /** - * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")" - */ - public function InExpression(): AST\InListExpression|AST\InSubselectExpression - { - $expression = $this->ArithmeticExpression(); - - $not = false; - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_IN); - $this->match(TokenType::T_OPEN_PARENTHESIS); - - if ($this->lexer->isNextToken(TokenType::T_SELECT)) { - $inExpression = new AST\InSubselectExpression( - $expression, - $this->Subselect(), - $not, - ); - } else { - $literals = [$this->InParameter()]; - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - $literals[] = $this->InParameter(); - } - - $inExpression = new AST\InListExpression( - $expression, - $literals, - $not, - ); - } - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $inExpression; - } - - /** - * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") - */ - public function InstanceOfExpression(): AST\InstanceOfExpression - { - $identificationVariable = $this->IdentificationVariable(); - - $not = false; - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_INSTANCE); - $this->match(TokenType::T_OF); - - $exprValues = $this->lexer->isNextToken(TokenType::T_OPEN_PARENTHESIS) - ? $this->InstanceOfParameterList() - : [$this->InstanceOfParameter()]; - - return new AST\InstanceOfExpression( - $identificationVariable, - $exprValues, - $not, - ); - } - - /** @return non-empty-list */ - public function InstanceOfParameterList(): array - { - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $exprValues = [$this->InstanceOfParameter()]; - - while ($this->lexer->isNextToken(TokenType::T_COMMA)) { - $this->match(TokenType::T_COMMA); - - $exprValues[] = $this->InstanceOfParameter(); - } - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return $exprValues; - } - - /** - * InstanceOfParameter ::= AbstractSchemaName | InputParameter - */ - public function InstanceOfParameter(): AST\InputParameter|string - { - if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { - $this->match(TokenType::T_INPUT_PARAMETER); - assert($this->lexer->token !== null); - - return new AST\InputParameter($this->lexer->token->value); - } - - $abstractSchemaName = $this->AbstractSchemaName(); - - $this->validateAbstractSchemaName($abstractSchemaName); - - return $abstractSchemaName; - } - - /** - * LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char] - */ - public function LikeExpression(): AST\LikeExpression - { - $stringExpr = $this->StringExpression(); - $not = false; - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_LIKE); - - if ($this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER)) { - $this->match(TokenType::T_INPUT_PARAMETER); - assert($this->lexer->token !== null); - $stringPattern = new AST\InputParameter($this->lexer->token->value); - } else { - $stringPattern = $this->StringPrimary(); - } - - $escapeChar = null; - - if ($this->lexer->lookahead !== null && $this->lexer->lookahead->type === TokenType::T_ESCAPE) { - $this->match(TokenType::T_ESCAPE); - $this->match(TokenType::T_STRING); - assert($this->lexer->token !== null); - - $escapeChar = new AST\Literal(AST\Literal::STRING, $this->lexer->token->value); - } - - return new AST\LikeExpression($stringExpr, $stringPattern, $escapeChar, $not); - } - - /** - * NullComparisonExpression ::= (InputParameter | NullIfExpression | CoalesceExpression | AggregateExpression | FunctionDeclaration | IdentificationVariable | SingleValuedPathExpression | ResultVariable) "IS" ["NOT"] "NULL" - */ - public function NullComparisonExpression(): AST\NullComparisonExpression - { - switch (true) { - case $this->lexer->isNextToken(TokenType::T_INPUT_PARAMETER): - $this->match(TokenType::T_INPUT_PARAMETER); - assert($this->lexer->token !== null); - - $expr = new AST\InputParameter($this->lexer->token->value); - break; - - case $this->lexer->isNextToken(TokenType::T_NULLIF): - $expr = $this->NullIfExpression(); - break; - - case $this->lexer->isNextToken(TokenType::T_COALESCE): - $expr = $this->CoalesceExpression(); - break; - - case $this->isFunction(): - $expr = $this->FunctionDeclaration(); - break; - - default: - // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression - $glimpse = $this->lexer->glimpse(); - assert($glimpse !== null); - - if ($glimpse->type === TokenType::T_DOT) { - $expr = $this->SingleValuedPathExpression(); - - // Leave switch statement - break; - } - - assert($this->lexer->lookahead !== null); - $lookaheadValue = $this->lexer->lookahead->value; - - // Validate existing component - if (! isset($this->queryComponents[$lookaheadValue])) { - $this->semanticalError('Cannot add having condition on undefined result variable.'); - } - - // Validate SingleValuedPathExpression (ie.: "product") - if (isset($this->queryComponents[$lookaheadValue]['metadata'])) { - $expr = $this->SingleValuedPathExpression(); - break; - } - - // Validating ResultVariable - if (! isset($this->queryComponents[$lookaheadValue]['resultVariable'])) { - $this->semanticalError('Cannot add having condition on a non result variable.'); - } - - $expr = $this->ResultVariable(); - break; - } - - $this->match(TokenType::T_IS); - - $not = false; - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - - $not = true; - } - - $this->match(TokenType::T_NULL); - - return new AST\NullComparisonExpression($expr, $not); - } - - /** - * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" - */ - public function ExistsExpression(): AST\ExistsExpression - { - $not = false; - - if ($this->lexer->isNextToken(TokenType::T_NOT)) { - $this->match(TokenType::T_NOT); - $not = true; - } - - $this->match(TokenType::T_EXISTS); - $this->match(TokenType::T_OPEN_PARENTHESIS); - - $subselect = $this->Subselect(); - - $this->match(TokenType::T_CLOSE_PARENTHESIS); - - return new AST\ExistsExpression($subselect, $not); - } - - /** - * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" - */ - public function ComparisonOperator(): string - { - assert($this->lexer->lookahead !== null); - switch ($this->lexer->lookahead->value) { - case '=': - $this->match(TokenType::T_EQUALS); - - return '='; - - case '<': - $this->match(TokenType::T_LOWER_THAN); - $operator = '<'; - - if ($this->lexer->isNextToken(TokenType::T_EQUALS)) { - $this->match(TokenType::T_EQUALS); - $operator .= '='; - } elseif ($this->lexer->isNextToken(TokenType::T_GREATER_THAN)) { - $this->match(TokenType::T_GREATER_THAN); - $operator .= '>'; - } - - return $operator; - - case '>': - $this->match(TokenType::T_GREATER_THAN); - $operator = '>'; - - if ($this->lexer->isNextToken(TokenType::T_EQUALS)) { - $this->match(TokenType::T_EQUALS); - $operator .= '='; - } - - return $operator; - - case '!': - $this->match(TokenType::T_NEGATE); - $this->match(TokenType::T_EQUALS); - - return '<>'; - - default: - $this->syntaxError('=, <, <=, <>, >, >=, !='); - } - } - - /** - * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime - */ - public function FunctionDeclaration(): Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - $token = $this->lexer->lookahead; - $funcName = strtolower($token->value); - - $customFunctionDeclaration = $this->CustomFunctionDeclaration(); - - // Check for custom functions functions first! - switch (true) { - case $customFunctionDeclaration !== null: - return $customFunctionDeclaration; - - case isset(self::$stringFunctions[$funcName]): - return $this->FunctionsReturningStrings(); - - case isset(self::$numericFunctions[$funcName]): - return $this->FunctionsReturningNumerics(); - - case isset(self::$datetimeFunctions[$funcName]): - return $this->FunctionsReturningDatetime(); - - default: - $this->syntaxError('known function', $token); - } - } - - /** - * Helper function for FunctionDeclaration grammar rule. - */ - private function CustomFunctionDeclaration(): Functions\FunctionNode|null - { - assert($this->lexer->lookahead !== null); - $token = $this->lexer->lookahead; - $funcName = strtolower($token->value); - - // Check for custom functions afterwards - $config = $this->em->getConfiguration(); - - return match (true) { - $config->getCustomStringFunction($funcName) !== null => $this->CustomFunctionsReturningStrings(), - $config->getCustomNumericFunction($funcName) !== null => $this->CustomFunctionsReturningNumerics(), - $config->getCustomDatetimeFunction($funcName) !== null => $this->CustomFunctionsReturningDatetime(), - default => null, - }; - } - - /** - * FunctionsReturningNumerics ::= - * "LENGTH" "(" StringPrimary ")" | - * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | - * "ABS" "(" SimpleArithmeticExpression ")" | - * "SQRT" "(" SimpleArithmeticExpression ")" | - * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | - * "SIZE" "(" CollectionValuedPathExpression ")" | - * "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" | - * "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" | - * "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")" - */ - public function FunctionsReturningNumerics(): AST\Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead->value); - $funcClass = self::$numericFunctions[$funcNameLower]; - - $function = new $funcClass($funcNameLower); - $function->parse($this); - - return $function; - } - - public function CustomFunctionsReturningNumerics(): AST\Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - // getCustomNumericFunction is case-insensitive - $functionName = strtolower($this->lexer->lookahead->value); - $functionClass = $this->em->getConfiguration()->getCustomNumericFunction($functionName); - - assert($functionClass !== null); - - $function = is_string($functionClass) - ? new $functionClass($functionName) - : $functionClass($functionName); - - $function->parse($this); - - return $function; - } - - /** - * FunctionsReturningDateTime ::= - * "CURRENT_DATE" | - * "CURRENT_TIME" | - * "CURRENT_TIMESTAMP" | - * "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" | - * "DATE_SUB" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" - */ - public function FunctionsReturningDatetime(): AST\Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead->value); - $funcClass = self::$datetimeFunctions[$funcNameLower]; - - $function = new $funcClass($funcNameLower); - $function->parse($this); - - return $function; - } - - public function CustomFunctionsReturningDatetime(): AST\Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - // getCustomDatetimeFunction is case-insensitive - $functionName = $this->lexer->lookahead->value; - $functionClass = $this->em->getConfiguration()->getCustomDatetimeFunction($functionName); - - assert($functionClass !== null); - - $function = is_string($functionClass) - ? new $functionClass($functionName) - : $functionClass($functionName); - - $function->parse($this); - - return $function; - } - - /** - * FunctionsReturningStrings ::= - * "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary}* ")" | - * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | - * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | - * "LOWER" "(" StringPrimary ")" | - * "UPPER" "(" StringPrimary ")" | - * "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")" - */ - public function FunctionsReturningStrings(): AST\Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - $funcNameLower = strtolower($this->lexer->lookahead->value); - $funcClass = self::$stringFunctions[$funcNameLower]; - - $function = new $funcClass($funcNameLower); - $function->parse($this); - - return $function; - } - - public function CustomFunctionsReturningStrings(): Functions\FunctionNode - { - assert($this->lexer->lookahead !== null); - // getCustomStringFunction is case-insensitive - $functionName = $this->lexer->lookahead->value; - $functionClass = $this->em->getConfiguration()->getCustomStringFunction($functionName); - - assert($functionClass !== null); - - $function = is_string($functionClass) - ? new $functionClass($functionName) - : $functionClass($functionName); - - $function->parse($this); - - return $function; - } - - private function getMetadataForDqlAlias(string $dqlAlias): ClassMetadata - { - if (! isset($this->queryComponents[$dqlAlias]['metadata'])) { - throw new LogicException(sprintf('No metadata for DQL alias: %s', $dqlAlias)); - } - - return $this->queryComponents[$dqlAlias]['metadata']; - } -} diff --git a/vendor/doctrine/orm/src/Query/ParserResult.php b/vendor/doctrine/orm/src/Query/ParserResult.php deleted file mode 100644 index 8b5ee1f..0000000 --- a/vendor/doctrine/orm/src/Query/ParserResult.php +++ /dev/null @@ -1,118 +0,0 @@ -> - */ - private array $parameterMappings = []; - - /** - * Initializes a new instance of the ParserResult class. - * The new instance is initialized with an empty ResultSetMapping. - */ - public function __construct() - { - $this->resultSetMapping = new ResultSetMapping(); - } - - /** - * Gets the ResultSetMapping for the parsed query. - * - * @return ResultSetMapping The result set mapping of the parsed query - */ - public function getResultSetMapping(): ResultSetMapping - { - return $this->resultSetMapping; - } - - /** - * Sets the ResultSetMapping of the parsed query. - */ - public function setResultSetMapping(ResultSetMapping $rsm): void - { - $this->resultSetMapping = $rsm; - } - - /** - * Sets the SQL executor that should be used for this ParserResult. - */ - public function setSqlExecutor(AbstractSqlExecutor $executor): void - { - $this->sqlExecutor = $executor; - } - - /** - * Gets the SQL executor used by this ParserResult. - */ - public function getSqlExecutor(): AbstractSqlExecutor - { - if ($this->sqlExecutor === null) { - throw new LogicException(sprintf( - 'Executor not set yet. Call %s::setSqlExecutor() first.', - self::class, - )); - } - - return $this->sqlExecutor; - } - - /** - * Adds a DQL to SQL parameter mapping. One DQL parameter name/position can map to - * several SQL parameter positions. - */ - public function addParameterMapping(string|int $dqlPosition, int $sqlPosition): void - { - $this->parameterMappings[$dqlPosition][] = $sqlPosition; - } - - /** - * Gets all DQL to SQL parameter mappings. - * - * @psalm-return array> The parameter mappings. - */ - public function getParameterMappings(): array - { - return $this->parameterMappings; - } - - /** - * Gets the SQL parameter positions for a DQL parameter name/position. - * - * @param string|int $dqlPosition The name or position of the DQL parameter. - * - * @return int[] The positions of the corresponding SQL parameters. - * @psalm-return list - */ - public function getSqlParameterPositions(string|int $dqlPosition): array - { - return $this->parameterMappings[$dqlPosition]; - } -} diff --git a/vendor/doctrine/orm/src/Query/Printer.php b/vendor/doctrine/orm/src/Query/Printer.php deleted file mode 100644 index db1f159..0000000 --- a/vendor/doctrine/orm/src/Query/Printer.php +++ /dev/null @@ -1,64 +0,0 @@ -println('(' . $name); - $this->indent++; - } - - /** - * Decreases indentation level by one and prints a closing parenthesis. - * - * This method is called after executing a production. - */ - public function endProduction(): void - { - $this->indent--; - $this->println(')'); - } - - /** - * Prints text indented with spaces depending on current indentation level. - * - * @param string $str The text. - */ - public function println(string $str): void - { - if (! $this->silent) { - echo str_repeat(' ', $this->indent), $str, "\n"; - } - } -} diff --git a/vendor/doctrine/orm/src/Query/QueryException.php b/vendor/doctrine/orm/src/Query/QueryException.php deleted file mode 100644 index ae945b1..0000000 --- a/vendor/doctrine/orm/src/Query/QueryException.php +++ /dev/null @@ -1,155 +0,0 @@ - or ? expected.'); - } - - public static function unknownParameter(string $key): self - { - return new self('Invalid parameter: token ' . $key . ' is not defined in the query.'); - } - - public static function parameterTypeMismatch(): self - { - return new self('DQL Query parameter and type numbers mismatch, but have to be exactly equal.'); - } - - public static function invalidPathExpression(PathExpression $pathExpr): self - { - return new self( - "Invalid PathExpression '" . $pathExpr->identificationVariable . '.' . $pathExpr->field . "'.", - ); - } - - public static function invalidLiteral(string|Stringable $literal): self - { - return new self("Invalid literal '" . $literal . "'"); - } - - public static function iterateWithFetchJoinCollectionNotAllowed(AssociationMapping $assoc): self - { - return new self( - 'Invalid query operation: Not allowed to iterate over fetch join collections ' . - 'in class ' . $assoc->sourceEntity . ' association ' . $assoc->fieldName, - ); - } - - /** - * @param string[] $assoc - * @psalm-param array $assoc - */ - public static function overwritingJoinConditionsNotYetSupported(array $assoc): self - { - return new self( - 'Unsupported query operation: It is not yet possible to overwrite the join ' . - 'conditions in class ' . $assoc['sourceEntityName'] . ' association ' . $assoc['fieldName'] . '. ' . - 'Use WITH to append additional join conditions to the association.', - ); - } - - public static function associationPathInverseSideNotSupported(PathExpression $pathExpr): self - { - return new self( - 'A single-valued association path expression to an inverse side is not supported in DQL queries. ' . - 'Instead of "' . $pathExpr->identificationVariable . '.' . $pathExpr->field . '" use an explicit join.', - ); - } - - public static function iterateWithFetchJoinNotAllowed(AssociationMapping $assoc): self - { - return new self( - 'Iterate with fetch join in class ' . $assoc->sourceEntity . - ' using association ' . $assoc->fieldName . ' not allowed.', - ); - } - - public static function eagerFetchJoinWithNotAllowed(string $sourceEntity, string $fieldName): self - { - return new self( - 'Associations with fetch-mode=EAGER may not be using WITH conditions in - "' . $sourceEntity . '#' . $fieldName . '".', - ); - } - - public static function iterateWithMixedResultNotAllowed(): self - { - return new self('Iterating a query with mixed results (using scalars) is not supported.'); - } - - public static function associationPathCompositeKeyNotSupported(): self - { - return new self( - 'A single-valued association path expression to an entity with a composite primary ' . - 'key is not supported. Explicitly name the components of the composite primary key ' . - 'in the query.', - ); - } - - public static function instanceOfUnrelatedClass(string $className, string $rootClass): self - { - return new self("Cannot check if a child of '" . $rootClass . "' is instanceof '" . $className . "', " . - 'inheritance hierarchy does not exists between these two classes.'); - } - - public static function invalidQueryComponent(string $dqlAlias): self - { - return new self( - "Invalid query component given for DQL alias '" . $dqlAlias . "', " . - "requires 'metadata', 'parent', 'relation', 'map', 'nestingLevel' and 'token' keys.", - ); - } -} diff --git a/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php b/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php deleted file mode 100644 index 3e0ec65..0000000 --- a/vendor/doctrine/orm/src/Query/QueryExpressionVisitor.php +++ /dev/null @@ -1,180 +0,0 @@ - Expr\Comparison::GT, - Comparison::GTE => Expr\Comparison::GTE, - Comparison::LT => Expr\Comparison::LT, - Comparison::LTE => Expr\Comparison::LTE, - ]; - - private readonly Expr $expr; - - /** @var list */ - private array $parameters = []; - - /** @param mixed[] $queryAliases */ - public function __construct( - private readonly array $queryAliases, - ) { - $this->expr = new Expr(); - } - - /** - * Gets bound parameters. - * Filled after {@link dispach()}. - * - * @return ArrayCollection - */ - public function getParameters(): ArrayCollection - { - return new ArrayCollection($this->parameters); - } - - public function clearParameters(): void - { - $this->parameters = []; - } - - /** - * Converts Criteria expression to Query one based on static map. - */ - private static function convertComparisonOperator(string $criteriaOperator): string|null - { - return self::OPERATOR_MAP[$criteriaOperator] ?? null; - } - - public function walkCompositeExpression(CompositeExpression $expr): mixed - { - $expressionList = []; - - foreach ($expr->getExpressionList() as $child) { - $expressionList[] = $this->dispatch($child); - } - - return match ($expr->getType()) { - CompositeExpression::TYPE_AND => new Expr\Andx($expressionList), - CompositeExpression::TYPE_OR => new Expr\Orx($expressionList), - CompositeExpression::TYPE_NOT => $this->expr->not($expressionList[0]), - default => throw new RuntimeException('Unknown composite ' . $expr->getType()), - }; - } - - public function walkComparison(Comparison $comparison): mixed - { - if (! isset($this->queryAliases[0])) { - throw new QueryException('No aliases are set before invoking walkComparison().'); - } - - $field = $this->queryAliases[0] . '.' . $comparison->getField(); - - foreach ($this->queryAliases as $alias) { - if (str_starts_with($comparison->getField() . '.', $alias . '.')) { - $field = $comparison->getField(); - break; - } - } - - $parameterName = str_replace('.', '_', $comparison->getField()); - - foreach ($this->parameters as $parameter) { - if ($parameter->getName() === $parameterName) { - $parameterName .= '_' . count($this->parameters); - break; - } - } - - $parameter = new Parameter($parameterName, $this->walkValue($comparison->getValue())); - $placeholder = ':' . $parameterName; - - switch ($comparison->getOperator()) { - case Comparison::IN: - $this->parameters[] = $parameter; - - return $this->expr->in($field, $placeholder); - - case Comparison::NIN: - $this->parameters[] = $parameter; - - return $this->expr->notIn($field, $placeholder); - - case Comparison::EQ: - case Comparison::IS: - if ($this->walkValue($comparison->getValue()) === null) { - return $this->expr->isNull($field); - } - - $this->parameters[] = $parameter; - - return $this->expr->eq($field, $placeholder); - - case Comparison::NEQ: - if ($this->walkValue($comparison->getValue()) === null) { - return $this->expr->isNotNull($field); - } - - $this->parameters[] = $parameter; - - return $this->expr->neq($field, $placeholder); - - case Comparison::CONTAINS: - $parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType()); - $this->parameters[] = $parameter; - - return $this->expr->like($field, $placeholder); - - case Comparison::MEMBER_OF: - return $this->expr->isMemberOf($comparison->getField(), $comparison->getValue()->getValue()); - - case Comparison::STARTS_WITH: - $parameter->setValue($parameter->getValue() . '%', $parameter->getType()); - $this->parameters[] = $parameter; - - return $this->expr->like($field, $placeholder); - - case Comparison::ENDS_WITH: - $parameter->setValue('%' . $parameter->getValue(), $parameter->getType()); - $this->parameters[] = $parameter; - - return $this->expr->like($field, $placeholder); - - default: - $operator = self::convertComparisonOperator($comparison->getOperator()); - if ($operator) { - $this->parameters[] = $parameter; - - return new Expr\Comparison( - $field, - $operator, - $placeholder, - ); - } - - throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator()); - } - } - - public function walkValue(Value $value): mixed - { - return $value->getValue(); - } -} diff --git a/vendor/doctrine/orm/src/Query/ResultSetMapping.php b/vendor/doctrine/orm/src/Query/ResultSetMapping.php deleted file mode 100644 index 612474d..0000000 --- a/vendor/doctrine/orm/src/Query/ResultSetMapping.php +++ /dev/null @@ -1,547 +0,0 @@ -Users should use the public methods. - * - * @todo Think about whether the number of lookup maps can be reduced. - */ -class ResultSetMapping -{ - /** - * Whether the result is mixed (contains scalar values together with field values). - * - * @ignore - */ - public bool $isMixed = false; - - /** - * Whether the result is a select statement. - * - * @ignore - */ - public bool $isSelect = true; - - /** - * Maps alias names to class names. - * - * @ignore - * @psalm-var array - */ - public array $aliasMap = []; - - /** - * Maps alias names to related association field names. - * - * @ignore - * @psalm-var array - */ - public array $relationMap = []; - - /** - * Maps alias names to parent alias names. - * - * @ignore - * @psalm-var array - */ - public array $parentAliasMap = []; - - /** - * Maps column names in the result set to field names for each class. - * - * @ignore - * @psalm-var array - */ - public array $fieldMappings = []; - - /** - * Maps column names in the result set to the alias/field name to use in the mapped result. - * - * @ignore - * @psalm-var array - */ - public array $scalarMappings = []; - - /** - * Maps scalar columns to enums - * - * @ignore - * @psalm-var array - */ - public $enumMappings = []; - - /** - * Maps column names in the result set to the alias/field type to use in the mapped result. - * - * @ignore - * @psalm-var array - */ - public array $typeMappings = []; - - /** - * Maps entities in the result set to the alias name to use in the mapped result. - * - * @ignore - * @psalm-var array - */ - public array $entityMappings = []; - - /** - * Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names. - * - * @ignore - * @psalm-var array - */ - public array $metaMappings = []; - - /** - * Maps column names in the result set to the alias they belong to. - * - * @ignore - * @psalm-var array - */ - public array $columnOwnerMap = []; - - /** - * List of columns in the result set that are used as discriminator columns. - * - * @ignore - * @psalm-var array - */ - public array $discriminatorColumns = []; - - /** - * Maps alias names to field names that should be used for indexing. - * - * @ignore - * @psalm-var array - */ - public array $indexByMap = []; - - /** - * Map from column names to class names that declare the field the column is mapped to. - * - * @ignore - * @psalm-var array - */ - public array $declaringClasses = []; - - /** - * This is necessary to hydrate derivate foreign keys correctly. - * - * @psalm-var array> - */ - public array $isIdentifierColumn = []; - - /** - * Maps column names in the result set to field names for each new object expression. - * - * @psalm-var array> - */ - public array $newObjectMappings = []; - - /** - * Maps metadata parameter names to the metadata attribute. - * - * @psalm-var array - */ - public array $metadataParameterMapping = []; - - /** - * Contains query parameter names to be resolved as discriminator values - * - * @psalm-var array - */ - public array $discriminatorParameters = []; - - /** - * Adds an entity result to this ResultSetMapping. - * - * @param string $class The class name of the entity. - * @param string $alias The alias for the class. The alias must be unique among all entity - * results or joined entity results within this ResultSetMapping. - * @param string|null $resultAlias The result alias with which the entity result should be - * placed in the result structure. - * @psalm-param class-string $class - * - * @return $this - * - * @todo Rename: addRootEntity - */ - public function addEntityResult(string $class, string $alias, string|null $resultAlias = null): static - { - $this->aliasMap[$alias] = $class; - $this->entityMappings[$alias] = $resultAlias; - - if ($resultAlias !== null) { - $this->isMixed = true; - } - - return $this; - } - - /** - * Sets a discriminator column for an entity result or joined entity result. - * The discriminator column will be used to determine the concrete class name to - * instantiate. - * - * @param string $alias The alias of the entity result or joined entity result the discriminator - * column should be used for. - * @param string $discrColumn The name of the discriminator column in the SQL result set. - * - * @return $this - * - * @todo Rename: addDiscriminatorColumn - */ - public function setDiscriminatorColumn(string $alias, string $discrColumn): static - { - $this->discriminatorColumns[$alias] = $discrColumn; - $this->columnOwnerMap[$discrColumn] = $alias; - - return $this; - } - - /** - * Sets a field to use for indexing an entity result or joined entity result. - * - * @param string $alias The alias of an entity result or joined entity result. - * @param string $fieldName The name of the field to use for indexing. - * - * @return $this - */ - public function addIndexBy(string $alias, string $fieldName): static - { - $found = false; - - foreach ([...$this->metaMappings, ...$this->fieldMappings] as $columnName => $columnFieldName) { - if (! ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] === $alias)) { - continue; - } - - $this->addIndexByColumn($alias, $columnName); - $found = true; - - break; - } - - /* TODO: check if this exception can be put back, for now it's gone because of assumptions made by some ORM internals - if ( ! $found) { - $message = sprintf( - 'Cannot add index by for DQL alias %s and field %s without calling addFieldResult() for them before.', - $alias, - $fieldName - ); - - throw new \LogicException($message); - } - */ - - return $this; - } - - /** - * Sets to index by a scalar result column name. - * - * @return $this - */ - public function addIndexByScalar(string $resultColumnName): static - { - $this->indexByMap['scalars'] = $resultColumnName; - - return $this; - } - - /** - * Sets a column to use for indexing an entity or joined entity result by the given alias name. - * - * @return $this - */ - public function addIndexByColumn(string $alias, string $resultColumnName): static - { - $this->indexByMap[$alias] = $resultColumnName; - - return $this; - } - - /** - * Checks whether an entity result or joined entity result with a given alias has - * a field set for indexing. - * - * @todo Rename: isIndexed($alias) - */ - public function hasIndexBy(string $alias): bool - { - return isset($this->indexByMap[$alias]); - } - - /** - * Checks whether the column with the given name is mapped as a field result - * as part of an entity result or joined entity result. - * - * @param string $columnName The name of the column in the SQL result set. - * - * @todo Rename: isField - */ - public function isFieldResult(string $columnName): bool - { - return isset($this->fieldMappings[$columnName]); - } - - /** - * Adds a field to the result that belongs to an entity or joined entity. - * - * @param string $alias The alias of the root entity or joined entity to which the field belongs. - * @param string $columnName The name of the column in the SQL result set. - * @param string $fieldName The name of the field on the declaring class. - * @param string|null $declaringClass The name of the class that declares/owns the specified field. - * When $alias refers to a superclass in a mapped hierarchy but - * the field $fieldName is defined on a subclass, specify that here. - * If not specified, the field is assumed to belong to the class - * designated by $alias. - * @psalm-param class-string|null $declaringClass - * - * @return $this - * - * @todo Rename: addField - */ - public function addFieldResult(string $alias, string $columnName, string $fieldName, string|null $declaringClass = null): static - { - // column name (in result set) => field name - $this->fieldMappings[$columnName] = $fieldName; - // column name => alias of owner - $this->columnOwnerMap[$columnName] = $alias; - // field name => class name of declaring class - $this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias]; - - if (! $this->isMixed && $this->scalarMappings) { - $this->isMixed = true; - } - - return $this; - } - - /** - * Adds a joined entity result. - * - * @param string $class The class name of the joined entity. - * @param string $alias The unique alias to use for the joined entity. - * @param string $parentAlias The alias of the entity result that is the parent of this joined result. - * @param string $relation The association field that connects the parent entity result - * with the joined entity result. - * @psalm-param class-string $class - * - * @return $this - * - * @todo Rename: addJoinedEntity - */ - public function addJoinedEntityResult(string $class, string $alias, string $parentAlias, string $relation): static - { - $this->aliasMap[$alias] = $class; - $this->parentAliasMap[$alias] = $parentAlias; - $this->relationMap[$alias] = $relation; - - return $this; - } - - /** - * Adds a scalar result mapping. - * - * @param string $columnName The name of the column in the SQL result set. - * @param string|int $alias The result alias with which the scalar result should be placed in the result structure. - * @param string $type The column type - * - * @return $this - * - * @todo Rename: addScalar - */ - public function addScalarResult(string $columnName, string|int $alias, string $type = 'string'): static - { - $this->scalarMappings[$columnName] = $alias; - $this->typeMappings[$columnName] = $type; - - if (! $this->isMixed && $this->fieldMappings) { - $this->isMixed = true; - } - - return $this; - } - - /** - * Adds a scalar result mapping. - * - * @param string $columnName The name of the column in the SQL result set. - * @param string $enumType The enum type - * - * @return $this - */ - public function addEnumResult(string $columnName, string $enumType): static - { - $this->enumMappings[$columnName] = $enumType; - - return $this; - } - - /** - * Adds a metadata parameter mappings. - */ - public function addMetadataParameterMapping(string|int $parameter, string $attribute): void - { - $this->metadataParameterMapping[$parameter] = $attribute; - } - - /** - * Checks whether a column with a given name is mapped as a scalar result. - * - * @todo Rename: isScalar - */ - public function isScalarResult(string $columnName): bool - { - return isset($this->scalarMappings[$columnName]); - } - - /** - * Gets the name of the class of an entity result or joined entity result, - * identified by the given unique alias. - * - * @psalm-return class-string - */ - public function getClassName(string $alias): string - { - return $this->aliasMap[$alias]; - } - - /** - * Gets the field alias for a column that is mapped as a scalar value. - * - * @param string $columnName The name of the column in the SQL result set. - */ - public function getScalarAlias(string $columnName): string|int - { - return $this->scalarMappings[$columnName]; - } - - /** - * Gets the name of the class that owns a field mapping for the specified column. - * - * @psalm-return class-string - */ - public function getDeclaringClass(string $columnName): string - { - return $this->declaringClasses[$columnName]; - } - - public function getRelation(string $alias): string - { - return $this->relationMap[$alias]; - } - - public function isRelation(string $alias): bool - { - return isset($this->relationMap[$alias]); - } - - /** - * Gets the alias of the class that owns a field mapping for the specified column. - */ - public function getEntityAlias(string $columnName): string - { - return $this->columnOwnerMap[$columnName]; - } - - /** - * Gets the parent alias of the given alias. - */ - public function getParentAlias(string $alias): string - { - return $this->parentAliasMap[$alias]; - } - - /** - * Checks whether the given alias has a parent alias. - */ - public function hasParentAlias(string $alias): bool - { - return isset($this->parentAliasMap[$alias]); - } - - /** - * Gets the field name for a column name. - */ - public function getFieldName(string $columnName): string - { - return $this->fieldMappings[$columnName]; - } - - /** @psalm-return array */ - public function getAliasMap(): array - { - return $this->aliasMap; - } - - /** - * Gets the number of different entities that appear in the mapped result. - * - * @psalm-return 0|positive-int - */ - public function getEntityResultCount(): int - { - return count($this->aliasMap); - } - - /** - * Checks whether this ResultSetMapping defines a mixed result. - * - * Mixed results can only occur in object and array (graph) hydration. In such a - * case a mixed result means that scalar values are mixed with objects/array in - * the result. - */ - public function isMixedResult(): bool - { - return $this->isMixed; - } - - /** - * Adds a meta column (foreign key or discriminator column) to the result set. - * - * @param string $alias The result alias with which the meta result should be placed in the result structure. - * @param string $columnName The name of the column in the SQL result set. - * @param string $fieldName The name of the field on the declaring class. - * @param string|null $type The column type - * - * @return $this - * - * @todo Make all methods of this class require all parameters and not infer anything - */ - public function addMetaResult( - string $alias, - string $columnName, - string $fieldName, - bool $isIdentifierColumn = false, - string|null $type = null, - ): static { - $this->metaMappings[$columnName] = $fieldName; - $this->columnOwnerMap[$columnName] = $alias; - - if ($isIdentifierColumn) { - $this->isIdentifierColumn[$alias][$columnName] = true; - } - - if ($type) { - $this->typeMappings[$columnName] = $type; - } - - return $this; - } -} diff --git a/vendor/doctrine/orm/src/Query/ResultSetMappingBuilder.php b/vendor/doctrine/orm/src/Query/ResultSetMappingBuilder.php deleted file mode 100644 index f28f3a9..0000000 --- a/vendor/doctrine/orm/src/Query/ResultSetMappingBuilder.php +++ /dev/null @@ -1,281 +0,0 @@ - queryColumnName). - * @psalm-param class-string $class - * @psalm-param array $renamedColumns - * @psalm-param self::COLUMN_RENAMING_*|null $renameMode - */ - public function addRootEntityFromClassMetadata( - string $class, - string $alias, - array $renamedColumns = [], - int|null $renameMode = null, - ): void { - $renameMode = $renameMode ?: $this->defaultRenameMode; - $columnAliasMap = $this->getColumnAliasMap($class, $renameMode, $renamedColumns); - - $this->addEntityResult($class, $alias); - $this->addAllClassFields($class, $alias, $columnAliasMap); - } - - /** - * Adds a joined entity and all of its fields to the result set. - * - * @param string $class The class name of the joined entity. - * @param string $alias The unique alias to use for the joined entity. - * @param string $parentAlias The alias of the entity result that is the parent of this joined result. - * @param string $relation The association field that connects the parent entity result - * with the joined entity result. - * @param string[] $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName). - * @psalm-param class-string $class - * @psalm-param array $renamedColumns - * @psalm-param self::COLUMN_RENAMING_*|null $renameMode - */ - public function addJoinedEntityFromClassMetadata( - string $class, - string $alias, - string $parentAlias, - string $relation, - array $renamedColumns = [], - int|null $renameMode = null, - ): void { - $renameMode = $renameMode ?: $this->defaultRenameMode; - $columnAliasMap = $this->getColumnAliasMap($class, $renameMode, $renamedColumns); - - $this->addJoinedEntityResult($class, $alias, $parentAlias, $relation); - $this->addAllClassFields($class, $alias, $columnAliasMap); - } - - /** - * Adds all fields of the given class to the result set mapping (columns and meta fields). - * - * @param string[] $columnAliasMap - * @psalm-param array $columnAliasMap - * - * @throws InvalidArgumentException - */ - protected function addAllClassFields(string $class, string $alias, array $columnAliasMap = []): void - { - $classMetadata = $this->em->getClassMetadata($class); - $platform = $this->em->getConnection()->getDatabasePlatform(); - - if (! $this->isInheritanceSupported($classMetadata)) { - throw new InvalidArgumentException('ResultSetMapping builder does not currently support your inheritance scheme.'); - } - - foreach ($classMetadata->getColumnNames() as $columnName) { - $propertyName = $classMetadata->getFieldName($columnName); - $columnAlias = $this->getSQLResultCasing($platform, $columnAliasMap[$columnName]); - - if (isset($this->fieldMappings[$columnAlias])) { - throw new InvalidArgumentException(sprintf( - "The column '%s' conflicts with another column in the mapper.", - $columnName, - )); - } - - $this->addFieldResult($alias, $columnAlias, $propertyName); - - $enumType = $classMetadata->getFieldMapping($propertyName)->enumType ?? null; - if (! empty($enumType)) { - $this->addEnumResult($columnAlias, $enumType); - } - } - - foreach ($classMetadata->associationMappings as $associationMapping) { - if ($associationMapping->isToOneOwningSide()) { - $targetClass = $this->em->getClassMetadata($associationMapping->targetEntity); - $isIdentifier = isset($associationMapping->id) && $associationMapping->id === true; - - foreach ($associationMapping->joinColumns as $joinColumn) { - $columnName = $joinColumn->name; - $columnAlias = $this->getSQLResultCasing($platform, $columnAliasMap[$columnName]); - $columnType = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - - if (isset($this->metaMappings[$columnAlias])) { - throw new InvalidArgumentException(sprintf( - "The column '%s' conflicts with another column in the mapper.", - $columnAlias, - )); - } - - $this->addMetaResult($alias, $columnAlias, $columnName, $isIdentifier, $columnType); - } - } - } - } - - private function isInheritanceSupported(ClassMetadata $classMetadata): bool - { - if ( - $classMetadata->isInheritanceTypeSingleTable() - && in_array($classMetadata->name, $classMetadata->discriminatorMap, true) - ) { - return true; - } - - return ! ($classMetadata->isInheritanceTypeSingleTable() || $classMetadata->isInheritanceTypeJoined()); - } - - /** - * Gets column alias for a given column. - * - * @psalm-param array $customRenameColumns - * - * @psalm-assert self::COLUMN_RENAMING_* $mode - */ - private function getColumnAlias(string $columnName, int $mode, array $customRenameColumns): string - { - return match ($mode) { - self::COLUMN_RENAMING_INCREMENT => $columnName . $this->sqlCounter++, - self::COLUMN_RENAMING_CUSTOM => $customRenameColumns[$columnName] ?? $columnName, - self::COLUMN_RENAMING_NONE => $columnName, - default => throw new InvalidArgumentException(sprintf('%d is not a valid value for $mode', $mode)), - }; - } - - /** - * Retrieves a class columns and join columns aliases that are used in the SELECT clause. - * - * This depends on the renaming mode selected by the user. - * - * @psalm-param class-string $className - * @psalm-param self::COLUMN_RENAMING_* $mode - * @psalm-param array $customRenameColumns - * - * @return string[] - * @psalm-return array - */ - private function getColumnAliasMap( - string $className, - int $mode, - array $customRenameColumns, - ): array { - if ($customRenameColumns) { // for BC with 2.2-2.3 API - $mode = self::COLUMN_RENAMING_CUSTOM; - } - - $columnAlias = []; - $class = $this->em->getClassMetadata($className); - - foreach ($class->getColumnNames() as $columnName) { - $columnAlias[$columnName] = $this->getColumnAlias($columnName, $mode, $customRenameColumns); - } - - foreach ($class->associationMappings as $associationMapping) { - if ($associationMapping->isToOneOwningSide()) { - foreach ($associationMapping->joinColumns as $joinColumn) { - $columnName = $joinColumn->name; - $columnAlias[$columnName] = $this->getColumnAlias($columnName, $mode, $customRenameColumns); - } - } - } - - return $columnAlias; - } - - /** - * Generates the Select clause from this ResultSetMappingBuilder. - * - * Works only for all the entity results. The select parts for scalar - * expressions have to be written manually. - * - * @param string[] $tableAliases - * @psalm-param array $tableAliases - */ - public function generateSelectClause(array $tableAliases = []): string - { - $sql = ''; - - foreach ($this->columnOwnerMap as $columnName => $dqlAlias) { - $tableAlias = $tableAliases[$dqlAlias] ?? $dqlAlias; - - if ($sql !== '') { - $sql .= ', '; - } - - if (isset($this->fieldMappings[$columnName])) { - $class = $this->em->getClassMetadata($this->declaringClasses[$columnName]); - $fieldName = $this->fieldMappings[$columnName]; - $classFieldMapping = $class->fieldMappings[$fieldName]; - $columnSql = $tableAlias . '.' . $classFieldMapping->columnName; - - $type = Type::getType($classFieldMapping->type); - $columnSql = $type->convertToPHPValueSQL($columnSql, $this->em->getConnection()->getDatabasePlatform()); - - $sql .= $columnSql; - } elseif (isset($this->metaMappings[$columnName])) { - $sql .= $tableAlias . '.' . $this->metaMappings[$columnName]; - } elseif (isset($this->discriminatorColumns[$dqlAlias])) { - $sql .= $tableAlias . '.' . $this->discriminatorColumns[$dqlAlias]; - } - - $sql .= ' AS ' . $columnName; - } - - return $sql; - } - - public function __toString(): string - { - return $this->generateSelectClause([]); - } -} diff --git a/vendor/doctrine/orm/src/Query/SqlWalker.php b/vendor/doctrine/orm/src/Query/SqlWalker.php deleted file mode 100644 index c6f98c1..0000000 --- a/vendor/doctrine/orm/src/Query/SqlWalker.php +++ /dev/null @@ -1,2264 +0,0 @@ -> - */ - private array $scalarResultAliasMap = []; - - /** - * Map from Table-Alias + Column-Name to OrderBy-Direction. - * - * @var array - */ - private array $orderedColumnsMap = []; - - /** - * Map from DQL-Alias + Field-Name to SQL Column Alias. - * - * @var array> - */ - private array $scalarFields = []; - - /** - * A list of classes that appear in non-scalar SelectExpressions. - * - * @psalm-var array - */ - private array $selectedClasses = []; - - /** - * The DQL alias of the root class of the currently traversed query. - * - * @psalm-var list - */ - private array $rootAliases = []; - - /** - * Flag that indicates whether to generate SQL table aliases in the SQL. - * These should only be generated for SELECT queries, not for UPDATE/DELETE. - */ - private bool $useSqlTableAliases = true; - - /** - * The database platform abstraction. - */ - private readonly AbstractPlatform $platform; - - /** - * The quote strategy. - */ - private readonly QuoteStrategy $quoteStrategy; - - /** @psalm-param array $queryComponents The query components (symbol table). */ - public function __construct( - private readonly Query $query, - private readonly ParserResult $parserResult, - private array $queryComponents, - ) { - $this->rsm = $parserResult->getResultSetMapping(); - $this->em = $query->getEntityManager(); - $this->conn = $this->em->getConnection(); - $this->platform = $this->conn->getDatabasePlatform(); - $this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy(); - } - - /** - * Gets the Query instance used by the walker. - */ - public function getQuery(): Query - { - return $this->query; - } - - /** - * Gets the Connection used by the walker. - */ - public function getConnection(): Connection - { - return $this->conn; - } - - /** - * Gets the EntityManager used by the walker. - */ - public function getEntityManager(): EntityManagerInterface - { - return $this->em; - } - - /** - * Gets the information about a single query component. - * - * @param string $dqlAlias The DQL alias. - * - * @return mixed[] - * @psalm-return QueryComponent - */ - public function getQueryComponent(string $dqlAlias): array - { - return $this->queryComponents[$dqlAlias]; - } - - public function getMetadataForDqlAlias(string $dqlAlias): ClassMetadata - { - return $this->queryComponents[$dqlAlias]['metadata'] - ?? throw new LogicException(sprintf('No metadata for DQL alias: %s', $dqlAlias)); - } - - /** - * Returns internal queryComponents array. - * - * @return array - */ - public function getQueryComponents(): array - { - return $this->queryComponents; - } - - /** - * Sets or overrides a query component for a given dql alias. - * - * @psalm-param QueryComponent $queryComponent - */ - public function setQueryComponent(string $dqlAlias, array $queryComponent): void - { - $requiredKeys = ['metadata', 'parent', 'relation', 'map', 'nestingLevel', 'token']; - - if (array_diff($requiredKeys, array_keys($queryComponent))) { - throw QueryException::invalidQueryComponent($dqlAlias); - } - - $this->queryComponents[$dqlAlias] = $queryComponent; - } - - /** - * Gets an executor that can be used to execute the result of this walker. - */ - public function getExecutor(AST\SelectStatement|AST\UpdateStatement|AST\DeleteStatement $statement): Exec\AbstractSqlExecutor - { - return match (true) { - $statement instanceof AST\SelectStatement - => new Exec\SingleSelectExecutor($statement, $this), - $statement instanceof AST\UpdateStatement - => $this->em->getClassMetadata($statement->updateClause->abstractSchemaName)->isInheritanceTypeJoined() - ? new Exec\MultiTableUpdateExecutor($statement, $this) - : new Exec\SingleTableDeleteUpdateExecutor($statement, $this), - $statement instanceof AST\DeleteStatement - => $this->em->getClassMetadata($statement->deleteClause->abstractSchemaName)->isInheritanceTypeJoined() - ? new Exec\MultiTableDeleteExecutor($statement, $this) - : new Exec\SingleTableDeleteUpdateExecutor($statement, $this), - }; - } - - /** - * Generates a unique, short SQL table alias. - */ - public function getSQLTableAlias(string $tableName, string $dqlAlias = ''): string - { - $tableName .= $dqlAlias ? '@[' . $dqlAlias . ']' : ''; - - if (! isset($this->tableAliasMap[$tableName])) { - $this->tableAliasMap[$tableName] = (preg_match('/[a-z]/i', $tableName[0]) ? strtolower($tableName[0]) : 't') - . $this->tableAliasCounter++ . '_'; - } - - return $this->tableAliasMap[$tableName]; - } - - /** - * Forces the SqlWalker to use a specific alias for a table name, rather than - * generating an alias on its own. - */ - public function setSQLTableAlias(string $tableName, string $alias, string $dqlAlias = ''): string - { - $tableName .= $dqlAlias ? '@[' . $dqlAlias . ']' : ''; - - $this->tableAliasMap[$tableName] = $alias; - - return $alias; - } - - /** - * Gets an SQL column alias for a column name. - */ - public function getSQLColumnAlias(string $columnName): string - { - return $this->quoteStrategy->getColumnAlias($columnName, $this->aliasCounter++, $this->platform); - } - - /** - * Generates the SQL JOINs that are necessary for Class Table Inheritance - * for the given class. - */ - private function generateClassTableInheritanceJoins( - ClassMetadata $class, - string $dqlAlias, - ): string { - $sql = ''; - - $baseTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - - // INNER JOIN parent class tables - foreach ($class->parentClasses as $parentClassName) { - $parentClass = $this->em->getClassMetadata($parentClassName); - $tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias); - - // If this is a joined association we must use left joins to preserve the correct result. - $sql .= isset($this->queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER '; - $sql .= 'JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON '; - - $sqlParts = []; - - foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { - $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; - } - - // Add filters on the root class - $sqlParts[] = $this->generateFilterConditionSQL($parentClass, $tableAlias); - - $sql .= implode(' AND ', array_filter($sqlParts)); - } - - // LEFT JOIN child class tables - foreach ($class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - $tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); - - $sql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON '; - - $sqlParts = []; - - foreach ($this->quoteStrategy->getIdentifierColumnNames($subClass, $this->platform) as $columnName) { - $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; - } - - $sql .= implode(' AND ', $sqlParts); - } - - return $sql; - } - - private function generateOrderedCollectionOrderByItems(): string - { - $orderedColumns = []; - - foreach ($this->selectedClasses as $selectedClass) { - $dqlAlias = $selectedClass['dqlAlias']; - $qComp = $this->queryComponents[$dqlAlias]; - - if (! isset($qComp['relation']->orderBy)) { - continue; - } - - assert(isset($qComp['metadata'])); - $persister = $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name); - - foreach ($qComp['relation']->orderBy as $fieldName => $orientation) { - $columnName = $this->quoteStrategy->getColumnName($fieldName, $qComp['metadata'], $this->platform); - $tableName = $qComp['metadata']->isInheritanceTypeJoined() - ? $persister->getOwningTable($fieldName) - : $qComp['metadata']->getTableName(); - - $orderedColumn = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName; - - // OrderByClause should replace an ordered relation. see - DDC-2475 - if (isset($this->orderedColumnsMap[$orderedColumn])) { - continue; - } - - $this->orderedColumnsMap[$orderedColumn] = $orientation; - $orderedColumns[] = $orderedColumn . ' ' . $orientation; - } - } - - return implode(', ', $orderedColumns); - } - - /** - * Generates a discriminator column SQL condition for the class with the given DQL alias. - * - * @psalm-param list $dqlAliases List of root DQL aliases to inspect for discriminator restrictions. - */ - private function generateDiscriminatorColumnConditionSQL(array $dqlAliases): string - { - $sqlParts = []; - - foreach ($dqlAliases as $dqlAlias) { - $class = $this->getMetadataForDqlAlias($dqlAlias); - - if (! $class->isInheritanceTypeSingleTable()) { - continue; - } - - $sqlTableAlias = $this->useSqlTableAliases - ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' - : ''; - - $conn = $this->em->getConnection(); - $values = []; - - if ($class->discriminatorValue !== null) { // discriminators can be 0 - $values[] = $class->getDiscriminatorColumn()->type === 'integer' && is_int($class->discriminatorValue) - ? $class->discriminatorValue - : $conn->quote((string) $class->discriminatorValue); - } - - foreach ($class->subClasses as $subclassName) { - $subclassMetadata = $this->em->getClassMetadata($subclassName); - - // Abstract entity classes show up in the list of subClasses, but may be omitted - // from the discriminator map. In that case, they have a null discriminator value. - if ($subclassMetadata->discriminatorValue === null) { - continue; - } - - $values[] = $subclassMetadata->getDiscriminatorColumn()->type === 'integer' && is_int($subclassMetadata->discriminatorValue) - ? $subclassMetadata->discriminatorValue - : $conn->quote((string) $subclassMetadata->discriminatorValue); - } - - if ($values !== []) { - $sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()->name . ' IN (' . implode(', ', $values) . ')'; - } else { - $sqlParts[] = '1=0'; // impossible condition - } - } - - $sql = implode(' AND ', $sqlParts); - - return count($sqlParts) > 1 ? '(' . $sql . ')' : $sql; - } - - /** - * Generates the filter SQL for a given entity and table alias. - */ - private function generateFilterConditionSQL( - ClassMetadata $targetEntity, - string $targetTableAlias, - ): string { - if (! $this->em->hasFilters()) { - return ''; - } - - switch ($targetEntity->inheritanceType) { - case ClassMetadata::INHERITANCE_TYPE_NONE: - break; - case ClassMetadata::INHERITANCE_TYPE_JOINED: - // The classes in the inheritance will be added to the query one by one, - // but only the root node is getting filtered - if ($targetEntity->name !== $targetEntity->rootEntityName) { - return ''; - } - - break; - case ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE: - // With STI the table will only be queried once, make sure that the filters - // are added to the root entity - $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName); - break; - default: - //@todo: throw exception? - return ''; - } - - $filterClauses = []; - foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { - $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias); - if ($filterExpr !== '') { - $filterClauses[] = '(' . $filterExpr . ')'; - } - } - - return implode(' AND ', $filterClauses); - } - - /** - * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. - */ - public function walkSelectStatement(AST\SelectStatement $selectStatement): string - { - $limit = $this->query->getMaxResults(); - $offset = $this->query->getFirstResult(); - $lockMode = $this->query->getHint(Query::HINT_LOCK_MODE) ?: LockMode::NONE; - $sql = $this->walkSelectClause($selectStatement->selectClause) - . $this->walkFromClause($selectStatement->fromClause) - . $this->walkWhereClause($selectStatement->whereClause); - - if ($selectStatement->groupByClause) { - $sql .= $this->walkGroupByClause($selectStatement->groupByClause); - } - - if ($selectStatement->havingClause) { - $sql .= $this->walkHavingClause($selectStatement->havingClause); - } - - if ($selectStatement->orderByClause) { - $sql .= $this->walkOrderByClause($selectStatement->orderByClause); - } - - $orderBySql = $this->generateOrderedCollectionOrderByItems(); - if (! $selectStatement->orderByClause && $orderBySql) { - $sql .= ' ORDER BY ' . $orderBySql; - } - - $sql = $this->platform->modifyLimitQuery($sql, $limit, $offset); - - if ($lockMode === LockMode::NONE) { - return $sql; - } - - if ($lockMode === LockMode::PESSIMISTIC_READ) { - return $sql . ' ' . $this->getReadLockSQL($this->platform); - } - - if ($lockMode === LockMode::PESSIMISTIC_WRITE) { - return $sql . ' ' . $this->getWriteLockSQL($this->platform); - } - - if ($lockMode !== LockMode::OPTIMISTIC) { - throw QueryException::invalidLockMode(); - } - - foreach ($this->selectedClasses as $selectedClass) { - if (! $selectedClass['class']->isVersioned) { - throw OptimisticLockException::lockFailed($selectedClass['class']->name); - } - } - - return $sql; - } - - /** - * Walks down a UpdateStatement AST node, thereby generating the appropriate SQL. - */ - public function walkUpdateStatement(AST\UpdateStatement $updateStatement): string - { - $this->useSqlTableAliases = false; - $this->rsm->isSelect = false; - - return $this->walkUpdateClause($updateStatement->updateClause) - . $this->walkWhereClause($updateStatement->whereClause); - } - - /** - * Walks down a DeleteStatement AST node, thereby generating the appropriate SQL. - */ - public function walkDeleteStatement(AST\DeleteStatement $deleteStatement): string - { - $this->useSqlTableAliases = false; - $this->rsm->isSelect = false; - - return $this->walkDeleteClause($deleteStatement->deleteClause) - . $this->walkWhereClause($deleteStatement->whereClause); - } - - /** - * Walks down an IdentificationVariable AST node, thereby generating the appropriate SQL. - * This one differs of ->walkIdentificationVariable() because it generates the entity identifiers. - */ - public function walkEntityIdentificationVariable(string $identVariable): string - { - $class = $this->getMetadataForDqlAlias($identVariable); - $tableAlias = $this->getSQLTableAlias($class->getTableName(), $identVariable); - $sqlParts = []; - - foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { - $sqlParts[] = $tableAlias . '.' . $columnName; - } - - return implode(', ', $sqlParts); - } - - /** - * Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL. - */ - public function walkIdentificationVariable(string $identificationVariable, string|null $fieldName = null): string - { - $class = $this->getMetadataForDqlAlias($identificationVariable); - - if ( - $fieldName !== null && $class->isInheritanceTypeJoined() && - isset($class->fieldMappings[$fieldName]->inherited) - ) { - $class = $this->em->getClassMetadata($class->fieldMappings[$fieldName]->inherited); - } - - return $this->getSQLTableAlias($class->getTableName(), $identificationVariable); - } - - /** - * Walks down a PathExpression AST node, thereby generating the appropriate SQL. - */ - public function walkPathExpression(AST\PathExpression $pathExpr): string - { - $sql = ''; - assert($pathExpr->field !== null); - - switch ($pathExpr->type) { - case AST\PathExpression::TYPE_STATE_FIELD: - $fieldName = $pathExpr->field; - $dqlAlias = $pathExpr->identificationVariable; - $class = $this->getMetadataForDqlAlias($dqlAlias); - - if ($this->useSqlTableAliases) { - $sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; - } - - $sql .= $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); - break; - - case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: - // 1- the owning side: - // Just use the foreign key, i.e. u.group_id - $fieldName = $pathExpr->field; - $dqlAlias = $pathExpr->identificationVariable; - $class = $this->getMetadataForDqlAlias($dqlAlias); - - if (isset($class->associationMappings[$fieldName]->inherited)) { - $class = $this->em->getClassMetadata($class->associationMappings[$fieldName]->inherited); - } - - $assoc = $class->associationMappings[$fieldName]; - - if (! $assoc->isOwningSide()) { - throw QueryException::associationPathInverseSideNotSupported($pathExpr); - } - - assert($assoc->isToOneOwningSide()); - - // COMPOSITE KEYS NOT (YET?) SUPPORTED - if (count($assoc->sourceToTargetKeyColumns) > 1) { - throw QueryException::associationPathCompositeKeyNotSupported(); - } - - if ($this->useSqlTableAliases) { - $sql .= $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'; - } - - $sql .= reset($assoc->targetToSourceKeyColumns); - break; - - default: - throw QueryException::invalidPathExpression($pathExpr); - } - - return $sql; - } - - /** - * Walks down a SelectClause AST node, thereby generating the appropriate SQL. - */ - public function walkSelectClause(AST\SelectClause $selectClause): string - { - $sql = 'SELECT ' . ($selectClause->isDistinct ? 'DISTINCT ' : ''); - $sqlSelectExpressions = array_filter(array_map($this->walkSelectExpression(...), $selectClause->selectExpressions)); - - if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) === true && $selectClause->isDistinct) { - $this->query->setHint(self::HINT_DISTINCT, true); - } - - $addMetaColumns = $this->query->getHydrationMode() === Query::HYDRATE_OBJECT - || $this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS); - - foreach ($this->selectedClasses as $selectedClass) { - $class = $selectedClass['class']; - $dqlAlias = $selectedClass['dqlAlias']; - $resultAlias = $selectedClass['resultAlias']; - - // Register as entity or joined entity result - if (! isset($this->queryComponents[$dqlAlias]['relation'])) { - $this->rsm->addEntityResult($class->name, $dqlAlias, $resultAlias); - } else { - assert(isset($this->queryComponents[$dqlAlias]['parent'])); - - $this->rsm->addJoinedEntityResult( - $class->name, - $dqlAlias, - $this->queryComponents[$dqlAlias]['parent'], - $this->queryComponents[$dqlAlias]['relation']->fieldName, - ); - } - - if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { - // Add discriminator columns to SQL - $rootClass = $this->em->getClassMetadata($class->rootEntityName); - $tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias); - $discrColumn = $rootClass->getDiscriminatorColumn(); - $columnAlias = $this->getSQLColumnAlias($discrColumn->name); - - $sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn->name . ' AS ' . $columnAlias; - - $this->rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); - $this->rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn->fieldName, false, $discrColumn->type); - if (! empty($discrColumn->enumType)) { - $this->rsm->addEnumResult($columnAlias, $discrColumn->enumType); - } - } - - // Add foreign key columns to SQL, if necessary - if (! $addMetaColumns && ! $class->containsForeignIdentifier) { - continue; - } - - // Add foreign key columns of class and also parent classes - foreach ($class->associationMappings as $assoc) { - if ( - ! $assoc->isToOneOwningSide() - || ( ! $addMetaColumns && ! isset($assoc->id)) - ) { - continue; - } - - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - $isIdentifier = (isset($assoc->id) && $assoc->id === true); - $owningClass = isset($assoc->inherited) ? $this->em->getClassMetadata($assoc->inherited) : $class; - $sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias); - - foreach ($assoc->joinColumns as $joinColumn) { - $columnName = $joinColumn->name; - $columnAlias = $this->getSQLColumnAlias($columnName); - $columnType = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - - $quotedColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - $sqlSelectExpressions[] = $sqlTableAlias . '.' . $quotedColumnName . ' AS ' . $columnAlias; - - $this->rsm->addMetaResult($dqlAlias, $columnAlias, $columnName, $isIdentifier, $columnType); - } - } - - // Add foreign key columns to SQL, if necessary - if (! $addMetaColumns) { - continue; - } - - // Add foreign key columns of subclasses - foreach ($class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); - - foreach ($subClass->associationMappings as $assoc) { - // Skip if association is inherited - if (isset($assoc->inherited)) { - continue; - } - - if ($assoc->isToOneOwningSide()) { - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - foreach ($assoc->joinColumns as $joinColumn) { - $columnName = $joinColumn->name; - $columnAlias = $this->getSQLColumnAlias($columnName); - $columnType = PersisterHelper::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $this->em); - - $quotedColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform); - $sqlSelectExpressions[] = $sqlTableAlias . '.' . $quotedColumnName . ' AS ' . $columnAlias; - - $this->rsm->addMetaResult($dqlAlias, $columnAlias, $columnName, $subClass->isIdentifier($columnName), $columnType); - } - } - } - } - } - - return $sql . implode(', ', $sqlSelectExpressions); - } - - /** - * Walks down a FromClause AST node, thereby generating the appropriate SQL. - */ - public function walkFromClause(AST\FromClause $fromClause): string - { - $identificationVarDecls = $fromClause->identificationVariableDeclarations; - $sqlParts = []; - - foreach ($identificationVarDecls as $identificationVariableDecl) { - $sqlParts[] = $this->walkIdentificationVariableDeclaration($identificationVariableDecl); - } - - return ' FROM ' . implode(', ', $sqlParts); - } - - /** - * Walks down a IdentificationVariableDeclaration AST node, thereby generating the appropriate SQL. - */ - public function walkIdentificationVariableDeclaration(AST\IdentificationVariableDeclaration $identificationVariableDecl): string - { - $sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration); - - if ($identificationVariableDecl->indexBy) { - $this->walkIndexBy($identificationVariableDecl->indexBy); - } - - foreach ($identificationVariableDecl->joins as $join) { - $sql .= $this->walkJoin($join); - } - - return $sql; - } - - /** - * Walks down a IndexBy AST node. - */ - public function walkIndexBy(AST\IndexBy $indexBy): void - { - $pathExpression = $indexBy->singleValuedPathExpression; - $alias = $pathExpression->identificationVariable; - assert($pathExpression->field !== null); - - switch ($pathExpression->type) { - case AST\PathExpression::TYPE_STATE_FIELD: - $field = $pathExpression->field; - break; - - case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: - // Just use the foreign key, i.e. u.group_id - $fieldName = $pathExpression->field; - $class = $this->getMetadataForDqlAlias($alias); - - if (isset($class->associationMappings[$fieldName]->inherited)) { - $class = $this->em->getClassMetadata($class->associationMappings[$fieldName]->inherited); - } - - $association = $class->associationMappings[$fieldName]; - - if (! $association->isOwningSide()) { - throw QueryException::associationPathInverseSideNotSupported($pathExpression); - } - - assert($association->isToOneOwningSide()); - - if (count($association->sourceToTargetKeyColumns) > 1) { - throw QueryException::associationPathCompositeKeyNotSupported(); - } - - $field = reset($association->targetToSourceKeyColumns); - break; - - default: - throw QueryException::invalidPathExpression($pathExpression); - } - - if (isset($this->scalarFields[$alias][$field])) { - $this->rsm->addIndexByScalar($this->scalarFields[$alias][$field]); - - return; - } - - $this->rsm->addIndexBy($alias, $field); - } - - /** - * Walks down a RangeVariableDeclaration AST node, thereby generating the appropriate SQL. - */ - public function walkRangeVariableDeclaration(AST\RangeVariableDeclaration $rangeVariableDeclaration): string - { - return $this->generateRangeVariableDeclarationSQL($rangeVariableDeclaration, false); - } - - /** - * Generate appropriate SQL for RangeVariableDeclaration AST node - */ - private function generateRangeVariableDeclarationSQL( - AST\RangeVariableDeclaration $rangeVariableDeclaration, - bool $buildNestedJoins, - ): string { - $class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName); - $dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable; - - if ($rangeVariableDeclaration->isRoot) { - $this->rootAliases[] = $dqlAlias; - } - - $sql = $this->platform->appendLockHint( - $this->quoteStrategy->getTableName($class, $this->platform) . ' ' . - $this->getSQLTableAlias($class->getTableName(), $dqlAlias), - $this->query->getHint(Query::HINT_LOCK_MODE) ?: LockMode::NONE, - ); - - if (! $class->isInheritanceTypeJoined()) { - return $sql; - } - - $classTableInheritanceJoins = $this->generateClassTableInheritanceJoins($class, $dqlAlias); - - if (! $buildNestedJoins) { - return $sql . $classTableInheritanceJoins; - } - - return $classTableInheritanceJoins === '' ? $sql : '(' . $sql . $classTableInheritanceJoins . ')'; - } - - /** - * Walks down a JoinAssociationDeclaration AST node, thereby generating the appropriate SQL. - * - * @psalm-param AST\Join::JOIN_TYPE_* $joinType - * - * @throws QueryException - */ - public function walkJoinAssociationDeclaration( - AST\JoinAssociationDeclaration $joinAssociationDeclaration, - int $joinType = AST\Join::JOIN_TYPE_INNER, - AST\ConditionalExpression|AST\Phase2OptimizableConditional|null $condExpr = null, - ): string { - $sql = ''; - - $associationPathExpression = $joinAssociationDeclaration->joinAssociationPathExpression; - $joinedDqlAlias = $joinAssociationDeclaration->aliasIdentificationVariable; - $indexBy = $joinAssociationDeclaration->indexBy; - - $relation = $this->queryComponents[$joinedDqlAlias]['relation'] ?? null; - assert($relation !== null); - $targetClass = $this->em->getClassMetadata($relation->targetEntity); - $sourceClass = $this->em->getClassMetadata($relation->sourceEntity); - $targetTableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); - - $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias); - $sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable); - - // Ensure we got the owning side, since it has all mapping info - $assoc = $this->em->getMetadataFactory()->getOwningSide($relation); - - if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) === true && (! $this->query->getHint(self::HINT_DISTINCT) || isset($this->selectedClasses[$joinedDqlAlias]))) { - if ($relation->isToMany()) { - throw QueryException::iterateWithFetchJoinNotAllowed($assoc); - } - } - - $fetchMode = $this->query->getHint('fetchMode')[$assoc->sourceEntity][$assoc->fieldName] ?? $relation->fetch; - - if ($fetchMode === ClassMetadata::FETCH_EAGER && $condExpr !== null) { - throw QueryException::eagerFetchJoinWithNotAllowed($assoc->sourceEntity, $assoc->fieldName); - } - - // This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot - // be the owning side and previously we ensured that $assoc is always the owning side of the associations. - // The owning side is necessary at this point because only it contains the JoinColumn information. - switch (true) { - case $assoc->isToOne(): - assert($assoc->isToOneOwningSide()); - $conditions = []; - - foreach ($assoc->joinColumns as $joinColumn) { - $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - - if ($relation->isOwningSide()) { - $conditions[] = $sourceTableAlias . '.' . $quotedSourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn; - - continue; - } - - $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $quotedSourceColumn; - } - - // Apply remaining inheritance restrictions - $discrSql = $this->generateDiscriminatorColumnConditionSQL([$joinedDqlAlias]); - - if ($discrSql) { - $conditions[] = $discrSql; - } - - // Apply the filters - $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias); - - if ($filterExpr) { - $conditions[] = $filterExpr; - } - - $targetTableJoin = [ - 'table' => $targetTableName . ' ' . $targetTableAlias, - 'condition' => implode(' AND ', $conditions), - ]; - break; - - case $assoc->isManyToMany(): - // Join relation table - $joinTable = $assoc->joinTable; - $joinTableAlias = $this->getSQLTableAlias($joinTable->name, $joinedDqlAlias); - $joinTableName = $this->quoteStrategy->getJoinTableName($assoc, $sourceClass, $this->platform); - - $conditions = []; - $relationColumns = $relation->isOwningSide() - ? $assoc->joinTable->joinColumns - : $assoc->joinTable->inverseJoinColumns; - - foreach ($relationColumns as $joinColumn) { - $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - - $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; - } - - $sql .= $joinTableName . ' ' . $joinTableAlias . ' ON ' . implode(' AND ', $conditions); - - // Join target table - $sql .= $joinType === AST\Join::JOIN_TYPE_LEFT || $joinType === AST\Join::JOIN_TYPE_LEFTOUTER ? ' LEFT JOIN ' : ' INNER JOIN '; - - $conditions = []; - $relationColumns = $relation->isOwningSide() - ? $assoc->joinTable->inverseJoinColumns - : $assoc->joinTable->joinColumns; - - foreach ($relationColumns as $joinColumn) { - $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); - $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - - $conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; - } - - // Apply remaining inheritance restrictions - $discrSql = $this->generateDiscriminatorColumnConditionSQL([$joinedDqlAlias]); - - if ($discrSql) { - $conditions[] = $discrSql; - } - - // Apply the filters - $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias); - - if ($filterExpr) { - $conditions[] = $filterExpr; - } - - $targetTableJoin = [ - 'table' => $targetTableName . ' ' . $targetTableAlias, - 'condition' => implode(' AND ', $conditions), - ]; - break; - - default: - throw new BadMethodCallException('Type of association must be one of *_TO_ONE or MANY_TO_MANY'); - } - - // Handle WITH clause - $withCondition = $condExpr === null ? '' : ('(' . $this->walkConditionalExpression($condExpr) . ')'); - - if ($targetClass->isInheritanceTypeJoined()) { - $ctiJoins = $this->generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); - // If we have WITH condition, we need to build nested joins for target class table and cti joins - if ($withCondition && $ctiJoins) { - $sql .= '(' . $targetTableJoin['table'] . $ctiJoins . ') ON ' . $targetTableJoin['condition']; - } else { - $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition'] . $ctiJoins; - } - } else { - $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition']; - } - - if ($withCondition) { - $sql .= ' AND ' . $withCondition; - } - - // Apply the indexes - if ($indexBy) { - // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently. - $this->walkIndexBy($indexBy); - } elseif ($relation->isIndexed()) { - $this->rsm->addIndexBy($joinedDqlAlias, $relation->indexBy()); - } - - return $sql; - } - - /** - * Walks down a FunctionNode AST node, thereby generating the appropriate SQL. - */ - public function walkFunction(AST\Functions\FunctionNode $function): string - { - return $function->getSql($this); - } - - /** - * Walks down an OrderByClause AST node, thereby generating the appropriate SQL. - */ - public function walkOrderByClause(AST\OrderByClause $orderByClause): string - { - $orderByItems = array_map($this->walkOrderByItem(...), $orderByClause->orderByItems); - - $collectionOrderByItems = $this->generateOrderedCollectionOrderByItems(); - if ($collectionOrderByItems !== '') { - $orderByItems = array_merge($orderByItems, (array) $collectionOrderByItems); - } - - return ' ORDER BY ' . implode(', ', $orderByItems); - } - - /** - * Walks down an OrderByItem AST node, thereby generating the appropriate SQL. - */ - public function walkOrderByItem(AST\OrderByItem $orderByItem): string - { - $type = strtoupper($orderByItem->type); - $expr = $orderByItem->expression; - $sql = $expr instanceof AST\Node - ? $expr->dispatch($this) - : $this->walkResultVariable($this->queryComponents[$expr]['token']->value); - - $this->orderedColumnsMap[$sql] = $type; - - if ($expr instanceof AST\Subselect) { - return '(' . $sql . ') ' . $type; - } - - return $sql . ' ' . $type; - } - - /** - * Walks down a HavingClause AST node, thereby generating the appropriate SQL. - */ - public function walkHavingClause(AST\HavingClause $havingClause): string - { - return ' HAVING ' . $this->walkConditionalExpression($havingClause->conditionalExpression); - } - - /** - * Walks down a Join AST node and creates the corresponding SQL. - */ - public function walkJoin(AST\Join $join): string - { - $joinType = $join->joinType; - $joinDeclaration = $join->joinAssociationDeclaration; - - $sql = $joinType === AST\Join::JOIN_TYPE_LEFT || $joinType === AST\Join::JOIN_TYPE_LEFTOUTER - ? ' LEFT JOIN ' - : ' INNER JOIN '; - - switch (true) { - case $joinDeclaration instanceof AST\RangeVariableDeclaration: - $class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName); - $dqlAlias = $joinDeclaration->aliasIdentificationVariable; - $tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - $conditions = []; - - if ($join->conditionalExpression) { - $conditions[] = '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')'; - } - - $isUnconditionalJoin = $conditions === []; - $condExprConjunction = $class->isInheritanceTypeJoined() && $joinType !== AST\Join::JOIN_TYPE_LEFT && $joinType !== AST\Join::JOIN_TYPE_LEFTOUTER && $isUnconditionalJoin - ? ' AND ' - : ' ON '; - - $sql .= $this->generateRangeVariableDeclarationSQL($joinDeclaration, ! $isUnconditionalJoin); - - // Apply remaining inheritance restrictions - $discrSql = $this->generateDiscriminatorColumnConditionSQL([$dqlAlias]); - - if ($discrSql) { - $conditions[] = $discrSql; - } - - // Apply the filters - $filterExpr = $this->generateFilterConditionSQL($class, $tableAlias); - - if ($filterExpr) { - $conditions[] = $filterExpr; - } - - if ($conditions) { - $sql .= $condExprConjunction . implode(' AND ', $conditions); - } - - break; - - case $joinDeclaration instanceof AST\JoinAssociationDeclaration: - $sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType, $join->conditionalExpression); - break; - } - - return $sql; - } - - /** - * Walks down a CoalesceExpression AST node and generates the corresponding SQL. - */ - public function walkCoalesceExpression(AST\CoalesceExpression $coalesceExpression): string - { - $sql = 'COALESCE('; - - $scalarExpressions = []; - - foreach ($coalesceExpression->scalarExpressions as $scalarExpression) { - $scalarExpressions[] = $this->walkSimpleArithmeticExpression($scalarExpression); - } - - return $sql . implode(', ', $scalarExpressions) . ')'; - } - - /** - * Walks down a NullIfExpression AST node and generates the corresponding SQL. - */ - public function walkNullIfExpression(AST\NullIfExpression $nullIfExpression): string - { - $firstExpression = is_string($nullIfExpression->firstExpression) - ? $this->conn->quote($nullIfExpression->firstExpression) - : $this->walkSimpleArithmeticExpression($nullIfExpression->firstExpression); - - $secondExpression = is_string($nullIfExpression->secondExpression) - ? $this->conn->quote($nullIfExpression->secondExpression) - : $this->walkSimpleArithmeticExpression($nullIfExpression->secondExpression); - - return 'NULLIF(' . $firstExpression . ', ' . $secondExpression . ')'; - } - - /** - * Walks down a GeneralCaseExpression AST node and generates the corresponding SQL. - */ - public function walkGeneralCaseExpression(AST\GeneralCaseExpression $generalCaseExpression): string - { - $sql = 'CASE'; - - foreach ($generalCaseExpression->whenClauses as $whenClause) { - $sql .= ' WHEN ' . $this->walkConditionalExpression($whenClause->caseConditionExpression); - $sql .= ' THEN ' . $this->walkSimpleArithmeticExpression($whenClause->thenScalarExpression); - } - - $sql .= ' ELSE ' . $this->walkSimpleArithmeticExpression($generalCaseExpression->elseScalarExpression) . ' END'; - - return $sql; - } - - /** - * Walks down a SimpleCaseExpression AST node and generates the corresponding SQL. - */ - public function walkSimpleCaseExpression(AST\SimpleCaseExpression $simpleCaseExpression): string - { - $sql = 'CASE ' . $this->walkStateFieldPathExpression($simpleCaseExpression->caseOperand); - - foreach ($simpleCaseExpression->simpleWhenClauses as $simpleWhenClause) { - $sql .= ' WHEN ' . $this->walkSimpleArithmeticExpression($simpleWhenClause->caseScalarExpression); - $sql .= ' THEN ' . $this->walkSimpleArithmeticExpression($simpleWhenClause->thenScalarExpression); - } - - $sql .= ' ELSE ' . $this->walkSimpleArithmeticExpression($simpleCaseExpression->elseScalarExpression) . ' END'; - - return $sql; - } - - /** - * Walks down a SelectExpression AST node and generates the corresponding SQL. - */ - public function walkSelectExpression(AST\SelectExpression $selectExpression): string - { - $sql = ''; - $expr = $selectExpression->expression; - $hidden = $selectExpression->hiddenAliasResultVariable; - - switch (true) { - case $expr instanceof AST\PathExpression: - if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) { - throw QueryException::invalidPathExpression($expr); - } - - assert($expr->field !== null); - $fieldName = $expr->field; - $dqlAlias = $expr->identificationVariable; - $class = $this->getMetadataForDqlAlias($dqlAlias); - - $resultAlias = $selectExpression->fieldIdentificationVariable ?: $fieldName; - $tableName = $class->isInheritanceTypeJoined() - ? $this->em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName) - : $class->getTableName(); - - $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); - $fieldMapping = $class->fieldMappings[$fieldName]; - $columnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); - $columnAlias = $this->getSQLColumnAlias($fieldMapping->columnName); - $col = $sqlTableAlias . '.' . $columnName; - - $type = Type::getType($fieldMapping->type); - $col = $type->convertToPHPValueSQL($col, $this->conn->getDatabasePlatform()); - - $sql .= $col . ' AS ' . $columnAlias; - - $this->scalarResultAliasMap[$resultAlias] = $columnAlias; - - if (! $hidden) { - $this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldMapping->type); - $this->scalarFields[$dqlAlias][$fieldName] = $columnAlias; - - if (! empty($fieldMapping->enumType)) { - $this->rsm->addEnumResult($columnAlias, $fieldMapping->enumType); - } - } - - break; - - case $expr instanceof AST\AggregateExpression: - case $expr instanceof AST\Functions\FunctionNode: - case $expr instanceof AST\SimpleArithmeticExpression: - case $expr instanceof AST\ArithmeticTerm: - case $expr instanceof AST\ArithmeticFactor: - case $expr instanceof AST\ParenthesisExpression: - case $expr instanceof AST\Literal: - case $expr instanceof AST\NullIfExpression: - case $expr instanceof AST\CoalesceExpression: - case $expr instanceof AST\GeneralCaseExpression: - case $expr instanceof AST\SimpleCaseExpression: - $columnAlias = $this->getSQLColumnAlias('sclr'); - $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; - - $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; - - $this->scalarResultAliasMap[$resultAlias] = $columnAlias; - - if ($hidden) { - break; - } - - if (! $expr instanceof Query\AST\TypedExpression) { - // Conceptually we could resolve field type here by traverse through AST to retrieve field type, - // but this is not a feasible solution; assume 'string'. - $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); - - break; - } - - $this->rsm->addScalarResult($columnAlias, $resultAlias, Type::getTypeRegistry()->lookupName($expr->getReturnType())); - - break; - - case $expr instanceof AST\Subselect: - $columnAlias = $this->getSQLColumnAlias('sclr'); - $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; - - $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; - - $this->scalarResultAliasMap[$resultAlias] = $columnAlias; - - if (! $hidden) { - // We cannot resolve field type here; assume 'string'. - $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); - } - - break; - - case $expr instanceof AST\NewObjectExpression: - $sql .= $this->walkNewObject($expr, $selectExpression->fieldIdentificationVariable); - break; - - default: - $dqlAlias = $expr; - $class = $this->getMetadataForDqlAlias($dqlAlias); - $resultAlias = $selectExpression->fieldIdentificationVariable ?: null; - - if (! isset($this->selectedClasses[$dqlAlias])) { - $this->selectedClasses[$dqlAlias] = [ - 'class' => $class, - 'dqlAlias' => $dqlAlias, - 'resultAlias' => $resultAlias, - ]; - } - - $sqlParts = []; - - // Select all fields from the queried class - foreach ($class->fieldMappings as $fieldName => $mapping) { - $tableName = isset($mapping->inherited) - ? $this->em->getClassMetadata($mapping->inherited)->getTableName() - : $class->getTableName(); - - $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); - $columnAlias = $this->getSQLColumnAlias($mapping->columnName); - $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); - - $col = $sqlTableAlias . '.' . $quotedColumnName; - - $type = Type::getType($mapping->type); - $col = $type->convertToPHPValueSQL($col, $this->platform); - - $sqlParts[] = $col . ' AS ' . $columnAlias; - - $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; - - $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); - - if (! empty($mapping->enumType)) { - $this->rsm->addEnumResult($columnAlias, $mapping->enumType); - } - } - - // Add any additional fields of subclasses (excluding inherited fields) - // 1) on Single Table Inheritance: always, since its marginal overhead - // 2) on Class Table Inheritance - foreach ($class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); - - foreach ($subClass->fieldMappings as $fieldName => $mapping) { - if (isset($mapping->inherited)) { - continue; - } - - $columnAlias = $this->getSQLColumnAlias($mapping->columnName); - $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $subClass, $this->platform); - - $col = $sqlTableAlias . '.' . $quotedColumnName; - - $type = Type::getType($mapping->type); - $col = $type->convertToPHPValueSQL($col, $this->platform); - - $sqlParts[] = $col . ' AS ' . $columnAlias; - - $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; - - $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); - } - } - - $sql .= implode(', ', $sqlParts); - } - - return $sql; - } - - public function walkQuantifiedExpression(AST\QuantifiedExpression $qExpr): string - { - return ' ' . strtoupper($qExpr->type) . '(' . $this->walkSubselect($qExpr->subselect) . ')'; - } - - /** - * Walks down a Subselect AST node, thereby generating the appropriate SQL. - */ - public function walkSubselect(AST\Subselect $subselect): string - { - $useAliasesBefore = $this->useSqlTableAliases; - $rootAliasesBefore = $this->rootAliases; - - $this->rootAliases = []; // reset the rootAliases for the subselect - $this->useSqlTableAliases = true; - - $sql = $this->walkSimpleSelectClause($subselect->simpleSelectClause); - $sql .= $this->walkSubselectFromClause($subselect->subselectFromClause); - $sql .= $this->walkWhereClause($subselect->whereClause); - - $sql .= $subselect->groupByClause ? $this->walkGroupByClause($subselect->groupByClause) : ''; - $sql .= $subselect->havingClause ? $this->walkHavingClause($subselect->havingClause) : ''; - $sql .= $subselect->orderByClause ? $this->walkOrderByClause($subselect->orderByClause) : ''; - - $this->rootAliases = $rootAliasesBefore; // put the main aliases back - $this->useSqlTableAliases = $useAliasesBefore; - - return $sql; - } - - /** - * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. - */ - public function walkSubselectFromClause(AST\SubselectFromClause $subselectFromClause): string - { - $identificationVarDecls = $subselectFromClause->identificationVariableDeclarations; - $sqlParts = []; - - foreach ($identificationVarDecls as $subselectIdVarDecl) { - $sqlParts[] = $this->walkIdentificationVariableDeclaration($subselectIdVarDecl); - } - - return ' FROM ' . implode(', ', $sqlParts); - } - - /** - * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. - */ - public function walkSimpleSelectClause(AST\SimpleSelectClause $simpleSelectClause): string - { - return 'SELECT' . ($simpleSelectClause->isDistinct ? ' DISTINCT' : '') - . $this->walkSimpleSelectExpression($simpleSelectClause->simpleSelectExpression); - } - - public function walkParenthesisExpression(AST\ParenthesisExpression $parenthesisExpression): string - { - return sprintf('(%s)', $parenthesisExpression->expression->dispatch($this)); - } - - public function walkNewObject(AST\NewObjectExpression $newObjectExpression, string|null $newObjectResultAlias = null): string - { - $sqlSelectExpressions = []; - $objIndex = $newObjectResultAlias ?: $this->newObjectCounter++; - - foreach ($newObjectExpression->args as $argIndex => $e) { - $resultAlias = $this->scalarResultCounter++; - $columnAlias = $this->getSQLColumnAlias('sclr'); - $fieldType = 'string'; - - switch (true) { - case $e instanceof AST\NewObjectExpression: - $sqlSelectExpressions[] = $e->dispatch($this); - break; - - case $e instanceof AST\Subselect: - $sqlSelectExpressions[] = '(' . $e->dispatch($this) . ') AS ' . $columnAlias; - break; - - case $e instanceof AST\PathExpression: - assert($e->field !== null); - $dqlAlias = $e->identificationVariable; - $class = $this->getMetadataForDqlAlias($dqlAlias); - $fieldName = $e->field; - $fieldMapping = $class->fieldMappings[$fieldName]; - $fieldType = $fieldMapping->type; - $col = trim($e->dispatch($this)); - - $type = Type::getType($fieldType); - $col = $type->convertToPHPValueSQL($col, $this->platform); - - $sqlSelectExpressions[] = $col . ' AS ' . $columnAlias; - - if (! empty($fieldMapping->enumType)) { - $this->rsm->addEnumResult($columnAlias, $fieldMapping->enumType); - } - - break; - - case $e instanceof AST\Literal: - switch ($e->type) { - case AST\Literal::BOOLEAN: - $fieldType = 'boolean'; - break; - - case AST\Literal::NUMERIC: - $fieldType = is_float($e->value) ? 'float' : 'integer'; - break; - } - - $sqlSelectExpressions[] = trim($e->dispatch($this)) . ' AS ' . $columnAlias; - break; - - default: - $sqlSelectExpressions[] = trim($e->dispatch($this)) . ' AS ' . $columnAlias; - break; - } - - $this->scalarResultAliasMap[$resultAlias] = $columnAlias; - $this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType); - - $this->rsm->newObjectMappings[$columnAlias] = [ - 'className' => $newObjectExpression->className, - 'objIndex' => $objIndex, - 'argIndex' => $argIndex, - ]; - } - - return implode(', ', $sqlSelectExpressions); - } - - /** - * Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL. - */ - public function walkSimpleSelectExpression(AST\SimpleSelectExpression $simpleSelectExpression): string - { - $expr = $simpleSelectExpression->expression; - $sql = ' '; - - switch (true) { - case $expr instanceof AST\PathExpression: - $sql .= $this->walkPathExpression($expr); - break; - - case $expr instanceof AST\Subselect: - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; - - $columnAlias = 'sclr' . $this->aliasCounter++; - $this->scalarResultAliasMap[$alias] = $columnAlias; - - $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; - break; - - case $expr instanceof AST\Functions\FunctionNode: - case $expr instanceof AST\SimpleArithmeticExpression: - case $expr instanceof AST\ArithmeticTerm: - case $expr instanceof AST\ArithmeticFactor: - case $expr instanceof AST\Literal: - case $expr instanceof AST\NullIfExpression: - case $expr instanceof AST\CoalesceExpression: - case $expr instanceof AST\GeneralCaseExpression: - case $expr instanceof AST\SimpleCaseExpression: - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; - - $columnAlias = $this->getSQLColumnAlias('sclr'); - $this->scalarResultAliasMap[$alias] = $columnAlias; - - $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; - break; - - case $expr instanceof AST\ParenthesisExpression: - $sql .= $this->walkParenthesisExpression($expr); - break; - - default: // IdentificationVariable - $sql .= $this->walkEntityIdentificationVariable($expr); - break; - } - - return $sql; - } - - /** - * Walks down an AggregateExpression AST node, thereby generating the appropriate SQL. - */ - public function walkAggregateExpression(AST\AggregateExpression $aggExpression): string - { - return $aggExpression->functionName . '(' . ($aggExpression->isDistinct ? 'DISTINCT ' : '') - . $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) . ')'; - } - - /** - * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. - */ - public function walkGroupByClause(AST\GroupByClause $groupByClause): string - { - $sqlParts = []; - - foreach ($groupByClause->groupByItems as $groupByItem) { - $sqlParts[] = $this->walkGroupByItem($groupByItem); - } - - return ' GROUP BY ' . implode(', ', $sqlParts); - } - - /** - * Walks down a GroupByItem AST node, thereby generating the appropriate SQL. - */ - public function walkGroupByItem(AST\PathExpression|string $groupByItem): string - { - // StateFieldPathExpression - if (! is_string($groupByItem)) { - return $this->walkPathExpression($groupByItem); - } - - // ResultVariable - if (isset($this->queryComponents[$groupByItem]['resultVariable'])) { - $resultVariable = $this->queryComponents[$groupByItem]['resultVariable']; - - if ($resultVariable instanceof AST\PathExpression) { - return $this->walkPathExpression($resultVariable); - } - - if ($resultVariable instanceof AST\Node && isset($resultVariable->pathExpression)) { - return $this->walkPathExpression($resultVariable->pathExpression); - } - - return $this->walkResultVariable($groupByItem); - } - - // IdentificationVariable - $sqlParts = []; - - foreach ($this->getMetadataForDqlAlias($groupByItem)->fieldNames as $field) { - $item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field); - $item->type = AST\PathExpression::TYPE_STATE_FIELD; - - $sqlParts[] = $this->walkPathExpression($item); - } - - foreach ($this->getMetadataForDqlAlias($groupByItem)->associationMappings as $mapping) { - if ($mapping->isToOneOwningSide()) { - $item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping->fieldName); - $item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - - $sqlParts[] = $this->walkPathExpression($item); - } - } - - return implode(', ', $sqlParts); - } - - /** - * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. - */ - public function walkDeleteClause(AST\DeleteClause $deleteClause): string - { - $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName); - $tableName = $class->getTableName(); - $sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform); - - $this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable); - $this->rootAliases[] = $deleteClause->aliasIdentificationVariable; - - return $sql; - } - - /** - * Walks down an UpdateClause AST node, thereby generating the appropriate SQL. - */ - public function walkUpdateClause(AST\UpdateClause $updateClause): string - { - $class = $this->em->getClassMetadata($updateClause->abstractSchemaName); - $tableName = $class->getTableName(); - $sql = 'UPDATE ' . $this->quoteStrategy->getTableName($class, $this->platform); - - $this->setSQLTableAlias($tableName, $tableName, $updateClause->aliasIdentificationVariable); - $this->rootAliases[] = $updateClause->aliasIdentificationVariable; - - return $sql . ' SET ' . implode(', ', array_map($this->walkUpdateItem(...), $updateClause->updateItems)); - } - - /** - * Walks down an UpdateItem AST node, thereby generating the appropriate SQL. - */ - public function walkUpdateItem(AST\UpdateItem $updateItem): string - { - $useTableAliasesBefore = $this->useSqlTableAliases; - $this->useSqlTableAliases = false; - - $sql = $this->walkPathExpression($updateItem->pathExpression) . ' = '; - $newValue = $updateItem->newValue; - - $sql .= match (true) { - $newValue instanceof AST\Node => $newValue->dispatch($this), - $newValue === null => 'NULL', - }; - - $this->useSqlTableAliases = $useTableAliasesBefore; - - return $sql; - } - - /** - * Walks down a WhereClause AST node, thereby generating the appropriate SQL. - * - * WhereClause or not, the appropriate discriminator sql is added. - */ - public function walkWhereClause(AST\WhereClause|null $whereClause): string - { - $condSql = $whereClause !== null ? $this->walkConditionalExpression($whereClause->conditionalExpression) : ''; - $discrSql = $this->generateDiscriminatorColumnConditionSQL($this->rootAliases); - - if ($this->em->hasFilters()) { - $filterClauses = []; - foreach ($this->rootAliases as $dqlAlias) { - $class = $this->getMetadataForDqlAlias($dqlAlias); - $tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - - $filterExpr = $this->generateFilterConditionSQL($class, $tableAlias); - if ($filterExpr) { - $filterClauses[] = $filterExpr; - } - } - - if (count($filterClauses)) { - if ($condSql) { - $condSql = '(' . $condSql . ') AND '; - } - - $condSql .= implode(' AND ', $filterClauses); - } - } - - if ($condSql) { - return ' WHERE ' . (! $discrSql ? $condSql : '(' . $condSql . ') AND ' . $discrSql); - } - - if ($discrSql) { - return ' WHERE ' . $discrSql; - } - - return ''; - } - - /** - * Walk down a ConditionalExpression AST node, thereby generating the appropriate SQL. - */ - public function walkConditionalExpression( - AST\ConditionalExpression|AST\Phase2OptimizableConditional $condExpr, - ): string { - // Phase 2 AST optimization: Skip processing of ConditionalExpression - // if only one ConditionalTerm is defined - if (! ($condExpr instanceof AST\ConditionalExpression)) { - return $this->walkConditionalTerm($condExpr); - } - - return implode(' OR ', array_map($this->walkConditionalTerm(...), $condExpr->conditionalTerms)); - } - - /** - * Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL. - */ - public function walkConditionalTerm( - AST\ConditionalTerm|AST\ConditionalPrimary|AST\ConditionalFactor $condTerm, - ): string { - // Phase 2 AST optimization: Skip processing of ConditionalTerm - // if only one ConditionalFactor is defined - if (! ($condTerm instanceof AST\ConditionalTerm)) { - return $this->walkConditionalFactor($condTerm); - } - - return implode(' AND ', array_map($this->walkConditionalFactor(...), $condTerm->conditionalFactors)); - } - - /** - * Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL. - */ - public function walkConditionalFactor( - AST\ConditionalFactor|AST\ConditionalPrimary $factor, - ): string { - // Phase 2 AST optimization: Skip processing of ConditionalFactor - // if only one ConditionalPrimary is defined - return ! ($factor instanceof AST\ConditionalFactor) - ? $this->walkConditionalPrimary($factor) - : ($factor->not ? 'NOT ' : '') . $this->walkConditionalPrimary($factor->conditionalPrimary); - } - - /** - * Walks down a ConditionalPrimary AST node, thereby generating the appropriate SQL. - */ - public function walkConditionalPrimary(AST\ConditionalPrimary $primary): string - { - if ($primary->isSimpleConditionalExpression()) { - return $primary->simpleConditionalExpression->dispatch($this); - } - - if ($primary->isConditionalExpression()) { - $condExpr = $primary->conditionalExpression; - - return '(' . $this->walkConditionalExpression($condExpr) . ')'; - } - - throw new LogicException('Unexpected state of ConditionalPrimary node.'); - } - - /** - * Walks down an ExistsExpression AST node, thereby generating the appropriate SQL. - */ - public function walkExistsExpression(AST\ExistsExpression $existsExpr): string - { - $sql = $existsExpr->not ? 'NOT ' : ''; - - $sql .= 'EXISTS (' . $this->walkSubselect($existsExpr->subselect) . ')'; - - return $sql; - } - - /** - * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. - */ - public function walkCollectionMemberExpression(AST\CollectionMemberExpression $collMemberExpr): string - { - $sql = $collMemberExpr->not ? 'NOT ' : ''; - $sql .= 'EXISTS (SELECT 1 FROM '; - - $entityExpr = $collMemberExpr->entityExpression; - $collPathExpr = $collMemberExpr->collectionValuedPathExpression; - assert($collPathExpr->field !== null); - - $fieldName = $collPathExpr->field; - $dqlAlias = $collPathExpr->identificationVariable; - - $class = $this->getMetadataForDqlAlias($dqlAlias); - - switch (true) { - // InputParameter - case $entityExpr instanceof AST\InputParameter: - $dqlParamKey = $entityExpr->name; - $entitySql = '?'; - break; - - // SingleValuedAssociationPathExpression | IdentificationVariable - case $entityExpr instanceof AST\PathExpression: - $entitySql = $this->walkPathExpression($entityExpr); - break; - - default: - throw new BadMethodCallException('Not implemented'); - } - - $assoc = $class->associationMappings[$fieldName]; - - if ($assoc->isOneToMany()) { - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); - $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - - $sql .= $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' WHERE '; - - $owningAssoc = $targetClass->associationMappings[$assoc->mappedBy]; - assert($owningAssoc->isManyToOne()); - $sqlParts = []; - - foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) { - $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $this->platform); - - $sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; - } - - foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) { - if (isset($dqlParamKey)) { - $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); - } - - $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql; - } - - $sql .= implode(' AND ', $sqlParts); - } else { // many-to-many - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - $owningAssoc = $this->em->getMetadataFactory()->getOwningSide($assoc); - assert($owningAssoc->isManyToManyOwningSide()); - $joinTable = $owningAssoc->joinTable; - - // SQL table aliases - $joinTableAlias = $this->getSQLTableAlias($joinTable->name); - $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - - $sql .= $this->quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $this->platform) . ' ' . $joinTableAlias . ' WHERE '; - - $joinColumns = $assoc->isOwningSide() ? $joinTable->joinColumns : $joinTable->inverseJoinColumns; - $sqlParts = []; - - foreach ($joinColumns as $joinColumn) { - $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$joinColumn->referencedColumnName], $class, $this->platform); - - $sqlParts[] = $joinTableAlias . '.' . $joinColumn->name . ' = ' . $sourceTableAlias . '.' . $targetColumn; - } - - $joinColumns = $assoc->isOwningSide() ? $joinTable->inverseJoinColumns : $joinTable->joinColumns; - - foreach ($joinColumns as $joinColumn) { - if (isset($dqlParamKey)) { - $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); - } - - $sqlParts[] = $joinTableAlias . '.' . $joinColumn->name . ' IN (' . $entitySql . ')'; - } - - $sql .= implode(' AND ', $sqlParts); - } - - return $sql . ')'; - } - - /** - * Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL. - */ - public function walkEmptyCollectionComparisonExpression(AST\EmptyCollectionComparisonExpression $emptyCollCompExpr): string - { - $sizeFunc = new AST\Functions\SizeFunction('size'); - $sizeFunc->collectionPathExpression = $emptyCollCompExpr->expression; - - return $sizeFunc->getSql($this) . ($emptyCollCompExpr->not ? ' > 0' : ' = 0'); - } - - /** - * Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL. - */ - public function walkNullComparisonExpression(AST\NullComparisonExpression $nullCompExpr): string - { - $expression = $nullCompExpr->expression; - $comparison = ' IS' . ($nullCompExpr->not ? ' NOT' : '') . ' NULL'; - - // Handle ResultVariable - if (is_string($expression) && isset($this->queryComponents[$expression]['resultVariable'])) { - return $this->walkResultVariable($expression) . $comparison; - } - - // Handle InputParameter mapping inclusion to ParserResult - if ($expression instanceof AST\InputParameter) { - return $this->walkInputParameter($expression) . $comparison; - } - - assert(! is_string($expression)); - - return $expression->dispatch($this) . $comparison; - } - - /** - * Walks down an InExpression AST node, thereby generating the appropriate SQL. - */ - public function walkInListExpression(AST\InListExpression $inExpr): string - { - return $this->walkArithmeticExpression($inExpr->expression) - . ($inExpr->not ? ' NOT' : '') . ' IN (' - . implode(', ', array_map($this->walkInParameter(...), $inExpr->literals)) - . ')'; - } - - /** - * Walks down an InExpression AST node, thereby generating the appropriate SQL. - */ - public function walkInSubselectExpression(AST\InSubselectExpression $inExpr): string - { - return $this->walkArithmeticExpression($inExpr->expression) - . ($inExpr->not ? ' NOT' : '') . ' IN (' - . $this->walkSubselect($inExpr->subselect) - . ')'; - } - - /** - * Walks down an InstanceOfExpression AST node, thereby generating the appropriate SQL. - * - * @throws QueryException - */ - public function walkInstanceOfExpression(AST\InstanceOfExpression $instanceOfExpr): string - { - $sql = ''; - - $dqlAlias = $instanceOfExpr->identificationVariable; - $discrClass = $class = $this->getMetadataForDqlAlias($dqlAlias); - - if ($class->discriminatorColumn) { - $discrClass = $this->em->getClassMetadata($class->rootEntityName); - } - - if ($this->useSqlTableAliases) { - $sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.'; - } - - $sql .= $class->getDiscriminatorColumn()->name . ($instanceOfExpr->not ? ' NOT IN ' : ' IN '); - $sql .= $this->getChildDiscriminatorsFromClassMetadata($discrClass, $instanceOfExpr); - - return $sql; - } - - public function walkInParameter(mixed $inParam): string - { - return $inParam instanceof AST\InputParameter - ? $this->walkInputParameter($inParam) - : $this->walkArithmeticExpression($inParam); - } - - /** - * Walks down a literal that represents an AST node, thereby generating the appropriate SQL. - */ - public function walkLiteral(AST\Literal $literal): string - { - return match ($literal->type) { - AST\Literal::STRING => $this->conn->quote($literal->value), - AST\Literal::BOOLEAN => (string) $this->conn->getDatabasePlatform()->convertBooleans(strtolower($literal->value) === 'true'), - AST\Literal::NUMERIC => (string) $literal->value, - default => throw QueryException::invalidLiteral($literal), - }; - } - - /** - * Walks down a BetweenExpression AST node, thereby generating the appropriate SQL. - */ - public function walkBetweenExpression(AST\BetweenExpression $betweenExpr): string - { - $sql = $this->walkArithmeticExpression($betweenExpr->expression); - - if ($betweenExpr->not) { - $sql .= ' NOT'; - } - - $sql .= ' BETWEEN ' . $this->walkArithmeticExpression($betweenExpr->leftBetweenExpression) - . ' AND ' . $this->walkArithmeticExpression($betweenExpr->rightBetweenExpression); - - return $sql; - } - - /** - * Walks down a LikeExpression AST node, thereby generating the appropriate SQL. - */ - public function walkLikeExpression(AST\LikeExpression $likeExpr): string - { - $stringExpr = $likeExpr->stringExpression; - if (is_string($stringExpr)) { - if (! isset($this->queryComponents[$stringExpr]['resultVariable'])) { - throw new LogicException(sprintf('No result variable found for string expression "%s".', $stringExpr)); - } - - $leftExpr = $this->walkResultVariable($stringExpr); - } else { - $leftExpr = $stringExpr->dispatch($this); - } - - $sql = $leftExpr . ($likeExpr->not ? ' NOT' : '') . ' LIKE '; - - if ($likeExpr->stringPattern instanceof AST\InputParameter) { - $sql .= $this->walkInputParameter($likeExpr->stringPattern); - } elseif ($likeExpr->stringPattern instanceof AST\Functions\FunctionNode) { - $sql .= $this->walkFunction($likeExpr->stringPattern); - } elseif ($likeExpr->stringPattern instanceof AST\PathExpression) { - $sql .= $this->walkPathExpression($likeExpr->stringPattern); - } else { - $sql .= $this->walkLiteral($likeExpr->stringPattern); - } - - if ($likeExpr->escapeChar) { - $sql .= ' ESCAPE ' . $this->walkLiteral($likeExpr->escapeChar); - } - - return $sql; - } - - /** - * Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL. - */ - public function walkStateFieldPathExpression(AST\PathExpression $stateFieldPathExpression): string - { - return $this->walkPathExpression($stateFieldPathExpression); - } - - /** - * Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL. - */ - public function walkComparisonExpression(AST\ComparisonExpression $compExpr): string - { - $leftExpr = $compExpr->leftExpression; - $rightExpr = $compExpr->rightExpression; - $sql = ''; - - $sql .= $leftExpr instanceof AST\Node - ? $leftExpr->dispatch($this) - : (is_numeric($leftExpr) ? $leftExpr : $this->conn->quote($leftExpr)); - - $sql .= ' ' . $compExpr->operator . ' '; - - $sql .= $rightExpr instanceof AST\Node - ? $rightExpr->dispatch($this) - : (is_numeric($rightExpr) ? $rightExpr : $this->conn->quote($rightExpr)); - - return $sql; - } - - /** - * Walks down an InputParameter AST node, thereby generating the appropriate SQL. - */ - public function walkInputParameter(AST\InputParameter $inputParam): string - { - $this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++); - - $parameter = $this->query->getParameter($inputParam->name); - - if ($parameter) { - $type = $parameter->getType(); - if (is_string($type) && Type::hasType($type)) { - return Type::getType($type)->convertToDatabaseValueSQL('?', $this->platform); - } - } - - return '?'; - } - - /** - * Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL. - */ - public function walkArithmeticExpression(AST\ArithmeticExpression $arithmeticExpr): string - { - return $arithmeticExpr->isSimpleArithmeticExpression() - ? $this->walkSimpleArithmeticExpression($arithmeticExpr->simpleArithmeticExpression) - : '(' . $this->walkSubselect($arithmeticExpr->subselect) . ')'; - } - - /** - * Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL. - */ - public function walkSimpleArithmeticExpression(AST\Node|string $simpleArithmeticExpr): string - { - if (! ($simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression)) { - return $this->walkArithmeticTerm($simpleArithmeticExpr); - } - - return implode(' ', array_map($this->walkArithmeticTerm(...), $simpleArithmeticExpr->arithmeticTerms)); - } - - /** - * Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL. - */ - public function walkArithmeticTerm(AST\Node|string $term): string - { - if (is_string($term)) { - return isset($this->queryComponents[$term]) - ? $this->walkResultVariable($this->queryComponents[$term]['token']->value) - : $term; - } - - // Phase 2 AST optimization: Skip processing of ArithmeticTerm - // if only one ArithmeticFactor is defined - if (! ($term instanceof AST\ArithmeticTerm)) { - return $this->walkArithmeticFactor($term); - } - - return implode(' ', array_map($this->walkArithmeticFactor(...), $term->arithmeticFactors)); - } - - /** - * Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL. - */ - public function walkArithmeticFactor(AST\Node|string $factor): string - { - if (is_string($factor)) { - return isset($this->queryComponents[$factor]) - ? $this->walkResultVariable($this->queryComponents[$factor]['token']->value) - : $factor; - } - - // Phase 2 AST optimization: Skip processing of ArithmeticFactor - // if only one ArithmeticPrimary is defined - if (! ($factor instanceof AST\ArithmeticFactor)) { - return $this->walkArithmeticPrimary($factor); - } - - $sign = $factor->isNegativeSigned() ? '-' : ($factor->isPositiveSigned() ? '+' : ''); - - return $sign . $this->walkArithmeticPrimary($factor->arithmeticPrimary); - } - - /** - * Walks down an ArithmeticPrimary that represents an AST node, thereby generating the appropriate SQL. - */ - public function walkArithmeticPrimary(AST\Node|string $primary): string - { - if ($primary instanceof AST\SimpleArithmeticExpression) { - return '(' . $this->walkSimpleArithmeticExpression($primary) . ')'; - } - - if ($primary instanceof AST\Node) { - return $primary->dispatch($this); - } - - return $this->walkEntityIdentificationVariable($primary); - } - - /** - * Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL. - */ - public function walkStringPrimary(AST\Node|string $stringPrimary): string - { - return is_string($stringPrimary) - ? $this->conn->quote($stringPrimary) - : $stringPrimary->dispatch($this); - } - - /** - * Walks down a ResultVariable that represents an AST node, thereby generating the appropriate SQL. - */ - public function walkResultVariable(string $resultVariable): string - { - if (! isset($this->scalarResultAliasMap[$resultVariable])) { - throw new InvalidArgumentException(sprintf('Unknown result variable: %s', $resultVariable)); - } - - $resultAlias = $this->scalarResultAliasMap[$resultVariable]; - - if (is_array($resultAlias)) { - return implode(', ', $resultAlias); - } - - return $resultAlias; - } - - /** - * @return string The list in parentheses of valid child discriminators from the given class - * - * @throws QueryException - */ - private function getChildDiscriminatorsFromClassMetadata( - ClassMetadata $rootClass, - AST\InstanceOfExpression $instanceOfExpr, - ): string { - $sqlParameterList = []; - $discriminators = []; - foreach ($instanceOfExpr->value as $parameter) { - if ($parameter instanceof AST\InputParameter) { - $this->rsm->discriminatorParameters[$parameter->name] = $parameter->name; - $sqlParameterList[] = $this->walkInParameter($parameter); - continue; - } - - $metadata = $this->em->getClassMetadata($parameter); - - if ($metadata->getName() !== $rootClass->name && ! $metadata->getReflectionClass()->isSubclassOf($rootClass->name)) { - throw QueryException::instanceOfUnrelatedClass($parameter, $rootClass->name); - } - - $discriminators += HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($metadata, $this->em); - } - - foreach (array_keys($discriminators) as $discriminatorValue) { - $sqlParameterList[] = $rootClass->getDiscriminatorColumn()->type === 'integer' && is_int($discriminatorValue) - ? $discriminatorValue - : $this->conn->quote((string) $discriminatorValue); - } - - return '(' . implode(', ', $sqlParameterList) . ')'; - } -} diff --git a/vendor/doctrine/orm/src/Query/TokenType.php b/vendor/doctrine/orm/src/Query/TokenType.php deleted file mode 100644 index e745e4a..0000000 --- a/vendor/doctrine/orm/src/Query/TokenType.php +++ /dev/null @@ -1,91 +0,0 @@ -= 100 - case T_FULLY_QUALIFIED_NAME = 101; - case T_IDENTIFIER = 102; - - // All keyword tokens should be >= 200 - case T_ALL = 200; - case T_AND = 201; - case T_ANY = 202; - case T_AS = 203; - case T_ASC = 204; - case T_AVG = 205; - case T_BETWEEN = 206; - case T_BOTH = 207; - case T_BY = 208; - case T_CASE = 209; - case T_COALESCE = 210; - case T_COUNT = 211; - case T_DELETE = 212; - case T_DESC = 213; - case T_DISTINCT = 214; - case T_ELSE = 215; - case T_EMPTY = 216; - case T_END = 217; - case T_ESCAPE = 218; - case T_EXISTS = 219; - case T_FALSE = 220; - case T_FROM = 221; - case T_GROUP = 222; - case T_HAVING = 223; - case T_HIDDEN = 224; - case T_IN = 225; - case T_INDEX = 226; - case T_INNER = 227; - case T_INSTANCE = 228; - case T_IS = 229; - case T_JOIN = 230; - case T_LEADING = 231; - case T_LEFT = 232; - case T_LIKE = 233; - case T_MAX = 234; - case T_MEMBER = 235; - case T_MIN = 236; - case T_NEW = 237; - case T_NOT = 238; - case T_NULL = 239; - case T_NULLIF = 240; - case T_OF = 241; - case T_OR = 242; - case T_ORDER = 243; - case T_OUTER = 244; - case T_SELECT = 246; - case T_SET = 247; - case T_SOME = 248; - case T_SUM = 249; - case T_THEN = 250; - case T_TRAILING = 251; - case T_TRUE = 252; - case T_UPDATE = 253; - case T_WHEN = 254; - case T_WHERE = 255; - case T_WITH = 256; -} diff --git a/vendor/doctrine/orm/src/Query/TreeWalker.php b/vendor/doctrine/orm/src/Query/TreeWalker.php deleted file mode 100644 index 6c21577..0000000 --- a/vendor/doctrine/orm/src/Query/TreeWalker.php +++ /dev/null @@ -1,44 +0,0 @@ - $queryComponents The query components (symbol table). - */ - public function __construct(AbstractQuery $query, ParserResult $parserResult, array $queryComponents); - - /** - * Returns internal queryComponents array. - * - * @psalm-return array - */ - public function getQueryComponents(): array; - - /** - * Walks down a SelectStatement AST node. - */ - public function walkSelectStatement(AST\SelectStatement $selectStatement): void; - - /** - * Walks down an UpdateStatement AST node. - */ - public function walkUpdateStatement(AST\UpdateStatement $updateStatement): void; - - /** - * Walks down a DeleteStatement AST node. - */ - public function walkDeleteStatement(AST\DeleteStatement $deleteStatement): void; -} diff --git a/vendor/doctrine/orm/src/Query/TreeWalkerAdapter.php b/vendor/doctrine/orm/src/Query/TreeWalkerAdapter.php deleted file mode 100644 index a7948db..0000000 --- a/vendor/doctrine/orm/src/Query/TreeWalkerAdapter.php +++ /dev/null @@ -1,90 +0,0 @@ -queryComponents; - } - - public function walkSelectStatement(AST\SelectStatement $selectStatement): void - { - } - - public function walkUpdateStatement(AST\UpdateStatement $updateStatement): void - { - } - - public function walkDeleteStatement(AST\DeleteStatement $deleteStatement): void - { - } - - /** - * Sets or overrides a query component for a given dql alias. - * - * @psalm-param QueryComponent $queryComponent - */ - protected function setQueryComponent(string $dqlAlias, array $queryComponent): void - { - $requiredKeys = ['metadata', 'parent', 'relation', 'map', 'nestingLevel', 'token']; - - if (array_diff($requiredKeys, array_keys($queryComponent))) { - throw QueryException::invalidQueryComponent($dqlAlias); - } - - $this->queryComponents[$dqlAlias] = $queryComponent; - } - - /** - * Retrieves the Query Instance responsible for the current walkers execution. - */ - protected function _getQuery(): AbstractQuery - { - return $this->query; - } - - /** - * Retrieves the ParserResult. - */ - protected function _getParserResult(): ParserResult - { - return $this->parserResult; - } - - protected function getMetadataForDqlAlias(string $dqlAlias): ClassMetadata - { - return $this->queryComponents[$dqlAlias]['metadata'] - ?? throw new LogicException(sprintf('No metadata for DQL alias: %s', $dqlAlias)); - } -} diff --git a/vendor/doctrine/orm/src/Query/TreeWalkerChain.php b/vendor/doctrine/orm/src/Query/TreeWalkerChain.php deleted file mode 100644 index 7bb3051..0000000 --- a/vendor/doctrine/orm/src/Query/TreeWalkerChain.php +++ /dev/null @@ -1,88 +0,0 @@ -> - */ - private array $walkers = []; - - /** - * {@inheritDoc} - */ - public function __construct( - private readonly AbstractQuery $query, - private readonly ParserResult $parserResult, - private array $queryComponents, - ) { - } - - /** - * Returns the internal queryComponents array. - * - * {@inheritDoc} - */ - public function getQueryComponents(): array - { - return $this->queryComponents; - } - - /** - * Adds a tree walker to the chain. - * - * @param string $walkerClass The class of the walker to instantiate. - * @psalm-param class-string $walkerClass - */ - public function addTreeWalker(string $walkerClass): void - { - $this->walkers[] = $walkerClass; - } - - public function walkSelectStatement(AST\SelectStatement $selectStatement): void - { - foreach ($this->getWalkers() as $walker) { - $walker->walkSelectStatement($selectStatement); - - $this->queryComponents = $walker->getQueryComponents(); - } - } - - public function walkUpdateStatement(AST\UpdateStatement $updateStatement): void - { - foreach ($this->getWalkers() as $walker) { - $walker->walkUpdateStatement($updateStatement); - } - } - - public function walkDeleteStatement(AST\DeleteStatement $deleteStatement): void - { - foreach ($this->getWalkers() as $walker) { - $walker->walkDeleteStatement($deleteStatement); - } - } - - /** @psalm-return Generator */ - private function getWalkers(): Generator - { - foreach ($this->walkers as $walkerClass) { - yield new $walkerClass($this->query, $this->parserResult, $this->queryComponents); - } - } -} diff --git a/vendor/doctrine/orm/src/QueryBuilder.php b/vendor/doctrine/orm/src/QueryBuilder.php deleted file mode 100644 index a6a39a9..0000000 --- a/vendor/doctrine/orm/src/QueryBuilder.php +++ /dev/null @@ -1,1375 +0,0 @@ - - */ - private array $dqlParts = [ - 'distinct' => false, - 'select' => [], - 'from' => [], - 'join' => [], - 'set' => [], - 'where' => null, - 'groupBy' => [], - 'having' => null, - 'orderBy' => [], - ]; - - private QueryType $type = QueryType::Select; - - /** - * The complete DQL string for this query. - */ - private string|null $dql = null; - - /** - * The query parameters. - * - * @psalm-var ArrayCollection - */ - private ArrayCollection $parameters; - - /** - * The index of the first result to retrieve. - */ - private int $firstResult = 0; - - /** - * The maximum number of results to retrieve. - */ - private int|null $maxResults = null; - - /** - * Keeps root entity alias names for join entities. - * - * @psalm-var array - */ - private array $joinRootAliases = []; - - /** - * Whether to use second level cache, if available. - */ - protected bool $cacheable = false; - - /** - * Second level cache region name. - */ - protected string|null $cacheRegion = null; - - /** - * Second level query cache mode. - * - * @psalm-var Cache::MODE_*|null - */ - protected int|null $cacheMode = null; - - protected int $lifetime = 0; - - /** - * Initializes a new QueryBuilder that uses the given EntityManager. - * - * @param EntityManagerInterface $em The EntityManager to use. - */ - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->parameters = new ArrayCollection(); - } - - /** - * Gets an ExpressionBuilder used for object-oriented construction of query expressions. - * This producer method is intended for convenient inline usage. Example: - * - * - * $qb = $em->createQueryBuilder(); - * $qb - * ->select('u') - * ->from('User', 'u') - * ->where($qb->expr()->eq('u.id', 1)); - * - * - * For more complex expression construction, consider storing the expression - * builder object in a local variable. - */ - public function expr(): Expr - { - return $this->em->getExpressionBuilder(); - } - - /** - * Enable/disable second level query (result) caching for this query. - * - * @return $this - */ - public function setCacheable(bool $cacheable): static - { - $this->cacheable = $cacheable; - - return $this; - } - - /** - * Are the query results enabled for second level cache? - */ - public function isCacheable(): bool - { - return $this->cacheable; - } - - /** @return $this */ - public function setCacheRegion(string $cacheRegion): static - { - $this->cacheRegion = $cacheRegion; - - return $this; - } - - /** - * Obtain the name of the second level query cache region in which query results will be stored - * - * @return string|null The cache region name; NULL indicates the default region. - */ - public function getCacheRegion(): string|null - { - return $this->cacheRegion; - } - - public function getLifetime(): int - { - return $this->lifetime; - } - - /** - * Sets the life-time for this query into second level cache. - * - * @return $this - */ - public function setLifetime(int $lifetime): static - { - $this->lifetime = $lifetime; - - return $this; - } - - /** @psalm-return Cache::MODE_*|null */ - public function getCacheMode(): int|null - { - return $this->cacheMode; - } - - /** - * @psalm-param Cache::MODE_* $cacheMode - * - * @return $this - */ - public function setCacheMode(int $cacheMode): static - { - $this->cacheMode = $cacheMode; - - return $this; - } - - /** - * Gets the associated EntityManager for this query builder. - */ - public function getEntityManager(): EntityManagerInterface - { - return $this->em; - } - - /** - * Gets the complete DQL string formed by the current specifications of this QueryBuilder. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * echo $qb->getDql(); // SELECT u FROM User u - * - */ - public function getDQL(): string - { - return $this->dql ??= match ($this->type) { - QueryType::Select => $this->getDQLForSelect(), - QueryType::Delete => $this->getDQLForDelete(), - QueryType::Update => $this->getDQLForUpdate(), - }; - } - - /** - * Constructs a Query instance from the current specifications of the builder. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * $q = $qb->getQuery(); - * $results = $q->execute(); - * - */ - public function getQuery(): Query - { - $parameters = clone $this->parameters; - $query = $this->em->createQuery($this->getDQL()) - ->setParameters($parameters) - ->setFirstResult($this->firstResult) - ->setMaxResults($this->maxResults); - - if ($this->lifetime) { - $query->setLifetime($this->lifetime); - } - - if ($this->cacheMode) { - $query->setCacheMode($this->cacheMode); - } - - if ($this->cacheable) { - $query->setCacheable($this->cacheable); - } - - if ($this->cacheRegion) { - $query->setCacheRegion($this->cacheRegion); - } - - return $query; - } - - /** - * Finds the root entity alias of the joined entity. - * - * @param string $alias The alias of the new join entity - * @param string $parentAlias The parent entity alias of the join relationship - */ - private function findRootAlias(string $alias, string $parentAlias): string - { - if (in_array($parentAlias, $this->getRootAliases(), true)) { - $rootAlias = $parentAlias; - } elseif (isset($this->joinRootAliases[$parentAlias])) { - $rootAlias = $this->joinRootAliases[$parentAlias]; - } else { - // Should never happen with correct joining order. Might be - // thoughtful to throw exception instead. - $rootAlias = $this->getRootAlias(); - } - - $this->joinRootAliases[$alias] = $rootAlias; - - return $rootAlias; - } - - /** - * Gets the FIRST root alias of the query. This is the first entity alias involved - * in the construction of the query. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * - * echo $qb->getRootAlias(); // u - * - * - * @deprecated Please use $qb->getRootAliases() instead. - * - * @throws RuntimeException - */ - public function getRootAlias(): string - { - $aliases = $this->getRootAliases(); - - if (! isset($aliases[0])) { - throw new RuntimeException('No alias was set before invoking getRootAlias().'); - } - - return $aliases[0]; - } - - /** - * Gets the root aliases of the query. This is the entity aliases involved - * in the construction of the query. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * - * $qb->getRootAliases(); // array('u') - * - * - * @return string[] - * @psalm-return list - */ - public function getRootAliases(): array - { - $aliases = []; - - foreach ($this->dqlParts['from'] as &$fromClause) { - if (is_string($fromClause)) { - $spacePos = strrpos($fromClause, ' '); - - /** @psalm-var class-string $from */ - $from = substr($fromClause, 0, $spacePos); - $alias = substr($fromClause, $spacePos + 1); - - $fromClause = new Query\Expr\From($from, $alias); - } - - $aliases[] = $fromClause->getAlias(); - } - - return $aliases; - } - - /** - * Gets all the aliases that have been used in the query. - * Including all select root aliases and join aliases - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->join('u.articles','a'); - * - * $qb->getAllAliases(); // array('u','a') - * - * - * @return string[] - * @psalm-return list - */ - public function getAllAliases(): array - { - return [...$this->getRootAliases(), ...array_keys($this->joinRootAliases)]; - } - - /** - * Gets the root entities of the query. This is the entity classes involved - * in the construction of the query. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * - * $qb->getRootEntities(); // array('User') - * - * - * @return string[] - * @psalm-return list - */ - public function getRootEntities(): array - { - $entities = []; - - foreach ($this->dqlParts['from'] as &$fromClause) { - if (is_string($fromClause)) { - $spacePos = strrpos($fromClause, ' '); - - /** @psalm-var class-string $from */ - $from = substr($fromClause, 0, $spacePos); - $alias = substr($fromClause, $spacePos + 1); - - $fromClause = new Query\Expr\From($from, $alias); - } - - $entities[] = $fromClause->getFrom(); - } - - return $entities; - } - - /** - * Sets a query parameter for the query being constructed. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->where('u.id = :user_id') - * ->setParameter('user_id', 1); - * - * - * @param string|int $key The parameter position or name. - * @param ParameterType|ArrayParameterType|string|int|null $type ParameterType::*, ArrayParameterType::* or \Doctrine\DBAL\Types\Type::* constant - * - * @return $this - */ - public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|int|null $type = null): static - { - $existingParameter = $this->getParameter($key); - - if ($existingParameter !== null) { - $existingParameter->setValue($value, $type); - - return $this; - } - - $this->parameters->add(new Parameter($key, $value, $type)); - - return $this; - } - - /** - * Sets a collection of query parameters for the query being constructed. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->where('u.id = :user_id1 OR u.id = :user_id2') - * ->setParameters(new ArrayCollection(array( - * new Parameter('user_id1', 1), - * new Parameter('user_id2', 2) - * ))); - * - * - * @psalm-param ArrayCollection $parameters - * - * @return $this - */ - public function setParameters(ArrayCollection $parameters): static - { - $this->parameters = $parameters; - - return $this; - } - - /** - * Gets all defined query parameters for the query being constructed. - * - * @psalm-return ArrayCollection - */ - public function getParameters(): ArrayCollection - { - return $this->parameters; - } - - /** - * Gets a (previously set) query parameter of the query being constructed. - */ - public function getParameter(string|int $key): Parameter|null - { - $key = Parameter::normalizeName($key); - - $filteredParameters = $this->parameters->filter( - static fn (Parameter $parameter): bool => $key === $parameter->getName() - ); - - return ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null; - } - - /** - * Sets the position of the first result to retrieve (the "offset"). - * - * @return $this - */ - public function setFirstResult(int|null $firstResult): static - { - $this->firstResult = (int) $firstResult; - - return $this; - } - - /** - * Gets the position of the first result the query object was set to retrieve (the "offset"). - */ - public function getFirstResult(): int - { - return $this->firstResult; - } - - /** - * Sets the maximum number of results to retrieve (the "limit"). - * - * @return $this - */ - public function setMaxResults(int|null $maxResults): static - { - $this->maxResults = $maxResults; - - return $this; - } - - /** - * Gets the maximum number of results the query object was set to retrieve (the "limit"). - * Returns NULL if {@link setMaxResults} was not applied to this query builder. - */ - public function getMaxResults(): int|null - { - return $this->maxResults; - } - - /** - * Either appends to or replaces a single, generic query part. - * - * The available parts are: 'select', 'from', 'join', 'set', 'where', - * 'groupBy', 'having' and 'orderBy'. - * - * @psalm-param string|object|list|array{join: array} $dqlPart - * - * @return $this - */ - public function add(string $dqlPartName, string|object|array $dqlPart, bool $append = false): static - { - if ($append && ($dqlPartName === 'where' || $dqlPartName === 'having')) { - throw new InvalidArgumentException( - "Using \$append = true does not have an effect with 'where' or 'having' " . - 'parts. See QueryBuilder#andWhere() for an example for correct usage.', - ); - } - - $isMultiple = is_array($this->dqlParts[$dqlPartName]) - && ! ($dqlPartName === 'join' && ! $append); - - // Allow adding any part retrieved from self::getDQLParts(). - if (is_array($dqlPart) && $dqlPartName !== 'join') { - $dqlPart = reset($dqlPart); - } - - // This is introduced for backwards compatibility reasons. - // TODO: Remove for 3.0 - if ($dqlPartName === 'join') { - $newDqlPart = []; - - foreach ($dqlPart as $k => $v) { - $k = is_numeric($k) ? $this->getRootAlias() : $k; - - $newDqlPart[$k] = $v; - } - - $dqlPart = $newDqlPart; - } - - if ($append && $isMultiple) { - if (is_array($dqlPart)) { - $key = key($dqlPart); - - $this->dqlParts[$dqlPartName][$key][] = $dqlPart[$key]; - } else { - $this->dqlParts[$dqlPartName][] = $dqlPart; - } - } else { - $this->dqlParts[$dqlPartName] = $isMultiple ? [$dqlPart] : $dqlPart; - } - - $this->dql = null; - - return $this; - } - - /** - * Specifies an item that is to be returned in the query result. - * Replaces any previously specified selections, if any. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u', 'p') - * ->from('User', 'u') - * ->leftJoin('u.Phonenumbers', 'p'); - * - * - * @return $this - */ - public function select(mixed ...$select): static - { - self::validateVariadicParameter($select); - - $this->type = QueryType::Select; - - if ($select === []) { - return $this; - } - - return $this->add('select', new Expr\Select($select), false); - } - - /** - * Adds a DISTINCT flag to this query. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->distinct() - * ->from('User', 'u'); - * - * - * @return $this - */ - public function distinct(bool $flag = true): static - { - if ($this->dqlParts['distinct'] !== $flag) { - $this->dqlParts['distinct'] = $flag; - $this->dql = null; - } - - return $this; - } - - /** - * Adds an item that is to be returned in the query result. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->addSelect('p') - * ->from('User', 'u') - * ->leftJoin('u.Phonenumbers', 'p'); - * - * - * @return $this - */ - public function addSelect(mixed ...$select): static - { - self::validateVariadicParameter($select); - - $this->type = QueryType::Select; - - if ($select === []) { - return $this; - } - - return $this->add('select', new Expr\Select($select), true); - } - - /** - * Turns the query being built into a bulk delete query that ranges over - * a certain entity type. - * - * - * $qb = $em->createQueryBuilder() - * ->delete('User', 'u') - * ->where('u.id = :user_id') - * ->setParameter('user_id', 1); - * - * - * @param class-string|null $delete The class/type whose instances are subject to the deletion. - * @param string|null $alias The class/type alias used in the constructed query. - * - * @return $this - */ - public function delete(string|null $delete = null, string|null $alias = null): static - { - $this->type = QueryType::Delete; - - if (! $delete) { - return $this; - } - - if (! $alias) { - throw new InvalidArgumentException(sprintf( - '%s(): The alias for entity %s must not be omitted.', - __METHOD__, - $delete, - )); - } - - return $this->add('from', new Expr\From($delete, $alias)); - } - - /** - * Turns the query being built into a bulk update query that ranges over - * a certain entity type. - * - * - * $qb = $em->createQueryBuilder() - * ->update('User', 'u') - * ->set('u.password', '?1') - * ->where('u.id = ?2'); - * - * - * @param class-string|null $update The class/type whose instances are subject to the update. - * @param string|null $alias The class/type alias used in the constructed query. - * - * @return $this - */ - public function update(string|null $update = null, string|null $alias = null): static - { - $this->type = QueryType::Update; - - if (! $update) { - return $this; - } - - if (! $alias) { - throw new InvalidArgumentException(sprintf( - '%s(): The alias for entity %s must not be omitted.', - __METHOD__, - $update, - )); - } - - return $this->add('from', new Expr\From($update, $alias)); - } - - /** - * Creates and adds a query root corresponding to the entity identified by the given alias, - * forming a cartesian product with any existing query roots. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u'); - * - * - * @param class-string $from The class name. - * @param string $alias The alias of the class. - * @param string|null $indexBy The index for the from. - * - * @return $this - */ - public function from(string $from, string $alias, string|null $indexBy = null): static - { - return $this->add('from', new Expr\From($from, $alias, $indexBy), true); - } - - /** - * Updates a query root corresponding to an entity setting its index by. This method is intended to be used with - * EntityRepository->createQueryBuilder(), which creates the initial FROM clause and do not allow you to update it - * setting an index by. - * - * - * $qb = $userRepository->createQueryBuilder('u') - * ->indexBy('u', 'u.id'); - * - * // Is equivalent to... - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u', 'u.id'); - * - * - * @return $this - * - * @throws Query\QueryException - */ - public function indexBy(string $alias, string $indexBy): static - { - $rootAliases = $this->getRootAliases(); - - if (! in_array($alias, $rootAliases, true)) { - throw new Query\QueryException( - sprintf('Specified root alias %s must be set before invoking indexBy().', $alias), - ); - } - - foreach ($this->dqlParts['from'] as &$fromClause) { - assert($fromClause instanceof Expr\From); - if ($fromClause->getAlias() !== $alias) { - continue; - } - - $fromClause = new Expr\From($fromClause->getFrom(), $fromClause->getAlias(), $indexBy); - } - - return $this; - } - - /** - * Creates and adds a join over an entity association to the query. - * - * The entities in the joined association will be fetched as part of the query - * result if the alias used for the joined association is placed in the select - * expressions. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); - * - * - * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType - * - * @return $this - */ - public function join( - string $join, - string $alias, - string|null $conditionType = null, - string|Expr\Composite|Expr\Comparison|Expr\Func|null $condition = null, - string|null $indexBy = null, - ): static { - return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy); - } - - /** - * Creates and adds a join over an entity association to the query. - * - * The entities in the joined association will be fetched as part of the query - * result if the alias used for the joined association is placed in the select - * expressions. - * - * [php] - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); - * - * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType - * - * @return $this - */ - public function innerJoin( - string $join, - string $alias, - string|null $conditionType = null, - string|Expr\Composite|Expr\Comparison|Expr\Func|null $condition = null, - string|null $indexBy = null, - ): static { - $parentAlias = substr($join, 0, (int) strpos($join, '.')); - - $rootAlias = $this->findRootAlias($alias, $parentAlias); - - $join = new Expr\Join( - Expr\Join::INNER_JOIN, - $join, - $alias, - $conditionType, - $condition, - $indexBy, - ); - - return $this->add('join', [$rootAlias => $join], true); - } - - /** - * Creates and adds a left join over an entity association to the query. - * - * The entities in the joined association will be fetched as part of the query - * result if the alias used for the joined association is placed in the select - * expressions. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); - * - * - * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType - * - * @return $this - */ - public function leftJoin( - string $join, - string $alias, - string|null $conditionType = null, - string|Expr\Composite|Expr\Comparison|Expr\Func|null $condition = null, - string|null $indexBy = null, - ): static { - $parentAlias = substr($join, 0, (int) strpos($join, '.')); - - $rootAlias = $this->findRootAlias($alias, $parentAlias); - - $join = new Expr\Join( - Expr\Join::LEFT_JOIN, - $join, - $alias, - $conditionType, - $condition, - $indexBy, - ); - - return $this->add('join', [$rootAlias => $join], true); - } - - /** - * Sets a new value for a field in a bulk update query. - * - * - * $qb = $em->createQueryBuilder() - * ->update('User', 'u') - * ->set('u.password', '?1') - * ->where('u.id = ?2'); - * - * - * @return $this - */ - public function set(string $key, mixed $value): static - { - return $this->add('set', new Expr\Comparison($key, Expr\Comparison::EQ, $value), true); - } - - /** - * Specifies one or more restrictions to the query result. - * Replaces any previously specified restrictions, if any. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->where('u.id = ?'); - * - * // You can optionally programmatically build and/or expressions - * $qb = $em->createQueryBuilder(); - * - * $or = $qb->expr()->orX(); - * $or->add($qb->expr()->eq('u.id', 1)); - * $or->add($qb->expr()->eq('u.id', 2)); - * - * $qb->update('User', 'u') - * ->set('u.password', '?') - * ->where($or); - * - * - * @return $this - */ - public function where(mixed ...$predicates): static - { - self::validateVariadicParameter($predicates); - - if (! (count($predicates) === 1 && $predicates[0] instanceof Expr\Composite)) { - $predicates = new Expr\Andx($predicates); - } - - return $this->add('where', $predicates); - } - - /** - * Adds one or more restrictions to the query results, forming a logical - * conjunction with any previously specified restrictions. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->where('u.username LIKE ?') - * ->andWhere('u.is_active = 1'); - * - * - * @see where() - * - * @return $this - */ - public function andWhere(mixed ...$where): static - { - self::validateVariadicParameter($where); - - $dql = $this->getDQLPart('where'); - - if ($dql instanceof Expr\Andx) { - $dql->addMultiple($where); - } else { - array_unshift($where, $dql); - $dql = new Expr\Andx($where); - } - - return $this->add('where', $dql); - } - - /** - * Adds one or more restrictions to the query results, forming a logical - * disjunction with any previously specified restrictions. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->where('u.id = 1') - * ->orWhere('u.id = 2'); - * - * - * @see where() - * - * @return $this - */ - public function orWhere(mixed ...$where): static - { - self::validateVariadicParameter($where); - - $dql = $this->getDQLPart('where'); - - if ($dql instanceof Expr\Orx) { - $dql->addMultiple($where); - } else { - array_unshift($where, $dql); - $dql = new Expr\Orx($where); - } - - return $this->add('where', $dql); - } - - /** - * Specifies a grouping over the results of the query. - * Replaces any previously specified groupings, if any. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->groupBy('u.id'); - * - * - * @return $this - */ - public function groupBy(string ...$groupBy): static - { - self::validateVariadicParameter($groupBy); - - return $this->add('groupBy', new Expr\GroupBy($groupBy)); - } - - /** - * Adds a grouping expression to the query. - * - * - * $qb = $em->createQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * ->groupBy('u.lastLogin') - * ->addGroupBy('u.createdAt'); - * - * - * @return $this - */ - public function addGroupBy(string ...$groupBy): static - { - self::validateVariadicParameter($groupBy); - - return $this->add('groupBy', new Expr\GroupBy($groupBy), true); - } - - /** - * Specifies a restriction over the groups of the query. - * Replaces any previous having restrictions, if any. - * - * @return $this - */ - public function having(mixed ...$having): static - { - self::validateVariadicParameter($having); - - if (! (count($having) === 1 && ($having[0] instanceof Expr\Andx || $having[0] instanceof Expr\Orx))) { - $having = new Expr\Andx($having); - } - - return $this->add('having', $having); - } - - /** - * Adds a restriction over the groups of the query, forming a logical - * conjunction with any existing having restrictions. - * - * @return $this - */ - public function andHaving(mixed ...$having): static - { - self::validateVariadicParameter($having); - - $dql = $this->getDQLPart('having'); - - if ($dql instanceof Expr\Andx) { - $dql->addMultiple($having); - } else { - array_unshift($having, $dql); - $dql = new Expr\Andx($having); - } - - return $this->add('having', $dql); - } - - /** - * Adds a restriction over the groups of the query, forming a logical - * disjunction with any existing having restrictions. - * - * @return $this - */ - public function orHaving(mixed ...$having): static - { - self::validateVariadicParameter($having); - - $dql = $this->getDQLPart('having'); - - if ($dql instanceof Expr\Orx) { - $dql->addMultiple($having); - } else { - array_unshift($having, $dql); - $dql = new Expr\Orx($having); - } - - return $this->add('having', $dql); - } - - /** - * Specifies an ordering for the query results. - * Replaces any previously specified orderings, if any. - * - * @return $this - */ - public function orderBy(string|Expr\OrderBy $sort, string|null $order = null): static - { - $orderBy = $sort instanceof Expr\OrderBy ? $sort : new Expr\OrderBy($sort, $order); - - return $this->add('orderBy', $orderBy); - } - - /** - * Adds an ordering to the query results. - * - * @return $this - */ - public function addOrderBy(string|Expr\OrderBy $sort, string|null $order = null): static - { - $orderBy = $sort instanceof Expr\OrderBy ? $sort : new Expr\OrderBy($sort, $order); - - return $this->add('orderBy', $orderBy, true); - } - - /** - * Adds criteria to the query. - * - * Adds where expressions with AND operator. - * Adds orderings. - * Overrides firstResult and maxResults if they're set. - * - * @return $this - * - * @throws Query\QueryException - */ - public function addCriteria(Criteria $criteria): static - { - $allAliases = $this->getAllAliases(); - if (! isset($allAliases[0])) { - throw new Query\QueryException('No aliases are set before invoking addCriteria().'); - } - - $visitor = new QueryExpressionVisitor($this->getAllAliases()); - - $whereExpression = $criteria->getWhereExpression(); - if ($whereExpression) { - $this->andWhere($visitor->dispatch($whereExpression)); - foreach ($visitor->getParameters() as $parameter) { - $this->parameters->add($parameter); - } - } - - foreach ($criteria->orderings() as $sort => $order) { - $hasValidAlias = false; - foreach ($allAliases as $alias) { - if (str_starts_with($sort . '.', $alias . '.')) { - $hasValidAlias = true; - break; - } - } - - if (! $hasValidAlias) { - $sort = $allAliases[0] . '.' . $sort; - } - - $this->addOrderBy($sort, $order->value); - } - - // Overwrite limits only if they was set in criteria - $firstResult = $criteria->getFirstResult(); - if ($firstResult > 0) { - $this->setFirstResult($firstResult); - } - - $maxResults = $criteria->getMaxResults(); - if ($maxResults !== null) { - $this->setMaxResults($maxResults); - } - - return $this; - } - - /** - * Gets a query part by its name. - */ - public function getDQLPart(string $queryPartName): mixed - { - return $this->dqlParts[$queryPartName]; - } - - /** - * Gets all query parts. - * - * @psalm-return array $dqlParts - */ - public function getDQLParts(): array - { - return $this->dqlParts; - } - - private function getDQLForDelete(): string - { - return 'DELETE' - . $this->getReducedDQLQueryPart('from', ['pre' => ' ', 'separator' => ', ']) - . $this->getReducedDQLQueryPart('where', ['pre' => ' WHERE ']) - . $this->getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ', 'separator' => ', ']); - } - - private function getDQLForUpdate(): string - { - return 'UPDATE' - . $this->getReducedDQLQueryPart('from', ['pre' => ' ', 'separator' => ', ']) - . $this->getReducedDQLQueryPart('set', ['pre' => ' SET ', 'separator' => ', ']) - . $this->getReducedDQLQueryPart('where', ['pre' => ' WHERE ']) - . $this->getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ', 'separator' => ', ']); - } - - private function getDQLForSelect(): string - { - $dql = 'SELECT' - . ($this->dqlParts['distinct'] === true ? ' DISTINCT' : '') - . $this->getReducedDQLQueryPart('select', ['pre' => ' ', 'separator' => ', ']); - - $fromParts = $this->getDQLPart('from'); - $joinParts = $this->getDQLPart('join'); - $fromClauses = []; - - // Loop through all FROM clauses - if (! empty($fromParts)) { - $dql .= ' FROM '; - - foreach ($fromParts as $from) { - $fromClause = (string) $from; - - if ($from instanceof Expr\From && isset($joinParts[$from->getAlias()])) { - foreach ($joinParts[$from->getAlias()] as $join) { - $fromClause .= ' ' . ((string) $join); - } - } - - $fromClauses[] = $fromClause; - } - } - - $dql .= implode(', ', $fromClauses) - . $this->getReducedDQLQueryPart('where', ['pre' => ' WHERE ']) - . $this->getReducedDQLQueryPart('groupBy', ['pre' => ' GROUP BY ', 'separator' => ', ']) - . $this->getReducedDQLQueryPart('having', ['pre' => ' HAVING ']) - . $this->getReducedDQLQueryPart('orderBy', ['pre' => ' ORDER BY ', 'separator' => ', ']); - - return $dql; - } - - /** @psalm-param array $options */ - private function getReducedDQLQueryPart(string $queryPartName, array $options = []): string - { - $queryPart = $this->getDQLPart($queryPartName); - - if (empty($queryPart)) { - return $options['empty'] ?? ''; - } - - return ($options['pre'] ?? '') - . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart) - . ($options['post'] ?? ''); - } - - /** - * Resets DQL parts. - * - * @param string[]|null $parts - * @psalm-param list|null $parts - * - * @return $this - */ - public function resetDQLParts(array|null $parts = null): static - { - if ($parts === null) { - $parts = array_keys($this->dqlParts); - } - - foreach ($parts as $part) { - $this->resetDQLPart($part); - } - - return $this; - } - - /** - * Resets single DQL part. - * - * @return $this - */ - public function resetDQLPart(string $part): static - { - $this->dqlParts[$part] = is_array($this->dqlParts[$part]) ? [] : null; - $this->dql = null; - - return $this; - } - - /** - * Gets a string representation of this QueryBuilder which corresponds to - * the final DQL query being constructed. - */ - public function __toString(): string - { - return $this->getDQL(); - } - - /** - * Deep clones all expression objects in the DQL parts. - * - * @return void - */ - public function __clone() - { - foreach ($this->dqlParts as $part => $elements) { - if (is_array($this->dqlParts[$part])) { - foreach ($this->dqlParts[$part] as $idx => $element) { - if (is_object($element)) { - $this->dqlParts[$part][$idx] = clone $element; - } - } - } elseif (is_object($elements)) { - $this->dqlParts[$part] = clone $elements; - } - } - - $parameters = []; - - foreach ($this->parameters as $parameter) { - $parameters[] = clone $parameter; - } - - $this->parameters = new ArrayCollection($parameters); - } -} diff --git a/vendor/doctrine/orm/src/Repository/DefaultRepositoryFactory.php b/vendor/doctrine/orm/src/Repository/DefaultRepositoryFactory.php deleted file mode 100644 index 5c408fb..0000000 --- a/vendor/doctrine/orm/src/Repository/DefaultRepositoryFactory.php +++ /dev/null @@ -1,49 +0,0 @@ - - */ - private array $repositoryList = []; - - public function getRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepository - { - $repositoryHash = $entityManager->getClassMetadata($entityName)->getName() . spl_object_id($entityManager); - - return $this->repositoryList[$repositoryHash] ??= $this->createRepository($entityManager, $entityName); - } - - /** - * Create a new repository instance for an entity class. - * - * @param EntityManagerInterface $entityManager The EntityManager instance. - * @param string $entityName The name of the entity. - */ - private function createRepository( - EntityManagerInterface $entityManager, - string $entityName, - ): EntityRepository { - $metadata = $entityManager->getClassMetadata($entityName); - $repositoryClassName = $metadata->customRepositoryClassName - ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName(); - - return new $repositoryClassName($entityManager, $metadata); - } -} diff --git a/vendor/doctrine/orm/src/Repository/Exception/InvalidFindByCall.php b/vendor/doctrine/orm/src/Repository/Exception/InvalidFindByCall.php deleted file mode 100644 index c5dd015..0000000 --- a/vendor/doctrine/orm/src/Repository/Exception/InvalidFindByCall.php +++ /dev/null @@ -1,21 +0,0 @@ - $entityName The name of the entity. - * - * @return EntityRepository - * - * @template T of object - */ - public function getRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepository; -} diff --git a/vendor/doctrine/orm/src/Tools/AttachEntityListenersListener.php b/vendor/doctrine/orm/src/Tools/AttachEntityListenersListener.php deleted file mode 100644 index 9203cfe..0000000 --- a/vendor/doctrine/orm/src/Tools/AttachEntityListenersListener.php +++ /dev/null @@ -1,69 +0,0 @@ -> - */ - private array $entityListeners = []; - - /** - * Adds an entity listener for a specific entity. - * - * @param class-string $entityClass The entity to attach the listener. - * @param class-string $listenerClass The listener class. - * @param Events::*|null $eventName The entity lifecycle event. - * @param non-falsy-string|null $listenerCallback The listener callback method or NULL to use $eventName. - */ - public function addEntityListener( - string $entityClass, - string $listenerClass, - string|null $eventName = null, - string|null $listenerCallback = null, - ): void { - $this->entityListeners[ltrim($entityClass, '\\')][] = [ - 'event' => $eventName, - 'class' => $listenerClass, - 'method' => $listenerCallback ?? $eventName, - ]; - } - - /** - * Processes event and attach the entity listener. - */ - public function loadClassMetadata(LoadClassMetadataEventArgs $event): void - { - $metadata = $event->getClassMetadata(); - - if (! isset($this->entityListeners[$metadata->name])) { - return; - } - - foreach ($this->entityListeners[$metadata->name] as $listener) { - if ($listener['event'] === null) { - EntityListenerBuilder::bindEntityListener($metadata, $listener['class']); - } else { - assert($listener['method'] !== null); - $metadata->addEntityListener($listener['event'], $listener['class'], $listener['method']); - } - } - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/AbstractEntityManagerCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/AbstractEntityManagerCommand.php deleted file mode 100644 index 370f4fb..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/AbstractEntityManagerCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -getOption('em') === null - ? $this->entityManagerProvider->getDefaultManager() - : $this->entityManagerProvider->getManager($input->getOption('em')); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/CollectionRegionCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/CollectionRegionCommand.php deleted file mode 100644 index b4c6efa..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/CollectionRegionCommand.php +++ /dev/null @@ -1,119 +0,0 @@ -setName('orm:clear-cache:region:collection') - ->setDescription('Clear a second-level cache collection region') - ->addArgument('owner-class', InputArgument::OPTIONAL, 'The owner entity name.') - ->addArgument('association', InputArgument::OPTIONAL, 'The association collection name.') - ->addArgument('owner-id', InputArgument::OPTIONAL, 'The owner identifier.') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all entity regions will be deleted/invalidated.') - ->addOption('flush', null, InputOption::VALUE_NONE, 'If defined, all cache entries will be flushed.') - ->setHelp(<<<'EOT' -The %command.name% command is meant to clear a second-level cache collection regions for an associated Entity Manager. -It is possible to delete/invalidate all collection region, a specific collection region or flushes the cache provider. - -The execution type differ on how you execute the command. -If you want to invalidate all entries for an collection region this command would do the work: - -%command.name% 'Entities\MyEntity' 'collectionName' - -To invalidate a specific entry you should use : - -%command.name% 'Entities\MyEntity' 'collectionName' 1 - -If you want to invalidate all entries for the all collection regions: - -%command.name% --all - -Alternatively, if you want to flush the configured cache provider for an collection region use this command: - -%command.name% 'Entities\MyEntity' 'collectionName' --flush - -Finally, be aware that if --flush option is passed, -not all cache providers are able to flush entries, because of a limitation of its execution nature. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $ownerClass = $input->getArgument('owner-class'); - $assoc = $input->getArgument('association'); - $ownerId = $input->getArgument('owner-id'); - $cache = $em->getCache(); - - if (! $cache instanceof Cache) { - throw new InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); - } - - if (( ! $ownerClass || ! $assoc) && ! $input->getOption('all')) { - throw new InvalidArgumentException('Missing arguments "--owner-class" "--association"'); - } - - if ($input->getOption('flush')) { - $cache->getCollectionCacheRegion($ownerClass, $assoc) - ->evictAll(); - - $ui->comment( - sprintf( - 'Flushing cache provider configured for "%s#%s"', - $ownerClass, - $assoc, - ), - ); - - return 0; - } - - if ($input->getOption('all')) { - $ui->comment('Clearing all second-level cache collection regions'); - - $cache->evictEntityRegions(); - - return 0; - } - - if ($ownerId) { - $ui->comment( - sprintf( - 'Clearing second-level cache entry for collection "%s#%s" owner entity identified by "%s"', - $ownerClass, - $assoc, - $ownerId, - ), - ); - $cache->evictCollection($ownerClass, $assoc, $ownerId); - - return 0; - } - - $ui->comment(sprintf('Clearing second-level cache for collection "%s#%s"', $ownerClass, $assoc)); - $cache->evictCollectionRegion($ownerClass, $assoc); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/EntityRegionCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/EntityRegionCommand.php deleted file mode 100644 index c5f2d65..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/EntityRegionCommand.php +++ /dev/null @@ -1,110 +0,0 @@ -setName('orm:clear-cache:region:entity') - ->setDescription('Clear a second-level cache entity region') - ->addArgument('entity-class', InputArgument::OPTIONAL, 'The entity name.') - ->addArgument('entity-id', InputArgument::OPTIONAL, 'The entity identifier.') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all entity regions will be deleted/invalidated.') - ->addOption('flush', null, InputOption::VALUE_NONE, 'If defined, all cache entries will be flushed.') - ->setHelp(<<<'EOT' -The %command.name% command is meant to clear a second-level cache entity region for an associated Entity Manager. -It is possible to delete/invalidate all entity region, a specific entity region or flushes the cache provider. - -The execution type differ on how you execute the command. -If you want to invalidate all entries for an entity region this command would do the work: - -%command.name% 'Entities\MyEntity' - -To invalidate a specific entry you should use : - -%command.name% 'Entities\MyEntity' 1 - -If you want to invalidate all entries for the all entity regions: - -%command.name% --all - -Alternatively, if you want to flush the configured cache provider for an entity region use this command: - -%command.name% 'Entities\MyEntity' --flush - -Finally, be aware that if --flush option is passed, -not all cache providers are able to flush entries, because of a limitation of its execution nature. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $entityClass = $input->getArgument('entity-class'); - $entityId = $input->getArgument('entity-id'); - $cache = $em->getCache(); - - if (! $cache instanceof Cache) { - throw new InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); - } - - if (! $entityClass && ! $input->getOption('all')) { - throw new InvalidArgumentException('Invalid argument "--entity-class"'); - } - - if ($input->getOption('flush')) { - $cache->getEntityCacheRegion($entityClass) - ->evictAll(); - - $ui->comment(sprintf('Flushing cache provider configured for entity named "%s"', $entityClass)); - - return 0; - } - - if ($input->getOption('all')) { - $ui->comment('Clearing all second-level cache entity regions'); - - $cache->evictEntityRegions(); - - return 0; - } - - if ($entityId) { - $ui->comment( - sprintf( - 'Clearing second-level cache entry for entity "%s" identified by "%s"', - $entityClass, - $entityId, - ), - ); - $cache->evictEntity($entityClass, $entityId); - - return 0; - } - - $ui->comment(sprintf('Clearing second-level cache for entity "%s"', $entityClass)); - $cache->evictEntityRegion($entityClass); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/MetadataCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/MetadataCommand.php deleted file mode 100644 index 147795b..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/MetadataCommand.php +++ /dev/null @@ -1,52 +0,0 @@ -setName('orm:clear-cache:metadata') - ->setDescription('Clear all metadata cache of the various cache drivers') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('flush', null, InputOption::VALUE_NONE, 'If defined, cache entries will be flushed instead of deleted/invalidated.') - ->setHelp(<<<'EOT' -The %command.name% command is meant to clear the metadata cache of associated Entity Manager. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $cacheDriver = $em->getConfiguration()->getMetadataCache(); - - if (! $cacheDriver) { - throw new InvalidArgumentException('No Metadata cache driver is configured on given EntityManager.'); - } - - $ui->comment('Clearing all Metadata cache entries'); - - $result = $cacheDriver->clear(); - $message = $result ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - - $ui->success($message); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryCommand.php deleted file mode 100644 index 83edd7a..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryCommand.php +++ /dev/null @@ -1,54 +0,0 @@ -setName('orm:clear-cache:query') - ->setDescription('Clear all query cache of the various cache drivers') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->setHelp('The %command.name% command is meant to clear the query cache of associated Entity Manager.'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $cache = $em->getConfiguration()->getQueryCache(); - - if (! $cache) { - throw new InvalidArgumentException('No Query cache driver is configured on given EntityManager.'); - } - - if ($cache instanceof ApcuAdapter) { - throw new LogicException('Cannot clear APCu Cache from Console, it\'s shared in the Webserver memory and not accessible from the CLI.'); - } - - $ui->comment('Clearing all Query cache entries'); - - $message = $cache->clear() ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - - $ui->success($message); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryRegionCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryRegionCommand.php deleted file mode 100644 index e80fb90..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/QueryRegionCommand.php +++ /dev/null @@ -1,101 +0,0 @@ -setName('orm:clear-cache:region:query') - ->setDescription('Clear a second-level cache query region') - ->addArgument('region-name', InputArgument::OPTIONAL, 'The query region to clear.') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all query regions will be deleted/invalidated.') - ->addOption('flush', null, InputOption::VALUE_NONE, 'If defined, all cache entries will be flushed.') - ->setHelp(<<<'EOT' -The %command.name% command is meant to clear a second-level cache query region for an associated Entity Manager. -It is possible to delete/invalidate all query region, a specific query region or flushes the cache provider. - -The execution type differ on how you execute the command. -If you want to invalidate all entries for the default query region this command would do the work: - -%command.name% - -To invalidate entries for a specific query region you should use : - -%command.name% my_region_name - -If you want to invalidate all entries for the all query region: - -%command.name% --all - -Alternatively, if you want to flush the configured cache provider use this command: - -%command.name% my_region_name --flush - -Finally, be aware that if --flush option is passed, -not all cache providers are able to flush entries, because of a limitation of its execution nature. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $name = $input->getArgument('region-name'); - $cache = $em->getCache(); - - if ($name === null) { - $name = Cache::DEFAULT_QUERY_REGION_NAME; - } - - if (! $cache instanceof Cache) { - throw new InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); - } - - if ($input->getOption('flush')) { - $cache->getQueryCache($name) - ->getRegion() - ->evictAll(); - - $ui->comment( - sprintf( - 'Flushing cache provider configured for second-level cache query region named "%s"', - $name, - ), - ); - - return 0; - } - - if ($input->getOption('all')) { - $ui->comment('Clearing all second-level cache query regions'); - - $cache->evictQueryRegions(); - - return 0; - } - - $ui->comment(sprintf('Clearing second-level cache query region named "%s"', $name)); - $cache->evictQueryRegion($name); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/ResultCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/ResultCommand.php deleted file mode 100644 index 4f84e0b..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ClearCache/ResultCommand.php +++ /dev/null @@ -1,65 +0,0 @@ -setName('orm:clear-cache:result') - ->setDescription('Clear all result cache of the various cache drivers') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('flush', null, InputOption::VALUE_NONE, 'If defined, cache entries will be flushed instead of deleted/invalidated.') - ->setHelp(<<<'EOT' -The %command.name% command is meant to clear the result cache of associated Entity Manager. -It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider -instance completely. - -The execution type differ on how you execute the command. -If you want to invalidate the entries (and not delete from cache instance), this command would do the work: - -%command.name% - -Alternatively, if you want to flush the cache provider using this command: - -%command.name% --flush - -Finally, be aware that if --flush option is passed, not all cache providers are able to flush entries, -because of a limitation of its execution nature. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $cache = $em->getConfiguration()->getResultCache(); - - if (! $cache) { - throw new InvalidArgumentException('No Result cache driver is configured on given EntityManager.'); - } - - $ui->comment('Clearing all Result cache entries'); - - $message = $cache->clear() ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - - $ui->success($message); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/GenerateProxiesCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/GenerateProxiesCommand.php deleted file mode 100644 index 5a407de..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/GenerateProxiesCommand.php +++ /dev/null @@ -1,96 +0,0 @@ -setName('orm:generate-proxies') - ->setAliases(['orm:generate:proxies']) - ->setDescription('Generates proxy classes for entity classes') - ->addArgument('dest-path', InputArgument::OPTIONAL, 'The path to generate your proxy classes. If none is provided, it will attempt to grab from configuration.') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'A string pattern used to match entities that should be processed.') - ->setHelp('Generates proxy classes for entity classes.'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - - $metadatas = $em->getMetadataFactory()->getAllMetadata(); - $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); - - // Process destination directory - $destPath = $input->getArgument('dest-path'); - if ($destPath === null) { - $destPath = $em->getConfiguration()->getProxyDir(); - - if ($destPath === null) { - throw new InvalidArgumentException('Proxy directory cannot be null'); - } - } - - if (! is_dir($destPath)) { - mkdir($destPath, 0775, true); - } - - $destPath = realpath($destPath); - - if (! file_exists($destPath)) { - throw new InvalidArgumentException( - sprintf("Proxies destination directory '%s' does not exist.", $em->getConfiguration()->getProxyDir()), - ); - } - - if (! is_writable($destPath)) { - throw new InvalidArgumentException( - sprintf("Proxies destination directory '%s' does not have write permissions.", $destPath), - ); - } - - if (empty($metadatas)) { - $ui->success('No Metadata Classes to process.'); - - return 0; - } - - foreach ($metadatas as $metadata) { - $ui->text(sprintf('Processing entity "%s"', $metadata->name)); - } - - // Generating Proxies - $em->getProxyFactory()->generateProxyClasses($metadatas, $destPath); - - // Outputting information message - $ui->newLine(); - $ui->text(sprintf('Proxy classes generated to "%s"', $destPath)); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/InfoCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/InfoCommand.php deleted file mode 100644 index deebb58..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/InfoCommand.php +++ /dev/null @@ -1,80 +0,0 @@ -setName('orm:info') - ->setDescription('Show basic information about all mapped entities') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->setHelp(<<<'EOT' -The %command.name% shows basic information about which -entities exist and possibly if their mapping information contains errors or -not. -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $entityManager = $this->getEntityManager($input); - - $entityClassNames = $entityManager->getConfiguration() - ->getMetadataDriverImpl() - ->getAllClassNames(); - - if (! $entityClassNames) { - $ui->caution( - [ - 'You do not have any mapped Doctrine ORM entities according to the current configuration.', - 'If you have entities or mapping files you should check your mapping configuration for errors.', - ], - ); - - return 1; - } - - $ui->text(sprintf('Found %d mapped entities:', count($entityClassNames))); - $ui->newLine(); - - $failure = false; - - foreach ($entityClassNames as $entityClassName) { - try { - $entityManager->getClassMetadata($entityClassName); - $ui->text(sprintf('[OK] %s', $entityClassName)); - } catch (MappingException $e) { - $ui->text( - [ - sprintf('[FAIL] %s', $entityClassName), - sprintf('%s', $e->getMessage()), - '', - ], - ); - - $failure = true; - } - } - - return $failure ? 1 : 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/MappingDescribeCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/MappingDescribeCommand.php deleted file mode 100644 index 41a177d..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/MappingDescribeCommand.php +++ /dev/null @@ -1,279 +0,0 @@ -setName('orm:mapping:describe') - ->addArgument('entityName', InputArgument::REQUIRED, 'Full or partial name of entity') - ->setDescription('Display information about mapped objects') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->setHelp(<<<'EOT' -The %command.full_name% command describes the metadata for the given full or partial entity class name. - - %command.full_name% My\Namespace\Entity\MyEntity - -Or: - - %command.full_name% MyEntity -EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $entityManager = $this->getEntityManager($input); - - $this->displayEntity($input->getArgument('entityName'), $entityManager, $ui); - - return 0; - } - - /** - * Display all the mapping information for a single Entity. - * - * @param string $entityName Full or partial entity class name - */ - private function displayEntity( - string $entityName, - EntityManagerInterface $entityManager, - SymfonyStyle $ui, - ): void { - $metadata = $this->getClassMetadata($entityName, $entityManager); - - $ui->table( - ['Field', 'Value'], - array_merge( - [ - $this->formatField('Name', $metadata->name), - $this->formatField('Root entity name', $metadata->rootEntityName), - $this->formatField('Custom generator definition', $metadata->customGeneratorDefinition), - $this->formatField('Custom repository class', $metadata->customRepositoryClassName), - $this->formatField('Mapped super class?', $metadata->isMappedSuperclass), - $this->formatField('Embedded class?', $metadata->isEmbeddedClass), - $this->formatField('Parent classes', $metadata->parentClasses), - $this->formatField('Sub classes', $metadata->subClasses), - $this->formatField('Embedded classes', $metadata->subClasses), - $this->formatField('Identifier', $metadata->identifier), - $this->formatField('Inheritance type', $metadata->inheritanceType), - $this->formatField('Discriminator column', $metadata->discriminatorColumn), - $this->formatField('Discriminator value', $metadata->discriminatorValue), - $this->formatField('Discriminator map', $metadata->discriminatorMap), - $this->formatField('Generator type', $metadata->generatorType), - $this->formatField('Table', $metadata->table), - $this->formatField('Composite identifier?', $metadata->isIdentifierComposite), - $this->formatField('Foreign identifier?', $metadata->containsForeignIdentifier), - $this->formatField('Enum identifier?', $metadata->containsEnumIdentifier), - $this->formatField('Sequence generator definition', $metadata->sequenceGeneratorDefinition), - $this->formatField('Change tracking policy', $metadata->changeTrackingPolicy), - $this->formatField('Versioned?', $metadata->isVersioned), - $this->formatField('Version field', $metadata->versionField), - $this->formatField('Read only?', $metadata->isReadOnly), - - $this->formatEntityListeners($metadata->entityListeners), - ], - [$this->formatField('Association mappings:', '')], - $this->formatMappings($metadata->associationMappings), - [$this->formatField('Field mappings:', '')], - $this->formatMappings($metadata->fieldMappings), - ), - ); - } - - /** - * Return all mapped entity class names - * - * @return string[] - * @psalm-return class-string[] - */ - private function getMappedEntities(EntityManagerInterface $entityManager): array - { - $entityClassNames = $entityManager->getConfiguration() - ->getMetadataDriverImpl() - ->getAllClassNames(); - - if (! $entityClassNames) { - throw new InvalidArgumentException( - 'You do not have any mapped Doctrine ORM entities according to the current configuration. ' . - 'If you have entities or mapping files you should check your mapping configuration for errors.', - ); - } - - return $entityClassNames; - } - - /** - * Return the class metadata for the given entity - * name - * - * @param string $entityName Full or partial entity name - */ - private function getClassMetadata( - string $entityName, - EntityManagerInterface $entityManager, - ): ClassMetadata { - try { - return $entityManager->getClassMetadata($entityName); - } catch (MappingException) { - } - - $matches = array_filter( - $this->getMappedEntities($entityManager), - static fn ($mappedEntity) => preg_match('{' . preg_quote($entityName) . '}', $mappedEntity) - ); - - if (! $matches) { - throw new InvalidArgumentException(sprintf( - 'Could not find any mapped Entity classes matching "%s"', - $entityName, - )); - } - - if (count($matches) > 1) { - throw new InvalidArgumentException(sprintf( - 'Entity name "%s" is ambiguous, possible matches: "%s"', - $entityName, - implode(', ', $matches), - )); - } - - return $entityManager->getClassMetadata(current($matches)); - } - - /** - * Format the given value for console output - */ - private function formatValue(mixed $value): string - { - if ($value === '') { - return ''; - } - - if ($value === null) { - return 'Null'; - } - - if (is_bool($value)) { - return '' . ($value ? 'True' : 'False') . ''; - } - - if (empty($value)) { - return 'Empty'; - } - - if (is_array($value)) { - return json_encode( - $value, - JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR, - ); - } - - if (is_object($value)) { - return sprintf('<%s>', get_debug_type($value)); - } - - if (is_scalar($value)) { - return (string) $value; - } - - throw new InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true))); - } - - /** - * Add the given label and value to the two column table output - * - * @param string $label Label for the value - * @param mixed $value A Value to show - * - * @return string[] - * @psalm-return array{0: string, 1: string} - */ - private function formatField(string $label, mixed $value): array - { - if ($value === null) { - $value = 'None'; - } - - return [sprintf('%s', $label), $this->formatValue($value)]; - } - - /** - * Format the association mappings - * - * @psalm-param array $propertyMappings - * - * @return string[][] - * @psalm-return list - */ - private function formatMappings(array $propertyMappings): array - { - $output = []; - - foreach ($propertyMappings as $propertyName => $mapping) { - $output[] = $this->formatField(sprintf(' %s', $propertyName), ''); - - foreach ((array) $mapping as $field => $value) { - $output[] = $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); - } - } - - return $output; - } - - /** - * Format the entity listeners - * - * @psalm-param list $entityListeners - * - * @return string[] - * @psalm-return array{0: string, 1: string} - */ - private function formatEntityListeners(array $entityListeners): array - { - return $this->formatField('Entity listeners', array_map('get_class', $entityListeners)); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/RunDqlCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/RunDqlCommand.php deleted file mode 100644 index 252151e..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/RunDqlCommand.php +++ /dev/null @@ -1,118 +0,0 @@ -setName('orm:run-dql') - ->setDescription('Executes arbitrary DQL directly from the command line') - ->addArgument('dql', InputArgument::REQUIRED, 'The DQL to execute.') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('hydrate', null, InputOption::VALUE_REQUIRED, 'Hydration mode of result set. Should be either: object, array, scalar or single-scalar.', 'object') - ->addOption('first-result', null, InputOption::VALUE_REQUIRED, 'The first result in the result set.') - ->addOption('max-result', null, InputOption::VALUE_REQUIRED, 'The maximum number of results in the result set.') - ->addOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of Entity graph.', 7) - ->addOption('show-sql', null, InputOption::VALUE_NONE, 'Dump generated SQL instead of executing query') - ->setHelp(<<<'EOT' - The %command.name% command executes the given DQL query and - outputs the results: - - php %command.full_name% "SELECT u FROM App\Entity\User u" - - You can also optionally specify some additional options like what type of - hydration to use when executing the query: - - php %command.full_name% "SELECT u FROM App\Entity\User u" --hydrate=array - - Additionally you can specify the first result and maximum amount of results to - show: - - php %command.full_name% "SELECT u FROM App\Entity\User u" --first-result=0 --max-result=30 - EOT); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = new SymfonyStyle($input, $output); - - $em = $this->getEntityManager($input); - - $dql = $input->getArgument('dql'); - if ($dql === null) { - throw new RuntimeException("Argument 'dql' is required in order to execute this command correctly."); - } - - $depth = $input->getOption('depth'); - - if (! is_numeric($depth)) { - throw new LogicException("Option 'depth' must contain an integer value"); - } - - $hydrationModeName = (string) $input->getOption('hydrate'); - $hydrationMode = 'Doctrine\ORM\Query::HYDRATE_' . strtoupper(str_replace('-', '_', $hydrationModeName)); - - if (! defined($hydrationMode)) { - throw new RuntimeException(sprintf( - "Hydration mode '%s' does not exist. It should be either: object. array, scalar or single-scalar.", - $hydrationModeName, - )); - } - - $query = $em->createQuery($dql); - - $firstResult = $input->getOption('first-result'); - if ($firstResult !== null) { - if (! is_numeric($firstResult)) { - throw new LogicException("Option 'first-result' must contain an integer value"); - } - - $query->setFirstResult((int) $firstResult); - } - - $maxResult = $input->getOption('max-result'); - if ($maxResult !== null) { - if (! is_numeric($maxResult)) { - throw new LogicException("Option 'max-result' must contain an integer value"); - } - - $query->setMaxResults((int) $maxResult); - } - - if ($input->getOption('show-sql')) { - $ui->text($query->getSQL()); - - return 0; - } - - $resultSet = $query->execute([], constant($hydrationMode)); - - $ui->text(Debug::dump($resultSet, (int) $input->getOption('depth'))); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/AbstractCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/AbstractCommand.php deleted file mode 100644 index b1e4460..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/AbstractCommand.php +++ /dev/null @@ -1,39 +0,0 @@ -getEntityManager($input); - - $metadatas = $em->getMetadataFactory()->getAllMetadata(); - - if (empty($metadatas)) { - $ui->getErrorStyle()->success('No Metadata Classes to process.'); - - return 0; - } - - return $this->executeSchemaCommand($input, $output, new SchemaTool($em), $metadatas, $ui); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/CreateCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/CreateCommand.php deleted file mode 100644 index 69e20c6..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/CreateCommand.php +++ /dev/null @@ -1,75 +0,0 @@ -setName('orm:schema-tool:create') - ->setDescription('Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Instead of trying to apply generated SQLs into EntityManager Storage Connection, output them.') - ->setHelp(<<<'EOT' -Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output. - -Hint: If you have a database with tables that should not be managed -by the ORM, you can use a DBAL functionality to filter the tables and sequences down -on a global level: - - $config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool { - if ($assetName instanceof AbstractAsset) { - $assetName = $assetName->getName(); - } - - return !str_starts_with($assetName, 'audit_'); - }); -EOT); - } - - /** - * {@inheritDoc} - */ - protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui): int - { - $dumpSql = $input->getOption('dump-sql') === true; - - if ($dumpSql) { - $sqls = $schemaTool->getCreateSchemaSql($metadatas); - - foreach ($sqls as $sql) { - $ui->writeln(sprintf('%s;', $sql)); - } - - return 0; - } - - $notificationUi = $ui->getErrorStyle(); - - $notificationUi->caution('This operation should not be executed in a production environment!'); - - $notificationUi->text('Creating database schema...'); - $notificationUi->newLine(); - - $schemaTool->createSchema($metadatas); - - $notificationUi->success('Database schema created successfully!'); - - return 0; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/DropCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/DropCommand.php deleted file mode 100644 index 5c8253b..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/DropCommand.php +++ /dev/null @@ -1,116 +0,0 @@ -setName('orm:schema-tool:drop') - ->setDescription('Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Instead of trying to apply generated SQLs into EntityManager Storage Connection, output them.') - ->addOption('force', 'f', InputOption::VALUE_NONE, "Don't ask for the deletion of the database, but force the operation to run.") - ->addOption('full-database', null, InputOption::VALUE_NONE, 'Instead of using the Class Metadata to detect the database table schema, drop ALL assets that the database contains.') - ->setHelp(<<<'EOT' -Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output. -Beware that the complete database is dropped by this command, even tables that are not relevant to your metadata model. - -Hint: If you have a database with tables that should not be managed -by the ORM, you can use a DBAL functionality to filter the tables and sequences down -on a global level: - - $config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool { - if ($assetName instanceof AbstractAsset) { - $assetName = $assetName->getName(); - } - - return !str_starts_with($assetName, 'audit_'); - }); -EOT); - } - - /** - * {@inheritDoc} - */ - protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui): int - { - $isFullDatabaseDrop = $input->getOption('full-database'); - $dumpSql = $input->getOption('dump-sql') === true; - $force = $input->getOption('force') === true; - - if ($dumpSql) { - if ($isFullDatabaseDrop) { - $sqls = $schemaTool->getDropDatabaseSQL(); - } else { - $sqls = $schemaTool->getDropSchemaSQL($metadatas); - } - - foreach ($sqls as $sql) { - $ui->writeln(sprintf('%s;', $sql)); - } - - return 0; - } - - $notificationUi = $ui->getErrorStyle(); - - if ($force) { - $notificationUi->text('Dropping database schema...'); - $notificationUi->newLine(); - - if ($isFullDatabaseDrop) { - $schemaTool->dropDatabase(); - } else { - $schemaTool->dropSchema($metadatas); - } - - $notificationUi->success('Database schema dropped successfully!'); - - return 0; - } - - $notificationUi->caution('This operation should not be executed in a production environment!'); - - if ($isFullDatabaseDrop) { - $sqls = $schemaTool->getDropDatabaseSQL(); - } else { - $sqls = $schemaTool->getDropSchemaSQL($metadatas); - } - - if (empty($sqls)) { - $notificationUi->success('Nothing to drop. The database is empty!'); - - return 0; - } - - $notificationUi->text( - [ - sprintf('The Schema-Tool would execute "%s" queries to update the database.', count($sqls)), - '', - 'Please run the operation by passing one - or both - of the following options:', - '', - sprintf(' %s --force to execute the command', $this->getName()), - sprintf(' %s --dump-sql to dump the SQL statements to the screen', $this->getName()), - ], - ); - - return 1; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/UpdateCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/UpdateCommand.php deleted file mode 100644 index f35fc38..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/SchemaTool/UpdateCommand.php +++ /dev/null @@ -1,147 +0,0 @@ -setName($this->name) - ->setDescription('Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('complete', null, InputOption::VALUE_NONE, 'This option is a no-op, is deprecated and will be removed in 4.0') - ->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Dumps the generated SQL statements to the screen (does not execute them).') - ->addOption('force', 'f', InputOption::VALUE_NONE, 'Causes the generated SQL statements to be physically executed against your database.') - ->setHelp(<<<'EOT' -The %command.name% command generates the SQL needed to -synchronize the database schema with the current mapping metadata of the -default entity manager. - -For example, if you add metadata for a new column to an entity, this command -would generate and output the SQL needed to add the new column to the database: - -%command.name% --dump-sql - -Alternatively, you can execute the generated queries: - -%command.name% --force - -If both options are specified, the queries are output and then executed: - -%command.name% --dump-sql --force - -Finally, be aware that this task will drop all database assets (e.g. tables, -etc) that are *not* described by the current metadata. In other words, without -this option, this task leaves untouched any "extra" tables that exist in the -database, but which aren't described by any metadata. - -Hint: If you have a database with tables that should not be managed -by the ORM, you can use a DBAL functionality to filter the tables and sequences down -on a global level: - - $config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool { - if ($assetName instanceof AbstractAsset) { - $assetName = $assetName->getName(); - } - - return !str_starts_with($assetName, 'audit_'); - }); -EOT); - } - - /** - * {@inheritDoc} - */ - protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui): int - { - $notificationUi = $ui->getErrorStyle(); - - if ($input->getOption('complete') === true) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/11354', - 'The --complete option is a no-op, is deprecated and will be removed in Doctrine ORM 4.0.', - ); - $notificationUi->warning('The --complete option is a no-op, is deprecated and will be removed in Doctrine ORM 4.0.'); - } - - $sqls = $schemaTool->getUpdateSchemaSql($metadatas); - - if (empty($sqls)) { - $notificationUi->success('Nothing to update - your database is already in sync with the current entity metadata.'); - - return 0; - } - - $dumpSql = $input->getOption('dump-sql') === true; - $force = $input->getOption('force') === true; - - if ($dumpSql) { - foreach ($sqls as $sql) { - $ui->writeln(sprintf('%s;', $sql)); - } - } - - if ($force) { - if ($dumpSql) { - $notificationUi->newLine(); - } - - $notificationUi->text('Updating database schema...'); - $notificationUi->newLine(); - - $schemaTool->updateSchema($metadatas); - - $pluralization = count($sqls) === 1 ? 'query was' : 'queries were'; - - $notificationUi->text(sprintf(' %s %s executed', count($sqls), $pluralization)); - $notificationUi->success('Database schema updated successfully!'); - } - - if ($dumpSql || $force) { - return 0; - } - - $notificationUi->caution( - [ - 'This operation should not be executed in a production environment!', - '', - 'Use the incremental update to detect changes during development and use', - 'the SQL DDL provided to manually update your database in production.', - ], - ); - - $notificationUi->text( - [ - sprintf('The Schema-Tool would execute "%s" queries to update the database.', count($sqls)), - '', - 'Please run the operation by passing one - or both - of the following options:', - '', - sprintf(' %s --force to execute the command', $this->getName()), - sprintf(' %s --dump-sql to dump the SQL statements to the screen', $this->getName()), - ], - ); - - return 1; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/Command/ValidateSchemaCommand.php b/vendor/doctrine/orm/src/Tools/Console/Command/ValidateSchemaCommand.php deleted file mode 100644 index cffb4ce..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/Command/ValidateSchemaCommand.php +++ /dev/null @@ -1,89 +0,0 @@ -setName('orm:validate-schema') - ->setDescription('Validate the mapping files') - ->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on') - ->addOption('skip-mapping', null, InputOption::VALUE_NONE, 'Skip the mapping validation check') - ->addOption('skip-sync', null, InputOption::VALUE_NONE, 'Skip checking if the mapping is in sync with the database') - ->addOption('skip-property-types', null, InputOption::VALUE_NONE, 'Skip checking if property types match the Doctrine types') - ->setHelp('Validate that the mapping files are correct and in sync with the database.'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $ui = (new SymfonyStyle($input, $output))->getErrorStyle(); - - $em = $this->getEntityManager($input); - $validator = new SchemaValidator($em, ! $input->getOption('skip-property-types')); - $exit = 0; - - $ui->section('Mapping'); - - if ($input->getOption('skip-mapping')) { - $ui->text('[SKIPPED] The mapping was not checked.'); - } else { - $errors = $validator->validateMapping(); - if ($errors) { - foreach ($errors as $className => $errorMessages) { - $ui->text( - sprintf( - '[FAIL] The entity-class %s mapping is invalid:', - $className, - ), - ); - - $ui->listing($errorMessages); - $ui->newLine(); - } - - ++$exit; - } else { - $ui->success('The mapping files are correct.'); - } - } - - $ui->section('Database'); - - if ($input->getOption('skip-sync')) { - $ui->text('[SKIPPED] The database was not checked for synchronicity.'); - } elseif (! $validator->schemaInSyncWithMetadata()) { - $ui->error('The database schema is not in sync with the current mapping file.'); - - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $sqls = $validator->getUpdateSchemaList(); - $ui->comment(sprintf('%d schema diff(s) detected:', count($sqls))); - foreach ($sqls as $sql) { - $ui->text(sprintf(' %s;', $sql)); - } - } - - $exit += 2; - } else { - $ui->success('The database schema is in sync with the mapping files.'); - } - - return $exit; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/ConsoleRunner.php b/vendor/doctrine/orm/src/Tools/Console/ConsoleRunner.php deleted file mode 100644 index 0a00483..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/ConsoleRunner.php +++ /dev/null @@ -1,88 +0,0 @@ -run(); - } - - /** - * Creates a console application with the given helperset and - * optional commands. - * - * @param SymfonyCommand[] $commands - * - * @throws OutOfBoundsException - */ - public static function createApplication( - EntityManagerProvider $entityManagerProvider, - array $commands = [], - ): Application { - $version = InstalledVersions::getVersion('doctrine/orm'); - assert($version !== null); - - $cli = new Application('Doctrine Command Line Interface', $version); - $cli->setCatchExceptions(true); - - self::addCommands($cli, $entityManagerProvider); - $cli->addCommands($commands); - - return $cli; - } - - public static function addCommands(Application $cli, EntityManagerProvider $entityManagerProvider): void - { - $connectionProvider = new ConnectionFromManagerProvider($entityManagerProvider); - - if (class_exists(DBALConsole\Command\ReservedWordsCommand::class)) { - $cli->add(new DBALConsole\Command\ReservedWordsCommand($connectionProvider)); - } - - $cli->addCommands( - [ - // DBAL Commands - new DBALConsole\Command\RunSqlCommand($connectionProvider), - - // ORM Commands - new Command\ClearCache\CollectionRegionCommand($entityManagerProvider), - new Command\ClearCache\EntityRegionCommand($entityManagerProvider), - new Command\ClearCache\MetadataCommand($entityManagerProvider), - new Command\ClearCache\QueryCommand($entityManagerProvider), - new Command\ClearCache\QueryRegionCommand($entityManagerProvider), - new Command\ClearCache\ResultCommand($entityManagerProvider), - new Command\SchemaTool\CreateCommand($entityManagerProvider), - new Command\SchemaTool\UpdateCommand($entityManagerProvider), - new Command\SchemaTool\DropCommand($entityManagerProvider), - new Command\GenerateProxiesCommand($entityManagerProvider), - new Command\RunDqlCommand($entityManagerProvider), - new Command\ValidateSchemaCommand($entityManagerProvider), - new Command\InfoCommand($entityManagerProvider), - new Command\MappingDescribeCommand($entityManagerProvider), - ], - ); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider.php b/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider.php deleted file mode 100644 index 866589b..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider.php +++ /dev/null @@ -1,14 +0,0 @@ -entityManagerProvider->getDefaultManager()->getConnection(); - } - - public function getConnection(string $name): Connection - { - return $this->entityManagerProvider->getManager($name)->getConnection(); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/SingleManagerProvider.php b/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/SingleManagerProvider.php deleted file mode 100644 index ebe60c9..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/SingleManagerProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -entityManager; - } - - public function getManager(string $name): EntityManagerInterface - { - if ($name !== $this->defaultManagerName) { - throw UnknownManagerException::unknownManager($name, [$this->defaultManagerName]); - } - - return $this->entityManager; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/UnknownManagerException.php b/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/UnknownManagerException.php deleted file mode 100644 index 583d909..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/EntityManagerProvider/UnknownManagerException.php +++ /dev/null @@ -1,23 +0,0 @@ - $knownManagers */ - public static function unknownManager(string $unknownManager, array $knownManagers = []): self - { - return new self(sprintf( - 'Requested unknown entity manager: %s, known managers: %s', - $unknownManager, - implode(', ', $knownManagers), - )); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Console/MetadataFilter.php b/vendor/doctrine/orm/src/Tools/Console/MetadataFilter.php deleted file mode 100644 index 05e248c..0000000 --- a/vendor/doctrine/orm/src/Tools/Console/MetadataFilter.php +++ /dev/null @@ -1,92 +0,0 @@ -filter = (array) $filter; - - parent::__construct($metadata); - } - - public function accept(): bool - { - if (count($this->filter) === 0) { - return true; - } - - $it = $this->getInnerIterator(); - $metadata = $it->current(); - - foreach ($this->filter as $filter) { - $pregResult = preg_match('/' . $filter . '/', $metadata->getName()); - - if ($pregResult === false) { - throw new RuntimeException( - sprintf("Error while evaluating regex '/%s/'.", $filter), - ); - } - - if ($pregResult) { - return true; - } - } - - return false; - } - - /** @return ArrayIterator */ - public function getInnerIterator(): ArrayIterator - { - $innerIterator = parent::getInnerIterator(); - - assert($innerIterator instanceof ArrayIterator); - - return $innerIterator; - } - - public function count(): int - { - return count($this->getInnerIterator()); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Debug.php b/vendor/doctrine/orm/src/Tools/Debug.php deleted file mode 100644 index 8521e53..0000000 --- a/vendor/doctrine/orm/src/Tools/Debug.php +++ /dev/null @@ -1,158 +0,0 @@ -toArray(); - } - - if (! $maxDepth) { - return is_object($var) ? $var::class - : (is_array($var) ? 'Array(' . count($var) . ')' : $var); - } - - if (is_array($var)) { - $return = []; - - foreach ($var as $k => $v) { - $return[$k] = self::export($v, $maxDepth - 1); - } - - return $return; - } - - if (! is_object($var)) { - return $var; - } - - $return = new stdClass(); - if ($var instanceof DateTimeInterface) { - $return->__CLASS__ = $var::class; - $return->date = $var->format('c'); - $return->timezone = $var->getTimezone()->getName(); - - return $return; - } - - $return->__CLASS__ = DefaultProxyClassNameResolver::getClass($var); - - if ($var instanceof Proxy) { - $return->__IS_PROXY__ = true; - $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); - } - - if ($var instanceof ArrayObject || $var instanceof ArrayIterator) { - $return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1); - } - - return self::fillReturnWithClassAttributes($var, $return, $maxDepth); - } - - /** - * Fill the $return variable with class attributes - * Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075} - */ - private static function fillReturnWithClassAttributes(object $var, stdClass $return, int $maxDepth): stdClass - { - $clone = (array) $var; - - foreach (array_keys($clone) as $key) { - $aux = explode("\0", (string) $key); - $name = end($aux); - if ($aux[0] === '') { - $name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private'); - } - - $return->$name = self::export($clone[$key], $maxDepth - 1); - } - - return $return; - } -} diff --git a/vendor/doctrine/orm/src/Tools/DebugUnitOfWorkListener.php b/vendor/doctrine/orm/src/Tools/DebugUnitOfWorkListener.php deleted file mode 100644 index 71059f7..0000000 --- a/vendor/doctrine/orm/src/Tools/DebugUnitOfWorkListener.php +++ /dev/null @@ -1,144 +0,0 @@ -dumpIdentityMap($args->getObjectManager()); - } - - /** - * Dumps the contents of the identity map into a stream. - */ - public function dumpIdentityMap(EntityManagerInterface $em): void - { - $uow = $em->getUnitOfWork(); - $identityMap = $uow->getIdentityMap(); - - $fh = fopen($this->file, 'xb+'); - if (count($identityMap) === 0) { - fwrite($fh, 'Flush Operation [' . $this->context . "] - Empty identity map.\n"); - - return; - } - - fwrite($fh, 'Flush Operation [' . $this->context . "] - Dumping identity map:\n"); - foreach ($identityMap as $className => $map) { - fwrite($fh, 'Class: ' . $className . "\n"); - - foreach ($map as $entity) { - fwrite($fh, ' Entity: ' . $this->getIdString($entity, $uow) . ' ' . spl_object_id($entity) . "\n"); - fwrite($fh, " Associations:\n"); - - $cm = $em->getClassMetadata($className); - - foreach ($cm->associationMappings as $field => $assoc) { - fwrite($fh, ' ' . $field . ' '); - $value = $cm->getFieldValue($entity, $field); - - if ($assoc->isToOne()) { - if ($value === null) { - fwrite($fh, " NULL\n"); - } else { - if ($uow->isUninitializedObject($value)) { - fwrite($fh, '[PROXY] '); - } - - fwrite($fh, $this->getIdString($value, $uow) . ' ' . spl_object_id($value) . "\n"); - } - } else { - $initialized = ! ($value instanceof PersistentCollection) || $value->isInitialized(); - if ($value === null) { - fwrite($fh, " NULL\n"); - } elseif ($initialized) { - fwrite($fh, '[INITIALIZED] ' . $this->getType($value) . ' ' . count($value) . " elements\n"); - - foreach ($value as $obj) { - fwrite($fh, ' ' . $this->getIdString($obj, $uow) . ' ' . spl_object_id($obj) . "\n"); - } - } else { - fwrite($fh, '[PROXY] ' . $this->getType($value) . " unknown element size\n"); - foreach ($value->unwrap() as $obj) { - fwrite($fh, ' ' . $this->getIdString($obj, $uow) . ' ' . spl_object_id($obj) . "\n"); - } - } - } - } - } - } - - fclose($fh); - } - - private function getType(mixed $var): string - { - if (is_object($var)) { - $refl = new ReflectionObject($var); - - return $refl->getShortName(); - } - - return gettype($var); - } - - private function getIdString(object $entity, UnitOfWork $uow): string - { - if ($uow->isInIdentityMap($entity)) { - $ids = $uow->getEntityIdentifier($entity); - $idstring = ''; - - foreach ($ids as $k => $v) { - $idstring .= $k . '=' . $v; - } - } else { - $idstring = 'NEWOBJECT '; - } - - $state = $uow->getEntityState($entity); - - if ($state === UnitOfWork::STATE_NEW) { - $idstring .= ' [NEW]'; - } elseif ($state === UnitOfWork::STATE_REMOVED) { - $idstring .= ' [REMOVED]'; - } elseif ($state === UnitOfWork::STATE_MANAGED) { - $idstring .= ' [MANAGED]'; - } elseif ($state === UnitOfWork::STATE_DETACHED) { - $idstring .= ' [DETACHED]'; - } - - return $idstring; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaEventArgs.php b/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaEventArgs.php deleted file mode 100644 index 3b0993e..0000000 --- a/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaEventArgs.php +++ /dev/null @@ -1,33 +0,0 @@ -em; - } - - public function getSchema(): Schema - { - return $this->schema; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaTableEventArgs.php b/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaTableEventArgs.php deleted file mode 100644 index a09aaae..0000000 --- a/vendor/doctrine/orm/src/Tools/Event/GenerateSchemaTableEventArgs.php +++ /dev/null @@ -1,40 +0,0 @@ -classMetadata; - } - - public function getSchema(): Schema - { - return $this->schema; - } - - public function getClassTable(): Table - { - return $this->classTable; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Exception/MissingColumnException.php b/vendor/doctrine/orm/src/Tools/Exception/MissingColumnException.php deleted file mode 100644 index 764721e..0000000 --- a/vendor/doctrine/orm/src/Tools/Exception/MissingColumnException.php +++ /dev/null @@ -1,23 +0,0 @@ - FROM ()) - * - * Works with composite keys but cannot deal with queries that have multiple - * root entities (e.g. `SELECT f, b from Foo, Bar`) - * - * Note that the ORDER BY clause is not removed. Many SQL implementations (e.g. MySQL) - * are able to cache subqueries. By keeping the ORDER BY clause intact, the limitSubQuery - * that will most likely be executed next can be read from the native SQL cache. - * - * @psalm-import-type QueryComponent from Parser - */ -class CountOutputWalker extends SqlWalker -{ - private readonly AbstractPlatform $platform; - private readonly ResultSetMapping $rsm; - - /** - * {@inheritDoc} - */ - public function __construct(Query $query, ParserResult $parserResult, array $queryComponents) - { - $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); - $this->rsm = $parserResult->getResultSetMapping(); - - parent::__construct($query, $parserResult, $queryComponents); - } - - public function walkSelectStatement(SelectStatement $selectStatement): string - { - if ($this->platform instanceof SQLServerPlatform) { - $selectStatement->orderByClause = null; - } - - $sql = parent::walkSelectStatement($selectStatement); - - if ($selectStatement->groupByClause) { - return sprintf( - 'SELECT COUNT(*) AS dctrn_count FROM (%s) dctrn_table', - $sql, - ); - } - - // Find out the SQL alias of the identifier column of the root entity - // It may be possible to make this work with multiple root entities but that - // would probably require issuing multiple queries or doing a UNION SELECT - // so for now, It's not supported. - - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $rootIdentifier = $rootClass->identifier; - - // For every identifier, find out the SQL alias by combing through the ResultSetMapping - $sqlIdentifier = []; - foreach ($rootIdentifier as $property) { - if (isset($rootClass->fieldMappings[$property])) { - foreach (array_keys($this->rsm->fieldMappings, $property, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - - if (isset($rootClass->associationMappings[$property])) { - $association = $rootClass->associationMappings[$property]; - assert($association->isToOneOwningSide()); - $joinColumn = $association->joinColumns[0]->name; - - foreach (array_keys($this->rsm->metaMappings, $joinColumn, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - } - - if (count($rootIdentifier) !== count($sqlIdentifier)) { - throw new RuntimeException(sprintf( - 'Not all identifier properties can be found in the ResultSetMapping: %s', - implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))), - )); - } - - // Build the counter query - return sprintf( - 'SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT %s FROM (%s) dctrn_result) dctrn_table', - implode(', ', $sqlIdentifier), - $sql, - ); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php deleted file mode 100644 index d212943..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php +++ /dev/null @@ -1,68 +0,0 @@ -havingClause) { - throw new RuntimeException('Cannot count query that uses a HAVING clause. Use the output walkers for pagination'); - } - - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - $pathType = PathExpression::TYPE_STATE_FIELD; - if (isset($rootClass->associationMappings[$identifierFieldName])) { - $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - } - - $pathExpression = new PathExpression( - PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, - $rootAlias, - $identifierFieldName, - ); - $pathExpression->type = $pathType; - - $distinct = $this->_getQuery()->getHint(self::HINT_DISTINCT); - $selectStatement->selectClause->selectExpressions = [ - new SelectExpression( - new AggregateExpression('count', $pathExpression, $distinct), - null, - ), - ]; - - // ORDER BY is not needed, only increases query execution through unnecessary sorting. - $selectStatement->orderByClause = null; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php b/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php deleted file mode 100644 index 0e3da93..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php +++ /dev/null @@ -1,16 +0,0 @@ - FROM () LIMIT x OFFSET y - * - * Works with composite keys but cannot deal with queries that have multiple - * root entities (e.g. `SELECT f, b from Foo, Bar`) - * - * @psalm-import-type QueryComponent from Parser - */ -class LimitSubqueryOutputWalker extends SqlWalker -{ - private const ORDER_BY_PATH_EXPRESSION = '/(? */ - private array $orderByPathExpressions = []; - - /** - * We don't want to add path expressions from sub-selects into the select clause of the containing query. - * This state flag simply keeps track on whether we are walking on a subquery or not - */ - private bool $inSubSelect = false; - - /** - * Stores various parameters that are otherwise unavailable - * because Doctrine\ORM\Query\SqlWalker keeps everything private without - * accessors. - * - * {@inheritDoc} - */ - public function __construct( - Query $query, - ParserResult $parserResult, - array $queryComponents, - ) { - $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); - $this->rsm = $parserResult->getResultSetMapping(); - - // Reset limit and offset - $this->firstResult = $query->getFirstResult(); - $this->maxResults = $query->getMaxResults(); - $query->setFirstResult(0)->setMaxResults(null); - - $this->em = $query->getEntityManager(); - $this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy(); - - parent::__construct($query, $parserResult, $queryComponents); - } - - /** - * Check if the platform supports the ROW_NUMBER window function. - */ - private function platformSupportsRowNumber(): bool - { - return $this->platform instanceof PostgreSQLPlatform - || $this->platform instanceof SQLServerPlatform - || $this->platform instanceof OraclePlatform - || $this->platform instanceof DB2Platform - || (method_exists($this->platform, 'supportsRowNumberFunction') - && $this->platform->supportsRowNumberFunction()); - } - - /** - * Rebuilds a select statement's order by clause for use in a - * ROW_NUMBER() OVER() expression. - */ - private function rebuildOrderByForRowNumber(SelectStatement $AST): void - { - $orderByClause = $AST->orderByClause; - $selectAliasToExpressionMap = []; - // Get any aliases that are available for select expressions. - foreach ($AST->selectClause->selectExpressions as $selectExpression) { - $selectAliasToExpressionMap[$selectExpression->fieldIdentificationVariable] = $selectExpression->expression; - } - - // Rebuild string orderby expressions to use the select expression they're referencing - foreach ($orderByClause->orderByItems as $orderByItem) { - if (is_string($orderByItem->expression) && isset($selectAliasToExpressionMap[$orderByItem->expression])) { - $orderByItem->expression = $selectAliasToExpressionMap[$orderByItem->expression]; - } - } - - $func = new RowNumberOverFunction('dctrn_rownum'); - $func->orderByClause = $AST->orderByClause; - $AST->selectClause->selectExpressions[] = new SelectExpression($func, 'dctrn_rownum', true); - - // No need for an order by clause, we'll order by rownum in the outer query. - $AST->orderByClause = null; - } - - public function walkSelectStatement(SelectStatement $selectStatement): string - { - if ($this->platformSupportsRowNumber()) { - return $this->walkSelectStatementWithRowNumber($selectStatement); - } - - return $this->walkSelectStatementWithoutRowNumber($selectStatement); - } - - /** - * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT. - * This method is for use with platforms which support ROW_NUMBER. - * - * @throws RuntimeException - */ - public function walkSelectStatementWithRowNumber(SelectStatement $AST): string - { - $hasOrderBy = false; - $outerOrderBy = ' ORDER BY dctrn_minrownum ASC'; - $orderGroupBy = ''; - if ($AST->orderByClause instanceof OrderByClause) { - $hasOrderBy = true; - $this->rebuildOrderByForRowNumber($AST); - } - - $innerSql = $this->getInnerSQL($AST); - - $sqlIdentifier = $this->getSQLIdentifier($AST); - - if ($hasOrderBy) { - $orderGroupBy = ' GROUP BY ' . implode(', ', $sqlIdentifier); - $sqlIdentifier[] = 'MIN(' . $this->walkResultVariable('dctrn_rownum') . ') AS dctrn_minrownum'; - } - - // Build the counter query - $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $innerSql, - ); - - if ($hasOrderBy) { - $sql .= $orderGroupBy . $outerOrderBy; - } - - // Apply the limit and offset. - $sql = $this->platform->modifyLimitQuery( - $sql, - $this->maxResults, - $this->firstResult, - ); - - // Add the columns to the ResultSetMapping. It's not really nice but - // it works. Preferably I'd clear the RSM or simply create a new one - // but that is not possible from inside the output walker, so we dirty - // up the one we have. - foreach ($sqlIdentifier as $property => $alias) { - $this->rsm->addScalarResult($alias, $property); - } - - return $sql; - } - - /** - * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT. - * This method is for platforms which DO NOT support ROW_NUMBER. - * - * @throws RuntimeException - */ - public function walkSelectStatementWithoutRowNumber(SelectStatement $AST, bool $addMissingItemsFromOrderByToSelect = true): string - { - // We don't want to call this recursively! - if ($AST->orderByClause instanceof OrderByClause && $addMissingItemsFromOrderByToSelect) { - // In the case of ordering a query by columns from joined tables, we - // must add those columns to the select clause of the query BEFORE - // the SQL is generated. - $this->addMissingItemsFromOrderByToSelect($AST); - } - - // Remove order by clause from the inner query - // It will be re-appended in the outer select generated by this method - $orderByClause = $AST->orderByClause; - $AST->orderByClause = null; - - $innerSql = $this->getInnerSQL($AST); - - $sqlIdentifier = $this->getSQLIdentifier($AST); - - // Build the counter query - $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $innerSql, - ); - - // https://github.com/doctrine/orm/issues/2630 - $sql = $this->preserveSqlOrdering($sqlIdentifier, $innerSql, $sql, $orderByClause); - - // Apply the limit and offset. - $sql = $this->platform->modifyLimitQuery( - $sql, - $this->maxResults, - $this->firstResult, - ); - - // Add the columns to the ResultSetMapping. It's not really nice but - // it works. Preferably I'd clear the RSM or simply create a new one - // but that is not possible from inside the output walker, so we dirty - // up the one we have. - foreach ($sqlIdentifier as $property => $alias) { - $this->rsm->addScalarResult($alias, $property); - } - - // Restore orderByClause - $AST->orderByClause = $orderByClause; - - return $sql; - } - - /** - * Finds all PathExpressions in an AST's OrderByClause, and ensures that - * the referenced fields are present in the SelectClause of the passed AST. - */ - private function addMissingItemsFromOrderByToSelect(SelectStatement $AST): void - { - $this->orderByPathExpressions = []; - - // We need to do this in another walker because otherwise we'll end up - // polluting the state of this one. - $walker = clone $this; - - // This will populate $orderByPathExpressions via - // LimitSubqueryOutputWalker::walkPathExpression, which will be called - // as the select statement is walked. We'll end up with an array of all - // path expressions referenced in the query. - $walker->walkSelectStatementWithoutRowNumber($AST, false); - $orderByPathExpressions = $walker->getOrderByPathExpressions(); - - // Get a map of referenced identifiers to field names. - $selects = []; - foreach ($orderByPathExpressions as $pathExpression) { - assert($pathExpression->field !== null); - $idVar = $pathExpression->identificationVariable; - $field = $pathExpression->field; - if (! isset($selects[$idVar])) { - $selects[$idVar] = []; - } - - $selects[$idVar][$field] = true; - } - - // Loop the select clause of the AST and exclude items from $select - // that are already being selected in the query. - foreach ($AST->selectClause->selectExpressions as $selectExpression) { - if ($selectExpression instanceof SelectExpression) { - $idVar = $selectExpression->expression; - if (! is_string($idVar)) { - continue; - } - - $field = $selectExpression->fieldIdentificationVariable; - if ($field === null) { - // No need to add this select, as we're already fetching the whole object. - unset($selects[$idVar]); - } else { - unset($selects[$idVar][$field]); - } - } - } - - // Add select items which were not excluded to the AST's select clause. - foreach ($selects as $idVar => $fields) { - $AST->selectClause->selectExpressions[] = new SelectExpression($idVar, null, true); - } - } - - /** - * Generates new SQL for statements with an order by clause - * - * @param mixed[] $sqlIdentifier - */ - private function preserveSqlOrdering( - array $sqlIdentifier, - string $innerSql, - string $sql, - OrderByClause|null $orderByClause, - ): string { - // If the sql statement has an order by clause, we need to wrap it in a new select distinct statement - if (! $orderByClause) { - return $sql; - } - - // now only select distinct identifier - return sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $this->recreateInnerSql($orderByClause, $sqlIdentifier, $innerSql), - ); - } - - /** - * Generates a new SQL statement for the inner query to keep the correct sorting - * - * @param mixed[] $identifiers - */ - private function recreateInnerSql( - OrderByClause $orderByClause, - array $identifiers, - string $innerSql, - ): string { - [$searchPatterns, $replacements] = $this->generateSqlAliasReplacements(); - $orderByItems = []; - - foreach ($orderByClause->orderByItems as $orderByItem) { - // Walk order by item to get string representation of it and - // replace path expressions in the order by clause with their column alias - $orderByItemString = preg_replace( - $searchPatterns, - $replacements, - $this->walkOrderByItem($orderByItem), - ); - - $orderByItems[] = $orderByItemString; - $identifier = substr($orderByItemString, 0, strrpos($orderByItemString, ' ')); - - if (! in_array($identifier, $identifiers, true)) { - $identifiers[] = $identifier; - } - } - - return $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result_inner ORDER BY %s', - implode(', ', $identifiers), - $innerSql, - implode(', ', $orderByItems), - ); - } - - /** - * @return string[][] - * @psalm-return array{0: list, 1: list} - */ - private function generateSqlAliasReplacements(): array - { - $aliasMap = $searchPatterns = $replacements = $metadataList = []; - - // Generate DQL alias -> SQL table alias mapping - foreach (array_keys($this->rsm->aliasMap) as $dqlAlias) { - $metadataList[$dqlAlias] = $class = $this->getMetadataForDqlAlias($dqlAlias); - $aliasMap[$dqlAlias] = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - } - - // Generate search patterns for each field's path expression in the order by clause - foreach ($this->rsm->fieldMappings as $fieldAlias => $fieldName) { - $dqlAliasForFieldAlias = $this->rsm->columnOwnerMap[$fieldAlias]; - $class = $metadataList[$dqlAliasForFieldAlias]; - - // If the field is from a joined child table, we won't be ordering on it. - if (! isset($class->fieldMappings[$fieldName])) { - continue; - } - - $fieldMapping = $class->fieldMappings[$fieldName]; - - // Get the proper column name as will appear in the select list - $columnName = $this->quoteStrategy->getColumnName( - $fieldName, - $metadataList[$dqlAliasForFieldAlias], - $this->em->getConnection()->getDatabasePlatform(), - ); - - // Get the SQL table alias for the entity and field - $sqlTableAliasForFieldAlias = $aliasMap[$dqlAliasForFieldAlias]; - - if (isset($fieldMapping->declared) && $fieldMapping->declared !== $class->name) { - // Field was declared in a parent class, so we need to get the proper SQL table alias - // for the joined parent table. - $otherClassMetadata = $this->em->getClassMetadata($fieldMapping->declared); - - if (! $otherClassMetadata->isMappedSuperclass) { - $sqlTableAliasForFieldAlias = $this->getSQLTableAlias($otherClassMetadata->getTableName(), $dqlAliasForFieldAlias); - } - } - - // Compose search and replace patterns - $searchPatterns[] = sprintf(self::ORDER_BY_PATH_EXPRESSION, $sqlTableAliasForFieldAlias, $columnName); - $replacements[] = $fieldAlias; - } - - return [$searchPatterns, $replacements]; - } - - /** - * getter for $orderByPathExpressions - * - * @return list - */ - public function getOrderByPathExpressions(): array - { - return $this->orderByPathExpressions; - } - - /** - * @throws OptimisticLockException - * @throws QueryException - */ - private function getInnerSQL(SelectStatement $AST): string - { - // Set every select expression as visible(hidden = false) to - // make $AST have scalar mappings properly - this is relevant for referencing selected - // fields from outside the subquery, for example in the ORDER BY segment - $hiddens = []; - - foreach ($AST->selectClause->selectExpressions as $idx => $expr) { - $hiddens[$idx] = $expr->hiddenAliasResultVariable; - $expr->hiddenAliasResultVariable = false; - } - - $innerSql = parent::walkSelectStatement($AST); - - // Restore hiddens - foreach ($AST->selectClause->selectExpressions as $idx => $expr) { - $expr->hiddenAliasResultVariable = $hiddens[$idx]; - } - - return $innerSql; - } - - /** @return string[] */ - private function getSQLIdentifier(SelectStatement $AST): array - { - // Find out the SQL alias of the identifier column of the root entity. - // It may be possible to make this work with multiple root entities but that - // would probably require issuing multiple queries or doing a UNION SELECT. - // So for now, it's not supported. - - // Get the root entity and alias from the AST fromClause. - $from = $AST->fromClause->identificationVariableDeclarations; - if (count($from) !== 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $rootIdentifier = $rootClass->identifier; - - // For every identifier, find out the SQL alias by combing through the ResultSetMapping - $sqlIdentifier = []; - foreach ($rootIdentifier as $property) { - if (isset($rootClass->fieldMappings[$property])) { - foreach (array_keys($this->rsm->fieldMappings, $property, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - - if (isset($rootClass->associationMappings[$property])) { - $association = $rootClass->associationMappings[$property]; - assert($association->isToOneOwningSide()); - $joinColumn = $association->joinColumns[0]->name; - - foreach (array_keys($this->rsm->metaMappings, $joinColumn, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - } - - if (count($sqlIdentifier) === 0) { - throw new RuntimeException('The Paginator does not support Queries which only yield ScalarResults.'); - } - - if (count($rootIdentifier) !== count($sqlIdentifier)) { - throw new RuntimeException(sprintf( - 'Not all identifier properties can be found in the ResultSetMapping: %s', - implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))), - )); - } - - return $sqlIdentifier; - } - - public function walkPathExpression(PathExpression $pathExpr): string - { - if (! $this->inSubSelect && ! $this->platformSupportsRowNumber() && ! in_array($pathExpr, $this->orderByPathExpressions, true)) { - $this->orderByPathExpressions[] = $pathExpr; - } - - return parent::walkPathExpression($pathExpr); - } - - public function walkSubSelect(Subselect $subselect): string - { - $this->inSubSelect = true; - - $sql = parent::walkSubselect($subselect); - - $this->inSubSelect = false; - - return $sql; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php deleted file mode 100644 index 3fb0eee..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php +++ /dev/null @@ -1,155 +0,0 @@ -fromClause->identificationVariableDeclarations; - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - - $this->validate($selectStatement); - $identifier = $rootClass->getSingleIdentifierFieldName(); - - if (isset($rootClass->associationMappings[$identifier])) { - throw new RuntimeException('Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator.'); - } - - $query = $this->_getQuery(); - - $query->setHint( - self::IDENTIFIER_TYPE, - Type::getType($rootClass->fieldMappings[$identifier]->type), - ); - - $query->setHint(self::FORCE_DBAL_TYPE_CONVERSION, true); - - $pathExpression = new PathExpression( - PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, - $rootAlias, - $identifier, - ); - - $pathExpression->type = PathExpression::TYPE_STATE_FIELD; - - $selectStatement->selectClause->selectExpressions = [new SelectExpression($pathExpression, '_dctrn_id')]; - $selectStatement->selectClause->isDistinct = ($query->getHints()[Paginator::HINT_ENABLE_DISTINCT] ?? true) === true; - - if (! isset($selectStatement->orderByClause)) { - return; - } - - $queryComponents = $this->getQueryComponents(); - foreach ($selectStatement->orderByClause->orderByItems as $item) { - if ($item->expression instanceof PathExpression) { - $selectStatement->selectClause->selectExpressions[] = new SelectExpression( - $this->createSelectExpressionItem($item->expression), - '_dctrn_ord' . $this->aliasCounter++, - ); - - continue; - } - - if (is_string($item->expression) && isset($queryComponents[$item->expression])) { - $qComp = $queryComponents[$item->expression]; - - if (isset($qComp['resultVariable'])) { - $selectStatement->selectClause->selectExpressions[] = new SelectExpression( - $qComp['resultVariable'], - $item->expression, - ); - } - } - } - } - - /** - * Validate the AST to ensure that this walker is able to properly manipulate it. - */ - private function validate(SelectStatement $AST): void - { - // Prevent LimitSubqueryWalker from being used with queries that include - // a limit, a fetched to-many join, and an order by condition that - // references a column from the fetch joined table. - $queryComponents = $this->getQueryComponents(); - $query = $this->_getQuery(); - $from = $AST->fromClause->identificationVariableDeclarations; - $fromRoot = reset($from); - - if ( - $query instanceof Query - && $query->getMaxResults() !== null - && $AST->orderByClause - && count($fromRoot->joins) - ) { - // Check each orderby item. - // TODO: check complex orderby items too... - foreach ($AST->orderByClause->orderByItems as $orderByItem) { - $expression = $orderByItem->expression; - if ( - $orderByItem->expression instanceof PathExpression - && isset($queryComponents[$expression->identificationVariable]) - ) { - $queryComponent = $queryComponents[$expression->identificationVariable]; - if ( - isset($queryComponent['parent']) - && isset($queryComponent['relation']) - && $queryComponent['relation']->isToMany() - ) { - throw new RuntimeException('Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers.'); - } - } - } - } - } - - /** - * Retrieve either an IdentityFunction (IDENTITY(u.assoc)) or a state field (u.name). - * - * @return IdentityFunction|PathExpression - */ - private function createSelectExpressionItem(PathExpression $pathExpression): Node - { - if ($pathExpression->type === PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) { - $identity = new IdentityFunction('identity'); - - $identity->pathExpression = clone $pathExpression; - - return $identity; - } - - return clone $pathExpression; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php b/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php deleted file mode 100644 index db1b34d..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php +++ /dev/null @@ -1,263 +0,0 @@ - - */ -class Paginator implements Countable, IteratorAggregate -{ - use SQLResultCasing; - - public const HINT_ENABLE_DISTINCT = 'paginator.distinct.enable'; - - private readonly Query $query; - private bool|null $useOutputWalkers = null; - private int|null $count = null; - - /** @param bool $fetchJoinCollection Whether the query joins a collection (true by default). */ - public function __construct( - Query|QueryBuilder $query, - private readonly bool $fetchJoinCollection = true, - ) { - if ($query instanceof QueryBuilder) { - $query = $query->getQuery(); - } - - $this->query = $query; - } - - /** - * Returns the query. - */ - public function getQuery(): Query - { - return $this->query; - } - - /** - * Returns whether the query joins a collection. - * - * @return bool Whether the query joins a collection. - */ - public function getFetchJoinCollection(): bool - { - return $this->fetchJoinCollection; - } - - /** - * Returns whether the paginator will use an output walker. - */ - public function getUseOutputWalkers(): bool|null - { - return $this->useOutputWalkers; - } - - /** - * Sets whether the paginator will use an output walker. - * - * @return $this - */ - public function setUseOutputWalkers(bool|null $useOutputWalkers): static - { - $this->useOutputWalkers = $useOutputWalkers; - - return $this; - } - - public function count(): int - { - if ($this->count === null) { - try { - $this->count = (int) array_sum(array_map('current', $this->getCountQuery()->getScalarResult())); - } catch (NoResultException) { - $this->count = 0; - } - } - - return $this->count; - } - - /** - * {@inheritDoc} - * - * @psalm-return Traversable - */ - public function getIterator(): Traversable - { - $offset = $this->query->getFirstResult(); - $length = $this->query->getMaxResults(); - - if ($this->fetchJoinCollection && $length !== null) { - $subQuery = $this->cloneQuery($this->query); - - if ($this->useOutputWalker($subQuery)) { - $subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); - } else { - $this->appendTreeWalker($subQuery, LimitSubqueryWalker::class); - $this->unbindUnusedQueryParams($subQuery); - } - - $subQuery->setFirstResult($offset)->setMaxResults($length); - - $foundIdRows = $subQuery->getScalarResult(); - - // don't do this for an empty id array - if ($foundIdRows === []) { - return new ArrayIterator([]); - } - - $whereInQuery = $this->cloneQuery($this->query); - $ids = array_map('current', $foundIdRows); - - $this->appendTreeWalker($whereInQuery, WhereInWalker::class); - $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_HAS_IDS, true); - $whereInQuery->setFirstResult(0)->setMaxResults(null); - $whereInQuery->setCacheable($this->query->isCacheable()); - - $databaseIds = $this->convertWhereInIdentifiersToDatabaseValues($ids); - $whereInQuery->setParameter(WhereInWalker::PAGINATOR_ID_ALIAS, $databaseIds); - - $result = $whereInQuery->getResult($this->query->getHydrationMode()); - } else { - $result = $this->cloneQuery($this->query) - ->setMaxResults($length) - ->setFirstResult($offset) - ->setCacheable($this->query->isCacheable()) - ->getResult($this->query->getHydrationMode()); - } - - return new ArrayIterator($result); - } - - private function cloneQuery(Query $query): Query - { - $cloneQuery = clone $query; - - $cloneQuery->setParameters(clone $query->getParameters()); - $cloneQuery->setCacheable(false); - - foreach ($query->getHints() as $name => $value) { - $cloneQuery->setHint($name, $value); - } - - return $cloneQuery; - } - - /** - * Determines whether to use an output walker for the query. - */ - private function useOutputWalker(Query $query): bool - { - if ($this->useOutputWalkers === null) { - return (bool) $query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) === false; - } - - return $this->useOutputWalkers; - } - - /** - * Appends a custom tree walker to the tree walkers hint. - * - * @psalm-param class-string $walkerClass - */ - private function appendTreeWalker(Query $query, string $walkerClass): void - { - $hints = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); - - if ($hints === false) { - $hints = []; - } - - $hints[] = $walkerClass; - $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints); - } - - /** - * Returns Query prepared to count. - */ - private function getCountQuery(): Query - { - $countQuery = $this->cloneQuery($this->query); - - if (! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) { - $countQuery->setHint(CountWalker::HINT_DISTINCT, true); - } - - if ($this->useOutputWalker($countQuery)) { - $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win - - $rsm = new ResultSetMapping(); - $rsm->addScalarResult($this->getSQLResultCasing($platform, 'dctrn_count'), 'count'); - - $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, CountOutputWalker::class); - $countQuery->setResultSetMapping($rsm); - } else { - $this->appendTreeWalker($countQuery, CountWalker::class); - $this->unbindUnusedQueryParams($countQuery); - } - - $countQuery->setFirstResult(0)->setMaxResults(null); - - return $countQuery; - } - - private function unbindUnusedQueryParams(Query $query): void - { - $parser = new Parser($query); - $parameterMappings = $parser->parse()->getParameterMappings(); - /** @var Collection|Parameter[] $parameters */ - $parameters = $query->getParameters(); - - foreach ($parameters as $key => $parameter) { - $parameterName = $parameter->getName(); - - if (! (isset($parameterMappings[$parameterName]) || array_key_exists($parameterName, $parameterMappings))) { - unset($parameters[$key]); - } - } - - $query->setParameters($parameters); - } - - /** - * @param mixed[] $identifiers - * - * @return mixed[] - */ - private function convertWhereInIdentifiersToDatabaseValues(array $identifiers): array - { - $query = $this->cloneQuery($this->query); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, RootTypeWalker::class); - - $connection = $this->query->getEntityManager()->getConnection(); - $type = $query->getSQL(); - assert(is_string($type)); - - return array_map(static fn ($id): mixed => $connection->convertToDatabaseValue($id, $type), $identifiers); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php deleted file mode 100644 index f630ee1..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php +++ /dev/null @@ -1,48 +0,0 @@ - root entity id type resolution can be cached in the query cache. - */ -final class RootTypeWalker extends SqlWalker -{ - public function walkSelectStatement(AST\SelectStatement $selectStatement): string - { - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Can only process queries that select only one FROM component'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - return PersisterHelper::getTypeOfField( - $identifierFieldName, - $rootClass, - $this->getQuery() - ->getEntityManager(), - )[0]; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php b/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php deleted file mode 100644 index a0fdd01..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php +++ /dev/null @@ -1,40 +0,0 @@ -walkOrderByClause( - $this->orderByClause, - )) . ')'; - } - - /** - * @throws RowNumberOverFunctionNotEnabled - * - * @inheritdoc - */ - public function parse(Parser $parser): void - { - throw RowNumberOverFunctionNotEnabled::create(); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php deleted file mode 100644 index 01741ca..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php +++ /dev/null @@ -1,116 +0,0 @@ -fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - $pathType = PathExpression::TYPE_STATE_FIELD; - if (isset($rootClass->associationMappings[$identifierFieldName])) { - $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - } - - $pathExpression = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $rootAlias, $identifierFieldName); - $pathExpression->type = $pathType; - - $hasIds = $this->_getQuery()->getHint(self::HINT_PAGINATOR_HAS_IDS); - - if ($hasIds) { - $arithmeticExpression = new ArithmeticExpression(); - $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression( - [$pathExpression], - ); - $expression = new InListExpression( - $arithmeticExpression, - [new InputParameter(':' . self::PAGINATOR_ID_ALIAS)], - ); - } else { - $expression = new NullComparisonExpression($pathExpression); - } - - $conditionalPrimary = new ConditionalPrimary(); - $conditionalPrimary->simpleConditionalExpression = $expression; - if ($selectStatement->whereClause) { - if ($selectStatement->whereClause->conditionalExpression instanceof ConditionalTerm) { - $selectStatement->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary; - } elseif ($selectStatement->whereClause->conditionalExpression instanceof ConditionalPrimary) { - $selectStatement->whereClause->conditionalExpression = new ConditionalExpression( - [ - new ConditionalTerm( - [ - $selectStatement->whereClause->conditionalExpression, - $conditionalPrimary, - ], - ), - ], - ); - } else { - $tmpPrimary = new ConditionalPrimary(); - $tmpPrimary->conditionalExpression = $selectStatement->whereClause->conditionalExpression; - $selectStatement->whereClause->conditionalExpression = new ConditionalTerm( - [ - $tmpPrimary, - $conditionalPrimary, - ], - ); - } - } else { - $selectStatement->whereClause = new WhereClause( - new ConditionalExpression( - [new ConditionalTerm([$conditionalPrimary])], - ), - ); - } - } -} diff --git a/vendor/doctrine/orm/src/Tools/ResolveTargetEntityListener.php b/vendor/doctrine/orm/src/Tools/ResolveTargetEntityListener.php deleted file mode 100644 index 9e48521..0000000 --- a/vendor/doctrine/orm/src/Tools/ResolveTargetEntityListener.php +++ /dev/null @@ -1,117 +0,0 @@ - $mapping - */ - public function addResolveTargetEntity(string $originalEntity, string $newEntity, array $mapping): void - { - $mapping['targetEntity'] = ltrim($newEntity, '\\'); - $this->resolveTargetEntities[ltrim($originalEntity, '\\')] = $mapping; - } - - /** @internal this is an event callback, and should not be called directly */ - public function onClassMetadataNotFound(OnClassMetadataNotFoundEventArgs $args): void - { - if (array_key_exists($args->getClassName(), $this->resolveTargetEntities)) { - $args->setFoundMetadata( - $args - ->getObjectManager() - ->getClassMetadata($this->resolveTargetEntities[$args->getClassName()]['targetEntity']), - ); - } - } - - /** - * Processes event and resolves new target entity names. - * - * @internal this is an event callback, and should not be called directly - */ - public function loadClassMetadata(LoadClassMetadataEventArgs $args): void - { - $cm = $args->getClassMetadata(); - - foreach ($cm->associationMappings as $mapping) { - if (isset($this->resolveTargetEntities[$mapping->targetEntity])) { - $this->remapAssociation($cm, $mapping); - } - } - - foreach ($this->resolveTargetEntities as $interface => $data) { - if ($data['targetEntity'] === $cm->getName()) { - $args->getEntityManager()->getMetadataFactory()->setMetadataFor($interface, $cm); - } - } - - foreach ($cm->discriminatorMap as $value => $class) { - if (isset($this->resolveTargetEntities[$class])) { - $cm->addDiscriminatorMapClass($value, $this->resolveTargetEntities[$class]['targetEntity']); - } - } - } - - private function remapAssociation(ClassMetadata $classMetadata, AssociationMapping $mapping): void - { - $newMapping = $this->resolveTargetEntities[$mapping->targetEntity]; - $newMapping = array_replace_recursive( - $mapping->toArray(), - $newMapping, - ); - $newMapping['fieldName'] = $mapping->fieldName; - - unset($classMetadata->associationMappings[$mapping->fieldName]); - - switch ($mapping->type()) { - case ClassMetadata::MANY_TO_MANY: - $classMetadata->mapManyToMany($newMapping); - break; - case ClassMetadata::MANY_TO_ONE: - $classMetadata->mapManyToOne($newMapping); - break; - case ClassMetadata::ONE_TO_MANY: - $classMetadata->mapOneToMany($newMapping); - break; - case ClassMetadata::ONE_TO_ONE: - $classMetadata->mapOneToOne($newMapping); - break; - } - } -} diff --git a/vendor/doctrine/orm/src/Tools/SchemaTool.php b/vendor/doctrine/orm/src/Tools/SchemaTool.php deleted file mode 100644 index 42b52df..0000000 --- a/vendor/doctrine/orm/src/Tools/SchemaTool.php +++ /dev/null @@ -1,932 +0,0 @@ -ClassMetadata class descriptors. - * - * @link www.doctrine-project.org - */ -class SchemaTool -{ - private const KNOWN_COLUMN_OPTIONS = ['comment', 'unsigned', 'fixed', 'default']; - - private readonly AbstractPlatform $platform; - private readonly QuoteStrategy $quoteStrategy; - private readonly AbstractSchemaManager $schemaManager; - - /** - * Initializes a new SchemaTool instance that uses the connection of the - * provided EntityManager. - */ - public function __construct(private readonly EntityManagerInterface $em) - { - $this->platform = $em->getConnection()->getDatabasePlatform(); - $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $this->schemaManager = $em->getConnection()->createSchemaManager(); - } - - /** - * Creates the database schema for the given array of ClassMetadata instances. - * - * @psalm-param list $classes - * - * @throws ToolsException - */ - public function createSchema(array $classes): void - { - $createSchemaSql = $this->getCreateSchemaSql($classes); - $conn = $this->em->getConnection(); - - foreach ($createSchemaSql as $sql) { - try { - $conn->executeStatement($sql); - } catch (Throwable $e) { - throw ToolsException::schemaToolFailure($sql, $e); - } - } - } - - /** - * Gets the list of DDL statements that are required to create the database schema for - * the given list of ClassMetadata instances. - * - * @psalm-param list $classes - * - * @return list The SQL statements needed to create the schema for the classes. - */ - public function getCreateSchemaSql(array $classes): array - { - $schema = $this->getSchemaFromMetadata($classes); - - return $schema->toSql($this->platform); - } - - /** - * Detects instances of ClassMetadata that don't need to be processed in the SchemaTool context. - * - * @psalm-param array $processedClasses - */ - private function processingNotRequired( - ClassMetadata $class, - array $processedClasses, - ): bool { - return isset($processedClasses[$class->name]) || - $class->isMappedSuperclass || - $class->isEmbeddedClass || - ($class->isInheritanceTypeSingleTable() && $class->name !== $class->rootEntityName) || - in_array($class->name, $this->em->getConfiguration()->getSchemaIgnoreClasses()); - } - - /** - * Resolves fields in index mapping to column names - * - * @param mixed[] $indexData index or unique constraint data - * - * @return list Column names from combined fields and columns mappings - */ - private function getIndexColumns(ClassMetadata $class, array $indexData): array - { - $columns = []; - - if ( - isset($indexData['columns'], $indexData['fields']) - || ( - ! isset($indexData['columns']) - && ! isset($indexData['fields']) - ) - ) { - throw MappingException::invalidIndexConfiguration( - (string) $class, - $indexData['name'] ?? 'unnamed', - ); - } - - if (isset($indexData['columns'])) { - $columns = $indexData['columns']; - } - - if (isset($indexData['fields'])) { - foreach ($indexData['fields'] as $fieldName) { - if ($class->hasField($fieldName)) { - $columns[] = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); - } elseif ($class->hasAssociation($fieldName)) { - $assoc = $class->getAssociationMapping($fieldName); - assert($assoc->isToOneOwningSide()); - foreach ($assoc->joinColumns as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - } - } - } - - return $columns; - } - - /** - * Creates a Schema instance from a given set of metadata classes. - * - * @psalm-param list $classes - * - * @throws NotSupported - */ - public function getSchemaFromMetadata(array $classes): Schema - { - // Reminder for processed classes, used for hierarchies - $processedClasses = []; - $eventManager = $this->em->getEventManager(); - $metadataSchemaConfig = $this->schemaManager->createSchemaConfig(); - - $schema = new Schema([], [], $metadataSchemaConfig); - - $addedFks = []; - $blacklistedFks = []; - - foreach ($classes as $class) { - if ($this->processingNotRequired($class, $processedClasses)) { - continue; - } - - $table = $schema->createTable($this->quoteStrategy->getTableName($class, $this->platform)); - - if ($class->isInheritanceTypeSingleTable()) { - $this->gatherColumns($class, $table); - $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks); - - // Add the discriminator column - $this->addDiscriminatorColumnDefinition($class, $table); - - // Aggregate all the information from all classes in the hierarchy - foreach ($class->parentClasses as $parentClassName) { - // Parent class information is already contained in this class - $processedClasses[$parentClassName] = true; - } - - foreach ($class->subClasses as $subClassName) { - $subClass = $this->em->getClassMetadata($subClassName); - $this->gatherColumns($subClass, $table); - $this->gatherRelationsSql($subClass, $table, $schema, $addedFks, $blacklistedFks); - $processedClasses[$subClassName] = true; - } - } elseif ($class->isInheritanceTypeJoined()) { - // Add all non-inherited fields as columns - foreach ($class->fieldMappings as $fieldName => $mapping) { - if (! isset($mapping->inherited)) { - $this->gatherColumn($class, $mapping, $table); - } - } - - $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks); - - // Add the discriminator column only to the root table - if ($class->name === $class->rootEntityName) { - $this->addDiscriminatorColumnDefinition($class, $table); - } else { - // Add an ID FK column to child tables - $pkColumns = []; - $inheritedKeyColumns = []; - - foreach ($class->identifier as $identifierField) { - if (isset($class->fieldMappings[$identifierField]->inherited)) { - $idMapping = $class->fieldMappings[$identifierField]; - $this->gatherColumn($class, $idMapping, $table); - $columnName = $this->quoteStrategy->getColumnName( - $identifierField, - $class, - $this->platform, - ); - // TODO: This seems rather hackish, can we optimize it? - $table->getColumn($columnName)->setAutoincrement(false); - - $pkColumns[] = $columnName; - $inheritedKeyColumns[] = $columnName; - - continue; - } - - if (isset($class->associationMappings[$identifierField]->inherited)) { - $idMapping = $class->associationMappings[$identifierField]; - assert($idMapping->isToOneOwningSide()); - - $targetEntity = current( - array_filter( - $classes, - static fn (ClassMetadata $class): bool => $class->name === $idMapping->targetEntity, - ), - ); - - foreach ($idMapping->joinColumns as $joinColumn) { - if (isset($targetEntity->fieldMappings[$joinColumn->referencedColumnName])) { - $columnName = $this->quoteStrategy->getJoinColumnName( - $joinColumn, - $class, - $this->platform, - ); - - $pkColumns[] = $columnName; - $inheritedKeyColumns[] = $columnName; - } - } - } - } - - if ($inheritedKeyColumns !== []) { - // Add a FK constraint on the ID column - $table->addForeignKeyConstraint( - $this->quoteStrategy->getTableName( - $this->em->getClassMetadata($class->rootEntityName), - $this->platform, - ), - $inheritedKeyColumns, - $inheritedKeyColumns, - ['onDelete' => 'CASCADE'], - ); - } - - if ($pkColumns !== []) { - $table->setPrimaryKey($pkColumns); - } - } - } else { - $this->gatherColumns($class, $table); - $this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks); - } - - $pkColumns = []; - - foreach ($class->identifier as $identifierField) { - if (isset($class->fieldMappings[$identifierField])) { - $pkColumns[] = $this->quoteStrategy->getColumnName($identifierField, $class, $this->platform); - } elseif (isset($class->associationMappings[$identifierField])) { - $assoc = $class->associationMappings[$identifierField]; - assert($assoc->isToOneOwningSide()); - - foreach ($assoc->joinColumns as $joinColumn) { - $pkColumns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - } - } - } - - if (! $table->hasIndex('primary')) { - $table->setPrimaryKey($pkColumns); - } - - // there can be unique indexes automatically created for join column - // if join column is also primary key we should keep only primary key on this column - // so, remove indexes overruled by primary key - $primaryKey = $table->getIndex('primary'); - - foreach ($table->getIndexes() as $idxKey => $existingIndex) { - if ($primaryKey->overrules($existingIndex)) { - $table->dropIndex($idxKey); - } - } - - if (isset($class->table['indexes'])) { - foreach ($class->table['indexes'] as $indexName => $indexData) { - if (! isset($indexData['flags'])) { - $indexData['flags'] = []; - } - - $table->addIndex( - $this->getIndexColumns($class, $indexData), - is_numeric($indexName) ? null : $indexName, - (array) $indexData['flags'], - $indexData['options'] ?? [], - ); - } - } - - if (isset($class->table['uniqueConstraints'])) { - foreach ($class->table['uniqueConstraints'] as $indexName => $indexData) { - $uniqIndex = new Index('tmp__' . $indexName, $this->getIndexColumns($class, $indexData), true, false, [], $indexData['options'] ?? []); - - foreach ($table->getIndexes() as $tableIndexName => $tableIndex) { - if ($tableIndex->isFulfilledBy($uniqIndex)) { - $table->dropIndex($tableIndexName); - break; - } - } - - $table->addUniqueIndex($uniqIndex->getColumns(), is_numeric($indexName) ? null : $indexName, $indexData['options'] ?? []); - } - } - - if (isset($class->table['options'])) { - foreach ($class->table['options'] as $key => $val) { - $table->addOption($key, $val); - } - } - - $processedClasses[$class->name] = true; - - if ($class->isIdGeneratorSequence() && $class->name === $class->rootEntityName) { - $seqDef = $class->sequenceGeneratorDefinition; - $quotedName = $this->quoteStrategy->getSequenceName($seqDef, $class, $this->platform); - if (! $schema->hasSequence($quotedName)) { - $schema->createSequence( - $quotedName, - (int) $seqDef['allocationSize'], - (int) $seqDef['initialValue'], - ); - } - } - - if ($eventManager->hasListeners(ToolEvents::postGenerateSchemaTable)) { - $eventManager->dispatchEvent( - ToolEvents::postGenerateSchemaTable, - new GenerateSchemaTableEventArgs($class, $schema, $table), - ); - } - } - - if ($eventManager->hasListeners(ToolEvents::postGenerateSchema)) { - $eventManager->dispatchEvent( - ToolEvents::postGenerateSchema, - new GenerateSchemaEventArgs($this->em, $schema), - ); - } - - return $schema; - } - - /** - * Gets a portable column definition as required by the DBAL for the discriminator - * column of a class. - */ - private function addDiscriminatorColumnDefinition(ClassMetadata $class, Table $table): void - { - $discrColumn = $class->discriminatorColumn; - assert($discrColumn !== null); - - if (strtolower($discrColumn->type) === 'string' && ! isset($discrColumn->length)) { - $discrColumn->type = 'string'; - $discrColumn->length = 255; - } - - $options = [ - 'length' => $discrColumn->length ?? null, - 'notnull' => true, - ]; - - if (isset($discrColumn->columnDefinition)) { - $options['columnDefinition'] = $discrColumn->columnDefinition; - } - - $options = $this->gatherColumnOptions($discrColumn) + $options; - $table->addColumn($discrColumn->name, $discrColumn->type, $options); - } - - /** - * Gathers the column definitions as required by the DBAL of all field mappings - * found in the given class. - */ - private function gatherColumns(ClassMetadata $class, Table $table): void - { - $pkColumns = []; - - foreach ($class->fieldMappings as $mapping) { - if ($class->isInheritanceTypeSingleTable() && isset($mapping->inherited)) { - continue; - } - - $this->gatherColumn($class, $mapping, $table); - - if ($class->isIdentifier($mapping->fieldName)) { - $pkColumns[] = $this->quoteStrategy->getColumnName($mapping->fieldName, $class, $this->platform); - } - } - } - - /** - * Creates a column definition as required by the DBAL from an ORM field mapping definition. - * - * @param ClassMetadata $class The class that owns the field mapping. - * @psalm-param FieldMapping $mapping The field mapping. - */ - private function gatherColumn( - ClassMetadata $class, - FieldMapping $mapping, - Table $table, - ): void { - $columnName = $this->quoteStrategy->getColumnName($mapping->fieldName, $class, $this->platform); - $columnType = $mapping->type; - - $options = []; - $options['length'] = $mapping->length ?? null; - $options['notnull'] = isset($mapping->nullable) ? ! $mapping->nullable : true; - if ($class->isInheritanceTypeSingleTable() && $class->parentClasses) { - $options['notnull'] = false; - } - - $options['platformOptions'] = []; - $options['platformOptions']['version'] = $class->isVersioned && $class->versionField === $mapping->fieldName; - - if (strtolower($columnType) === 'string' && $options['length'] === null) { - $options['length'] = 255; - } - - if (isset($mapping->precision)) { - $options['precision'] = $mapping->precision; - } - - if (isset($mapping->scale)) { - $options['scale'] = $mapping->scale; - } - - if (isset($mapping->default)) { - $options['default'] = $mapping->default; - } - - if (isset($mapping->columnDefinition)) { - $options['columnDefinition'] = $mapping->columnDefinition; - } - - // the 'default' option can be overwritten here - $options = $this->gatherColumnOptions($mapping) + $options; - - if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() === [$mapping->fieldName]) { - $options['autoincrement'] = true; - } - - if ($class->isInheritanceTypeJoined() && $class->name !== $class->rootEntityName) { - $options['autoincrement'] = false; - } - - if ($table->hasColumn($columnName)) { - // required in some inheritance scenarios - $table->modifyColumn($columnName, $options); - } else { - $table->addColumn($columnName, $columnType, $options); - } - - $isUnique = $mapping->unique ?? false; - if ($isUnique) { - $table->addUniqueIndex([$columnName]); - } - } - - /** - * Gathers the SQL for properly setting up the relations of the given class. - * This includes the SQL for foreign key constraints and join tables. - * - * @psalm-param array - * }> $addedFks - * @psalm-param array $blacklistedFks - * - * @throws NotSupported - */ - private function gatherRelationsSql( - ClassMetadata $class, - Table $table, - Schema $schema, - array &$addedFks, - array &$blacklistedFks, - ): void { - foreach ($class->associationMappings as $id => $mapping) { - if (isset($mapping->inherited) && ! in_array($id, $class->identifier, true)) { - continue; - } - - $foreignClass = $this->em->getClassMetadata($mapping->targetEntity); - - if ($mapping->isToOneOwningSide()) { - $primaryKeyColumns = []; // PK is unnecessary for this relation-type - - $this->gatherRelationJoinColumns( - $mapping->joinColumns, - $table, - $foreignClass, - $mapping, - $primaryKeyColumns, - $addedFks, - $blacklistedFks, - ); - } elseif ($mapping instanceof ManyToManyOwningSideMapping) { - // create join table - $joinTable = $mapping->joinTable; - - $theJoinTable = $schema->createTable( - $this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform), - ); - - foreach ($joinTable->options as $key => $val) { - $theJoinTable->addOption($key, $val); - } - - $primaryKeyColumns = []; - - // Build first FK constraint (relation table => source table) - $this->gatherRelationJoinColumns( - $joinTable->joinColumns, - $theJoinTable, - $class, - $mapping, - $primaryKeyColumns, - $addedFks, - $blacklistedFks, - ); - - // Build second FK constraint (relation table => target table) - $this->gatherRelationJoinColumns( - $joinTable->inverseJoinColumns, - $theJoinTable, - $foreignClass, - $mapping, - $primaryKeyColumns, - $addedFks, - $blacklistedFks, - ); - - $theJoinTable->setPrimaryKey($primaryKeyColumns); - } - } - } - - /** - * Gets the class metadata that is responsible for the definition of the referenced column name. - * - * Previously this was a simple task, but with DDC-117 this problem is actually recursive. If its - * not a simple field, go through all identifier field names that are associations recursively and - * find that referenced column name. - * - * TODO: Is there any way to make this code more pleasing? - * - * @psalm-return array{ClassMetadata, string}|null - */ - private function getDefiningClass(ClassMetadata $class, string $referencedColumnName): array|null - { - $referencedFieldName = $class->getFieldName($referencedColumnName); - - if ($class->hasField($referencedFieldName)) { - return [$class, $referencedFieldName]; - } - - if (in_array($referencedColumnName, $class->getIdentifierColumnNames(), true)) { - // it seems to be an entity as foreign key - foreach ($class->getIdentifierFieldNames() as $fieldName) { - if ( - $class->hasAssociation($fieldName) - && $class->getSingleAssociationJoinColumnName($fieldName) === $referencedColumnName - ) { - return $this->getDefiningClass( - $this->em->getClassMetadata($class->associationMappings[$fieldName]->targetEntity), - $class->getSingleAssociationReferencedJoinColumnName($fieldName), - ); - } - } - } - - return null; - } - - /** - * Gathers columns and fk constraints that are required for one part of relationship. - * - * @psalm-param list $joinColumns - * @psalm-param list $primaryKeyColumns - * @psalm-param array - * }> $addedFks - * @psalm-param array $blacklistedFks - * - * @throws MissingColumnException - */ - private function gatherRelationJoinColumns( - array $joinColumns, - Table $theJoinTable, - ClassMetadata $class, - AssociationMapping $mapping, - array &$primaryKeyColumns, - array &$addedFks, - array &$blacklistedFks, - ): void { - $localColumns = []; - $foreignColumns = []; - $fkOptions = []; - $foreignTableName = $this->quoteStrategy->getTableName($class, $this->platform); - $uniqueConstraints = []; - - foreach ($joinColumns as $joinColumn) { - [$definingClass, $referencedFieldName] = $this->getDefiningClass( - $class, - $joinColumn->referencedColumnName, - ); - - if (! $definingClass) { - throw MissingColumnException::fromColumnSourceAndTarget( - $joinColumn->referencedColumnName, - $mapping->sourceEntity, - $mapping->targetEntity, - ); - } - - $quotedColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); - $quotedRefColumnName = $this->quoteStrategy->getReferencedJoinColumnName( - $joinColumn, - $class, - $this->platform, - ); - - $primaryKeyColumns[] = $quotedColumnName; - $localColumns[] = $quotedColumnName; - $foreignColumns[] = $quotedRefColumnName; - - if (! $theJoinTable->hasColumn($quotedColumnName)) { - // Only add the column to the table if it does not exist already. - // It might exist already if the foreign key is mapped into a regular - // property as well. - - $fieldMapping = $definingClass->getFieldMapping($referencedFieldName); - - $columnOptions = ['notnull' => false]; - - if (isset($joinColumn->columnDefinition)) { - $columnOptions['columnDefinition'] = $joinColumn->columnDefinition; - } elseif (isset($fieldMapping->columnDefinition)) { - $columnOptions['columnDefinition'] = $fieldMapping->columnDefinition; - } - - if (isset($joinColumn->nullable)) { - $columnOptions['notnull'] = ! $joinColumn->nullable; - } - - $columnOptions += $this->gatherColumnOptions($fieldMapping); - - if (isset($fieldMapping->length)) { - $columnOptions['length'] = $fieldMapping->length; - } - - if ($fieldMapping->type === 'decimal') { - $columnOptions['scale'] = $fieldMapping->scale; - $columnOptions['precision'] = $fieldMapping->precision; - } - - $columnOptions = $this->gatherColumnOptions($joinColumn) + $columnOptions; - - $theJoinTable->addColumn($quotedColumnName, $fieldMapping->type, $columnOptions); - } - - if (isset($joinColumn->unique) && $joinColumn->unique === true) { - $uniqueConstraints[] = ['columns' => [$quotedColumnName]]; - } - - if (isset($joinColumn->onDelete)) { - $fkOptions['onDelete'] = $joinColumn->onDelete; - } - } - - // Prefer unique constraints over implicit simple indexes created for foreign keys. - // Also avoids index duplication. - foreach ($uniqueConstraints as $indexName => $unique) { - $theJoinTable->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); - } - - $compositeName = $theJoinTable->getName() . '.' . implode('', $localColumns); - if ( - isset($addedFks[$compositeName]) - && ($foreignTableName !== $addedFks[$compositeName]['foreignTableName'] - || 0 < count(array_diff($foreignColumns, $addedFks[$compositeName]['foreignColumns']))) - ) { - foreach ($theJoinTable->getForeignKeys() as $fkName => $key) { - if ( - count(array_diff($key->getLocalColumns(), $localColumns)) === 0 - && (($key->getForeignTableName() !== $foreignTableName) - || 0 < count(array_diff($key->getForeignColumns(), $foreignColumns))) - ) { - $theJoinTable->removeForeignKey($fkName); - break; - } - } - - $blacklistedFks[$compositeName] = true; - } elseif (! isset($blacklistedFks[$compositeName])) { - $addedFks[$compositeName] = ['foreignTableName' => $foreignTableName, 'foreignColumns' => $foreignColumns]; - $theJoinTable->addForeignKeyConstraint( - $foreignTableName, - $localColumns, - $foreignColumns, - $fkOptions, - ); - } - } - - /** @return mixed[] */ - private function gatherColumnOptions(JoinColumnMapping|FieldMapping|DiscriminatorColumnMapping $mapping): array - { - $mappingOptions = $mapping->options ?? []; - - if (isset($mapping->enumType)) { - $mappingOptions['enumType'] = $mapping->enumType; - } - - if (($mappingOptions['default'] ?? null) instanceof BackedEnum) { - $mappingOptions['default'] = $mappingOptions['default']->value; - } - - if (empty($mappingOptions)) { - return []; - } - - $options = array_intersect_key($mappingOptions, array_flip(self::KNOWN_COLUMN_OPTIONS)); - $options['platformOptions'] = array_diff_key($mappingOptions, $options); - - return $options; - } - - /** - * Drops the database schema for the given classes. - * - * In any way when an exception is thrown it is suppressed since drop was - * issued for all classes of the schema and some probably just don't exist. - * - * @psalm-param list $classes - */ - public function dropSchema(array $classes): void - { - $dropSchemaSql = $this->getDropSchemaSQL($classes); - $conn = $this->em->getConnection(); - - foreach ($dropSchemaSql as $sql) { - try { - $conn->executeStatement($sql); - } catch (Throwable) { - // ignored - } - } - } - - /** - * Drops all elements in the database of the current connection. - */ - public function dropDatabase(): void - { - $dropSchemaSql = $this->getDropDatabaseSQL(); - $conn = $this->em->getConnection(); - - foreach ($dropSchemaSql as $sql) { - $conn->executeStatement($sql); - } - } - - /** - * Gets the SQL needed to drop the database schema for the connections database. - * - * @return list - */ - public function getDropDatabaseSQL(): array - { - return $this->schemaManager - ->introspectSchema() - ->toDropSql($this->platform); - } - - /** - * Gets SQL to drop the tables defined by the passed classes. - * - * @psalm-param list $classes - * - * @return list - */ - public function getDropSchemaSQL(array $classes): array - { - $schema = $this->getSchemaFromMetadata($classes); - - $deployedSchema = $this->schemaManager->introspectSchema(); - - foreach ($schema->getTables() as $table) { - if (! $deployedSchema->hasTable($table->getName())) { - $schema->dropTable($table->getName()); - } - } - - if ($this->platform->supportsSequences()) { - foreach ($schema->getSequences() as $sequence) { - if (! $deployedSchema->hasSequence($sequence->getName())) { - $schema->dropSequence($sequence->getName()); - } - } - - foreach ($schema->getTables() as $table) { - $primaryKey = $table->getPrimaryKey(); - if ($primaryKey === null) { - continue; - } - - $columns = $primaryKey->getColumns(); - if (count($columns) === 1) { - $checkSequence = $table->getName() . '_' . $columns[0] . '_seq'; - if ($deployedSchema->hasSequence($checkSequence) && ! $schema->hasSequence($checkSequence)) { - $schema->createSequence($checkSequence); - } - } - } - } - - return $schema->toDropSql($this->platform); - } - - /** - * Updates the database schema of the given classes by comparing the ClassMetadata - * instances to the current database schema that is inspected. - * - * @param mixed[] $classes - */ - public function updateSchema(array $classes): void - { - $conn = $this->em->getConnection(); - - foreach ($this->getUpdateSchemaSql($classes) as $sql) { - $conn->executeStatement($sql); - } - } - - /** - * Gets the sequence of SQL statements that need to be performed in order - * to bring the given class mappings in-synch with the relational schema. - * - * @param list $classes The classes to consider. - * - * @return list The sequence of SQL statements. - */ - public function getUpdateSchemaSql(array $classes): array - { - $toSchema = $this->getSchemaFromMetadata($classes); - $fromSchema = $this->createSchemaForComparison($toSchema); - $comparator = $this->schemaManager->createComparator(); - $schemaDiff = $comparator->compareSchemas($fromSchema, $toSchema); - - return $this->platform->getAlterSchemaSQL($schemaDiff); - } - - /** - * Creates the schema from the database, ensuring tables from the target schema are whitelisted for comparison. - */ - private function createSchemaForComparison(Schema $toSchema): Schema - { - $connection = $this->em->getConnection(); - - // backup schema assets filter - $config = $connection->getConfiguration(); - $previousFilter = $config->getSchemaAssetsFilter(); - - if ($previousFilter === null) { - return $this->schemaManager->introspectSchema(); - } - - // whitelist assets we already know about in $toSchema, use the existing filter otherwise - $config->setSchemaAssetsFilter(static function ($asset) use ($previousFilter, $toSchema): bool { - $assetName = $asset instanceof AbstractAsset ? $asset->getName() : $asset; - - return $toSchema->hasTable($assetName) || $toSchema->hasSequence($assetName) || $previousFilter($asset); - }); - - try { - return $this->schemaManager->introspectSchema(); - } finally { - // restore schema assets filter - $config->setSchemaAssetsFilter($previousFilter); - } - } -} diff --git a/vendor/doctrine/orm/src/Tools/SchemaValidator.php b/vendor/doctrine/orm/src/Tools/SchemaValidator.php deleted file mode 100644 index fdfc003..0000000 --- a/vendor/doctrine/orm/src/Tools/SchemaValidator.php +++ /dev/null @@ -1,443 +0,0 @@ - ['string'], - BigIntType::class => ['int', 'string'], - BooleanType::class => ['bool'], - DecimalType::class => ['string'], - FloatType::class => ['float'], - GuidType::class => ['string'], - IntegerType::class => ['int'], - JsonType::class => ['array'], - SimpleArrayType::class => ['array'], - SmallIntType::class => ['int'], - StringType::class => ['string'], - TextType::class => ['string'], - ]; - - public function __construct( - private readonly EntityManagerInterface $em, - private readonly bool $validatePropertyTypes = true, - ) { - } - - /** - * Checks the internal consistency of all mapping files. - * - * There are several checks that can't be done at runtime or are too expensive, which can be verified - * with this command. For example: - * - * 1. Check if a relation with "mappedBy" is actually connected to that specified field. - * 2. Check if "mappedBy" and "inversedBy" are consistent to each other. - * 3. Check if "referencedColumnName" attributes are really pointing to primary key columns. - * - * @psalm-return array> - */ - public function validateMapping(): array - { - $errors = []; - $cmf = $this->em->getMetadataFactory(); - $classes = $cmf->getAllMetadata(); - - foreach ($classes as $class) { - $ce = $this->validateClass($class); - if ($ce) { - $errors[$class->name] = $ce; - } - } - - return $errors; - } - - /** - * Validates a single class of the current. - * - * @return string[] - * @psalm-return list - */ - public function validateClass(ClassMetadata $class): array - { - $ce = []; - $cmf = $this->em->getMetadataFactory(); - - foreach ($class->fieldMappings as $fieldName => $mapping) { - if (! Type::hasType($mapping->type)) { - $ce[] = "The field '" . $class->name . '#' . $fieldName . "' uses a non-existent type '" . $mapping->type . "'."; - } - } - - if ($this->validatePropertyTypes) { - array_push($ce, ...$this->validatePropertiesTypes($class)); - } - - foreach ($class->associationMappings as $fieldName => $assoc) { - if (! class_exists($assoc->targetEntity) || $cmf->isTransient($assoc->targetEntity)) { - $ce[] = "The target entity '" . $assoc->targetEntity . "' specified on " . $class->name . '#' . $fieldName . ' is unknown or not an entity.'; - - return $ce; - } - - $targetMetadata = $cmf->getMetadataFor($assoc->targetEntity); - - if ($targetMetadata->isMappedSuperclass) { - $ce[] = "The target entity '" . $assoc->targetEntity . "' specified on " . $class->name . '#' . $fieldName . ' is a mapped superclass. This is not possible since there is no table that a foreign key could refer to.'; - - return $ce; - } - - if (isset($assoc->id) && $targetMetadata->containsForeignIdentifier) { - $ce[] = "Cannot map association '" . $class->name . '#' . $fieldName . ' as identifier, because ' . - "the target entity '" . $targetMetadata->name . "' also maps an association as identifier."; - } - - if (! $assoc->isOwningSide()) { - if ($targetMetadata->hasField($assoc->mappedBy)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' refers to the owning side ' . - 'field ' . $assoc->targetEntity . '#' . $assoc->mappedBy . ' which is not defined as association, but as field.'; - } - - if (! $targetMetadata->hasAssociation($assoc->mappedBy)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' refers to the owning side ' . - 'field ' . $assoc->targetEntity . '#' . $assoc->mappedBy . ' which does not exist.'; - } elseif ($targetMetadata->associationMappings[$assoc->mappedBy]->inversedBy === null) { - $ce[] = 'The field ' . $class->name . '#' . $fieldName . ' is on the inverse side of a ' . - 'bi-directional relationship, but the specified mappedBy association on the target-entity ' . - $assoc->targetEntity . '#' . $assoc->mappedBy . ' does not contain the required ' . - "'inversedBy=\"" . $fieldName . "\"' attribute."; - } elseif ($targetMetadata->associationMappings[$assoc->mappedBy]->inversedBy !== $fieldName) { - $ce[] = 'The mappings ' . $class->name . '#' . $fieldName . ' and ' . - $assoc->targetEntity . '#' . $assoc->mappedBy . ' are ' . - 'inconsistent with each other.'; - } - } - - if ($assoc->isOwningSide() && $assoc->inversedBy !== null) { - if ($targetMetadata->hasField($assoc->inversedBy)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' refers to the inverse side ' . - 'field ' . $assoc->targetEntity . '#' . $assoc->inversedBy . ' which is not defined as association.'; - } - - if (! $targetMetadata->hasAssociation($assoc->inversedBy)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' refers to the inverse side ' . - 'field ' . $assoc->targetEntity . '#' . $assoc->inversedBy . ' which does not exist.'; - } elseif ($targetMetadata->associationMappings[$assoc->inversedBy]->isOwningSide()) { - $ce[] = 'The field ' . $class->name . '#' . $fieldName . ' is on the owning side of a ' . - 'bi-directional relationship, but the specified inversedBy association on the target-entity ' . - $assoc->targetEntity . '#' . $assoc->inversedBy . ' does not contain the required ' . - "'mappedBy=\"" . $fieldName . "\"' attribute."; - } elseif ($targetMetadata->associationMappings[$assoc->inversedBy]->mappedBy !== $fieldName) { - $ce[] = 'The mappings ' . $class->name . '#' . $fieldName . ' and ' . - $assoc->targetEntity . '#' . $assoc->inversedBy . ' are ' . - 'inconsistent with each other.'; - } - - // Verify inverse side/owning side match each other - if (array_key_exists($assoc->inversedBy, $targetMetadata->associationMappings)) { - $targetAssoc = $targetMetadata->associationMappings[$assoc->inversedBy]; - if ($assoc->isOneToOne() && ! $targetAssoc->isOneToOne()) { - $ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is one-to-one, then the inversed ' . - 'side ' . $targetMetadata->name . '#' . $assoc->inversedBy . ' has to be one-to-one as well.'; - } elseif ($assoc->isManyToOne() && ! $targetAssoc->isOneToMany()) { - $ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is many-to-one, then the inversed ' . - 'side ' . $targetMetadata->name . '#' . $assoc->inversedBy . ' has to be one-to-many.'; - } elseif ($assoc->isManyToMany() && ! $targetAssoc->isManyToMany()) { - $ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is many-to-many, then the inversed ' . - 'side ' . $targetMetadata->name . '#' . $assoc->inversedBy . ' has to be many-to-many as well.'; - } - } - } - - if ($assoc->isOwningSide()) { - if ($assoc->isManyToManyOwningSide()) { - $identifierColumns = $class->getIdentifierColumnNames(); - foreach ($assoc->joinTable->joinColumns as $joinColumn) { - if (! in_array($joinColumn->referencedColumnName, $identifierColumns, true)) { - $ce[] = "The referenced column name '" . $joinColumn->referencedColumnName . "' " . - "has to be a primary key column on the target entity class '" . $class->name . "'."; - break; - } - } - - $identifierColumns = $targetMetadata->getIdentifierColumnNames(); - foreach ($assoc->joinTable->inverseJoinColumns as $inverseJoinColumn) { - if (! in_array($inverseJoinColumn->referencedColumnName, $identifierColumns, true)) { - $ce[] = "The referenced column name '" . $inverseJoinColumn->referencedColumnName . "' " . - "has to be a primary key column on the target entity class '" . $targetMetadata->name . "'."; - break; - } - } - - if (count($targetMetadata->getIdentifierColumnNames()) !== count($assoc->joinTable->inverseJoinColumns)) { - $ce[] = "The inverse join columns of the many-to-many table '" . $assoc->joinTable->name . "' " . - "have to contain to ALL identifier columns of the target entity '" . $targetMetadata->name . "', " . - "however '" . implode(', ', array_diff($targetMetadata->getIdentifierColumnNames(), array_values($assoc->relationToTargetKeyColumns))) . - "' are missing."; - } - - if (count($class->getIdentifierColumnNames()) !== count($assoc->joinTable->joinColumns)) { - $ce[] = "The join columns of the many-to-many table '" . $assoc->joinTable->name . "' " . - "have to contain to ALL identifier columns of the source entity '" . $class->name . "', " . - "however '" . implode(', ', array_diff($class->getIdentifierColumnNames(), array_values($assoc->relationToSourceKeyColumns))) . - "' are missing."; - } - } elseif ($assoc->isToOneOwningSide()) { - $identifierColumns = $targetMetadata->getIdentifierColumnNames(); - foreach ($assoc->joinColumns as $joinColumn) { - if (! in_array($joinColumn->referencedColumnName, $identifierColumns, true)) { - $ce[] = "The referenced column name '" . $joinColumn->referencedColumnName . "' " . - "has to be a primary key column on the target entity class '" . $targetMetadata->name . "'."; - } - } - - if (count($identifierColumns) !== count($assoc->joinColumns)) { - $ids = []; - - foreach ($assoc->joinColumns as $joinColumn) { - $ids[] = $joinColumn->name; - } - - $ce[] = "The join columns of the association '" . $assoc->fieldName . "' " . - "have to match to ALL identifier columns of the target entity '" . $targetMetadata->name . "', " . - "however '" . implode(', ', array_diff($targetMetadata->getIdentifierColumnNames(), $ids)) . - "' are missing."; - } - } - } - - if ($assoc->isOrdered()) { - foreach ($assoc->orderBy() as $orderField => $orientation) { - if (! $targetMetadata->hasField($orderField) && ! $targetMetadata->hasAssociation($orderField)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' is ordered by a foreign field ' . - $orderField . ' that is not a field on the target entity ' . $targetMetadata->name . '.'; - continue; - } - - if ($targetMetadata->isCollectionValuedAssociation($orderField)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' is ordered by a field ' . - $orderField . ' on ' . $targetMetadata->name . ' that is a collection-valued association.'; - continue; - } - - if ($targetMetadata->isAssociationInverseSide($orderField)) { - $ce[] = 'The association ' . $class->name . '#' . $fieldName . ' is ordered by a field ' . - $orderField . ' on ' . $targetMetadata->name . ' that is the inverse side of an association.'; - continue; - } - } - } - } - - if ( - ! $class->isInheritanceTypeNone() - && ! $class->isRootEntity() - && ($class->reflClass !== null && ! $class->reflClass->isAbstract()) - && ! $class->isMappedSuperclass - && array_search($class->name, $class->discriminatorMap, true) === false - ) { - $ce[] = "Entity class '" . $class->name . "' is part of inheritance hierarchy, but is " . - "not mapped in the root entity '" . $class->rootEntityName . "' discriminator map. " . - 'All subclasses must be listed in the discriminator map.'; - } - - foreach ($class->subClasses as $subClass) { - if (! in_array($class->name, class_parents($subClass), true)) { - $ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child " . - "of '" . $class->name . "' but these entities are not related through inheritance."; - } - } - - return $ce; - } - - /** - * Checks if the Database Schema is in sync with the current metadata state. - */ - public function schemaInSyncWithMetadata(): bool - { - return count($this->getUpdateSchemaList()) === 0; - } - - /** - * Returns the list of missing Database Schema updates. - * - * @return array - */ - public function getUpdateSchemaList(): array - { - $schemaTool = new SchemaTool($this->em); - - $allMetadata = $this->em->getMetadataFactory()->getAllMetadata(); - - return $schemaTool->getUpdateSchemaSql($allMetadata); - } - - /** @return list containing the found issues */ - private function validatePropertiesTypes(ClassMetadata $class): array - { - return array_values( - array_filter( - array_map( - function (FieldMapping $fieldMapping) use ($class): string|null { - $fieldName = $fieldMapping->fieldName; - assert(isset($class->reflFields[$fieldName])); - $propertyType = $class->reflFields[$fieldName]->getType(); - - // If the field type is not a built-in type, we cannot check it - if (! Type::hasType($fieldMapping->type)) { - return null; - } - - // If the property type is not a named type, we cannot check it - if (! ($propertyType instanceof ReflectionNamedType) || $propertyType->getName() === 'mixed') { - return null; - } - - $metadataFieldType = $this->findBuiltInType(Type::getType($fieldMapping->type)); - - //If the metadata field type is not a mapped built-in type, we cannot check it - if ($metadataFieldType === null) { - return null; - } - - $propertyType = $propertyType->getName(); - - // If the property type is the same as the metadata field type, we are ok - if (in_array($propertyType, $metadataFieldType, true)) { - return null; - } - - if (is_a($propertyType, BackedEnum::class, true)) { - $backingType = (string) (new ReflectionEnum($propertyType))->getBackingType(); - - if (! in_array($backingType, $metadataFieldType, true)) { - return sprintf( - "The field '%s#%s' has the property type '%s' with a backing type of '%s' that differs from the metadata field type '%s'.", - $class->name, - $fieldName, - $propertyType, - $backingType, - implode('|', $metadataFieldType), - ); - } - - if (! isset($fieldMapping->enumType) || $propertyType === $fieldMapping->enumType) { - return null; - } - - return sprintf( - "The field '%s#%s' has the property type '%s' that differs from the metadata enumType '%s'.", - $class->name, - $fieldName, - $propertyType, - $fieldMapping->enumType, - ); - } - - if ( - isset($fieldMapping->enumType) - && $propertyType !== $fieldMapping->enumType - && interface_exists($propertyType) - && is_a($fieldMapping->enumType, $propertyType, true) - ) { - $backingType = (string) (new ReflectionEnum($fieldMapping->enumType))->getBackingType(); - - if (in_array($backingType, $metadataFieldType, true)) { - return null; - } - - return sprintf( - "The field '%s#%s' has the metadata enumType '%s' with a backing type of '%s' that differs from the metadata field type '%s'.", - $class->name, - $fieldName, - $fieldMapping->enumType, - $backingType, - implode('|', $metadataFieldType), - ); - } - - if ( - $fieldMapping->type === 'json' - && in_array($propertyType, ['string', 'int', 'float', 'bool', 'true', 'false', 'null'], true) - ) { - return null; - } - - return sprintf( - "The field '%s#%s' has the property type '%s' that differs from the metadata field type '%s' returned by the '%s' DBAL type.", - $class->name, - $fieldName, - $propertyType, - implode('|', $metadataFieldType), - $fieldMapping->type, - ); - }, - $class->fieldMappings, - ), - ), - ); - } - - /** - * The exact DBAL type must be used (no subclasses), since consumers of doctrine/orm may have their own - * customization around field types. - * - * @return list|null - */ - private function findBuiltInType(Type $type): array|null - { - $typeName = $type::class; - - return self::BUILTIN_TYPES_MAP[$typeName] ?? null; - } -} diff --git a/vendor/doctrine/orm/src/Tools/ToolEvents.php b/vendor/doctrine/orm/src/Tools/ToolEvents.php deleted file mode 100644 index fac37fa..0000000 --- a/vendor/doctrine/orm/src/Tools/ToolEvents.php +++ /dev/null @@ -1,23 +0,0 @@ -getMessage() . "' while executing DDL: " . $sql, - 0, - $e, - ); - } -} diff --git a/vendor/doctrine/orm/src/TransactionRequiredException.php b/vendor/doctrine/orm/src/TransactionRequiredException.php deleted file mode 100644 index 6114544..0000000 --- a/vendor/doctrine/orm/src/TransactionRequiredException.php +++ /dev/null @@ -1,21 +0,0 @@ -> - */ - private array $identityMap = []; - - /** - * Map of all identifiers of managed entities. - * Keys are object ids (spl_object_id). - * - * @psalm-var array> - */ - private array $entityIdentifiers = []; - - /** - * Map of the original entity data of managed entities. - * Keys are object ids (spl_object_id). This is used for calculating changesets - * at commit time. - * - * Internal note: Note that PHPs "copy-on-write" behavior helps a lot with memory usage. - * A value will only really be copied if the value in the entity is modified - * by the user. - * - * @psalm-var array> - */ - private array $originalEntityData = []; - - /** - * Map of entity changes. Keys are object ids (spl_object_id). - * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end. - * - * @psalm-var array> - */ - private array $entityChangeSets = []; - - /** - * The (cached) states of any known entities. - * Keys are object ids (spl_object_id). - * - * @psalm-var array - */ - private array $entityStates = []; - - /** - * Map of entities that are scheduled for dirty checking at commit time. - * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT. - * Keys are object ids (spl_object_id). - * - * @psalm-var array> - */ - private array $scheduledForSynchronization = []; - - /** - * A list of all pending entity insertions. - * - * @psalm-var array - */ - private array $entityInsertions = []; - - /** - * A list of all pending entity updates. - * - * @psalm-var array - */ - private array $entityUpdates = []; - - /** - * Any pending extra updates that have been scheduled by persisters. - * - * @psalm-var array}> - */ - private array $extraUpdates = []; - - /** - * A list of all pending entity deletions. - * - * @psalm-var array - */ - private array $entityDeletions = []; - - /** - * New entities that were discovered through relationships that were not - * marked as cascade-persist. During flush, this array is populated and - * then pruned of any entities that were discovered through a valid - * cascade-persist path. (Leftovers cause an error.) - * - * Keys are OIDs, payload is a two-item array describing the association - * and the entity. - * - * @var array indexed by respective object spl_object_id() - */ - private array $nonCascadedNewDetectedEntities = []; - - /** - * All pending collection deletions. - * - * @psalm-var array> - */ - private array $collectionDeletions = []; - - /** - * All pending collection updates. - * - * @psalm-var array> - */ - private array $collectionUpdates = []; - - /** - * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork. - * At the end of the UnitOfWork all these collections will make new snapshots - * of their data. - * - * @psalm-var array> - */ - private array $visitedCollections = []; - - /** - * List of collections visited during the changeset calculation that contain to-be-removed - * entities and need to have keys removed post commit. - * - * Indexed by Collection object ID, which also serves as the key in self::$visitedCollections; - * values are the key names that need to be removed. - * - * @psalm-var array> - */ - private array $pendingCollectionElementRemovals = []; - - /** - * The entity persister instances used to persist entity instances. - * - * @psalm-var array - */ - private array $persisters = []; - - /** - * The collection persister instances used to persist collections. - * - * @psalm-var array - */ - private array $collectionPersisters = []; - - /** - * The EventManager used for dispatching events. - */ - private readonly EventManager $evm; - - /** - * The ListenersInvoker used for dispatching events. - */ - private readonly ListenersInvoker $listenersInvoker; - - /** - * The IdentifierFlattener used for manipulating identifiers - */ - private readonly IdentifierFlattener $identifierFlattener; - - /** - * Orphaned entities that are scheduled for removal. - * - * @psalm-var array - */ - private array $orphanRemovals = []; - - /** - * Read-Only objects are never evaluated - * - * @var array - */ - private array $readOnlyObjects = []; - - /** - * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested. - * - * @psalm-var array> - */ - private array $eagerLoadingEntities = []; - - /** @var array> */ - private array $eagerLoadingCollections = []; - - protected bool $hasCache = false; - - /** - * Helper for handling completion of hydration - */ - private readonly HydrationCompleteHandler $hydrationCompleteHandler; - - /** - * Initializes a new UnitOfWork instance, bound to the given EntityManager. - * - * @param EntityManagerInterface $em The EntityManager that "owns" this UnitOfWork instance. - */ - public function __construct( - private readonly EntityManagerInterface $em, - ) { - $this->evm = $em->getEventManager(); - $this->listenersInvoker = new ListenersInvoker($em); - $this->hasCache = $em->getConfiguration()->isSecondLevelCacheEnabled(); - $this->identifierFlattener = new IdentifierFlattener($this, $em->getMetadataFactory()); - $this->hydrationCompleteHandler = new HydrationCompleteHandler($this->listenersInvoker, $em); - } - - /** - * Commits the UnitOfWork, executing all operations that have been postponed - * up to this point. The state of all managed entities will be synchronized with - * the database. - * - * The operations are executed in the following order: - * - * 1) All entity insertions - * 2) All entity updates - * 3) All collection deletions - * 4) All collection updates - * 5) All entity deletions - * - * @throws Exception - */ - public function commit(): void - { - $connection = $this->em->getConnection(); - - if ($connection instanceof PrimaryReadReplicaConnection) { - $connection->ensureConnectedToPrimary(); - } - - // Raise preFlush - if ($this->evm->hasListeners(Events::preFlush)) { - $this->evm->dispatchEvent(Events::preFlush, new PreFlushEventArgs($this->em)); - } - - // Compute changes done since last commit. - $this->computeChangeSets(); - - if ( - ! ($this->entityInsertions || - $this->entityDeletions || - $this->entityUpdates || - $this->collectionUpdates || - $this->collectionDeletions || - $this->orphanRemovals) - ) { - $this->dispatchOnFlushEvent(); - $this->dispatchPostFlushEvent(); - - $this->postCommitCleanup(); - - return; // Nothing to do. - } - - $this->assertThatThereAreNoUnintentionallyNonPersistedAssociations(); - - if ($this->orphanRemovals) { - foreach ($this->orphanRemovals as $orphan) { - $this->remove($orphan); - } - } - - $this->dispatchOnFlushEvent(); - - $conn = $this->em->getConnection(); - $conn->beginTransaction(); - - try { - // Collection deletions (deletions of complete collections) - foreach ($this->collectionDeletions as $collectionToDelete) { - // Deferred explicit tracked collections can be removed only when owning relation was persisted - $owner = $collectionToDelete->getOwner(); - - if ($this->em->getClassMetadata($owner::class)->isChangeTrackingDeferredImplicit() || $this->isScheduledForDirtyCheck($owner)) { - $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete); - } - } - - if ($this->entityInsertions) { - // Perform entity insertions first, so that all new entities have their rows in the database - // and can be referred to by foreign keys. The commit order only needs to take new entities - // into account (new entities referring to other new entities), since all other types (entities - // with updates or scheduled deletions) are currently not a problem, since they are already - // in the database. - $this->executeInserts(); - } - - if ($this->entityUpdates) { - // Updates do not need to follow a particular order - $this->executeUpdates(); - } - - // Extra updates that were requested by persisters. - // This may include foreign keys that could not be set when an entity was inserted, - // which may happen in the case of circular foreign key relationships. - if ($this->extraUpdates) { - $this->executeExtraUpdates(); - } - - // Collection updates (deleteRows, updateRows, insertRows) - // No particular order is necessary, since all entities themselves are already - // in the database - foreach ($this->collectionUpdates as $collectionToUpdate) { - $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate); - } - - // Entity deletions come last. Their order only needs to take care of other deletions - // (first delete entities depending upon others, before deleting depended-upon entities). - if ($this->entityDeletions) { - $this->executeDeletions(); - } - - $commitFailed = false; - try { - if ($conn->commit() === false) { - $commitFailed = true; - } - } catch (DBAL\Exception $e) { - $commitFailed = true; - } - - if ($commitFailed) { - throw new OptimisticLockException('Commit failed', null, $e ?? null); - } - } catch (Throwable $e) { - $this->em->close(); - - if ($conn->isTransactionActive()) { - $conn->rollBack(); - } - - $this->afterTransactionRolledBack(); - - throw $e; - } - - $this->afterTransactionComplete(); - - // Unset removed entities from collections, and take new snapshots from - // all visited collections. - foreach ($this->visitedCollections as $coid => $coll) { - if (isset($this->pendingCollectionElementRemovals[$coid])) { - foreach ($this->pendingCollectionElementRemovals[$coid] as $key => $valueIgnored) { - unset($coll[$key]); - } - } - - $coll->takeSnapshot(); - } - - $this->dispatchPostFlushEvent(); - - $this->postCommitCleanup(); - } - - private function postCommitCleanup(): void - { - $this->entityInsertions = - $this->entityUpdates = - $this->entityDeletions = - $this->extraUpdates = - $this->collectionUpdates = - $this->nonCascadedNewDetectedEntities = - $this->collectionDeletions = - $this->pendingCollectionElementRemovals = - $this->visitedCollections = - $this->orphanRemovals = - $this->entityChangeSets = - $this->scheduledForSynchronization = []; - } - - /** - * Computes the changesets of all entities scheduled for insertion. - */ - private function computeScheduleInsertsChangeSets(): void - { - foreach ($this->entityInsertions as $entity) { - $class = $this->em->getClassMetadata($entity::class); - - $this->computeChangeSet($class, $entity); - } - } - - /** - * Executes any extra updates that have been scheduled. - */ - private function executeExtraUpdates(): void - { - foreach ($this->extraUpdates as $oid => $update) { - [$entity, $changeset] = $update; - - $this->entityChangeSets[$oid] = $changeset; - $this->getEntityPersister($entity::class)->update($entity); - } - - $this->extraUpdates = []; - } - - /** - * Gets the changeset for an entity. - * - * @return mixed[][] - * @psalm-return array - */ - public function & getEntityChangeSet(object $entity): array - { - $oid = spl_object_id($entity); - $data = []; - - if (! isset($this->entityChangeSets[$oid])) { - return $data; - } - - return $this->entityChangeSets[$oid]; - } - - /** - * Computes the changes that happened to a single entity. - * - * Modifies/populates the following properties: - * - * {@link _originalEntityData} - * If the entity is NEW or MANAGED but not yet fully persisted (only has an id) - * then it was not fetched from the database and therefore we have no original - * entity data yet. All of the current entity data is stored as the original entity data. - * - * {@link _entityChangeSets} - * The changes detected on all properties of the entity are stored there. - * A change is a tuple array where the first entry is the old value and the second - * entry is the new value of the property. Changesets are used by persisters - * to INSERT/UPDATE the persistent entity state. - * - * {@link _entityUpdates} - * If the entity is already fully MANAGED (has been fetched from the database before) - * and any changes to its properties are detected, then a reference to the entity is stored - * there to mark it for an update. - * - * {@link _collectionDeletions} - * If a PersistentCollection has been de-referenced in a fully MANAGED entity, - * then this collection is marked for deletion. - * - * @param ClassMetadata $class The class descriptor of the entity. - * @param object $entity The entity for which to compute the changes. - * @psalm-param ClassMetadata $class - * @psalm-param T $entity - * - * @template T of object - * - * @ignore - */ - public function computeChangeSet(ClassMetadata $class, object $entity): void - { - $oid = spl_object_id($entity); - - if (isset($this->readOnlyObjects[$oid])) { - return; - } - - if (! $class->isInheritanceTypeNone()) { - $class = $this->em->getClassMetadata($entity::class); - } - - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush) & ~ListenersInvoker::INVOKE_MANAGER; - - if ($invoke !== ListenersInvoker::INVOKE_NONE) { - $this->listenersInvoker->invoke($class, Events::preFlush, $entity, new PreFlushEventArgs($this->em), $invoke); - } - - $actualData = []; - - foreach ($class->reflFields as $name => $refProp) { - $value = $refProp->getValue($entity); - - if ($class->isCollectionValuedAssociation($name) && $value !== null) { - if ($value instanceof PersistentCollection) { - if ($value->getOwner() === $entity) { - $actualData[$name] = $value; - continue; - } - - $value = new ArrayCollection($value->getValues()); - } - - // If $value is not a Collection then use an ArrayCollection. - if (! $value instanceof Collection) { - $value = new ArrayCollection($value); - } - - $assoc = $class->associationMappings[$name]; - assert($assoc->isToMany()); - - // Inject PersistentCollection - $value = new PersistentCollection( - $this->em, - $this->em->getClassMetadata($assoc->targetEntity), - $value, - ); - $value->setOwner($entity, $assoc); - $value->setDirty(! $value->isEmpty()); - - $refProp->setValue($entity, $value); - - $actualData[$name] = $value; - - continue; - } - - if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) { - $actualData[$name] = $value; - } - } - - if (! isset($this->originalEntityData[$oid])) { - // Entity is either NEW or MANAGED but not yet fully persisted (only has an id). - // These result in an INSERT. - $this->originalEntityData[$oid] = $actualData; - $changeSet = []; - - foreach ($actualData as $propName => $actualValue) { - if (! isset($class->associationMappings[$propName])) { - $changeSet[$propName] = [null, $actualValue]; - - continue; - } - - $assoc = $class->associationMappings[$propName]; - - if ($assoc->isToOneOwningSide()) { - $changeSet[$propName] = [null, $actualValue]; - } - } - - $this->entityChangeSets[$oid] = $changeSet; - } else { - // Entity is "fully" MANAGED: it was already fully persisted before - // and we have a copy of the original data - $originalData = $this->originalEntityData[$oid]; - $changeSet = []; - - foreach ($actualData as $propName => $actualValue) { - // skip field, its a partially omitted one! - if (! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) { - continue; - } - - $orgValue = $originalData[$propName]; - - if (! empty($class->fieldMappings[$propName]->enumType)) { - if (is_array($orgValue)) { - foreach ($orgValue as $id => $val) { - if ($val instanceof BackedEnum) { - $orgValue[$id] = $val->value; - } - } - } else { - if ($orgValue instanceof BackedEnum) { - $orgValue = $orgValue->value; - } - } - } - - // skip if value haven't changed - if ($orgValue === $actualValue) { - continue; - } - - // if regular field - if (! isset($class->associationMappings[$propName])) { - $changeSet[$propName] = [$orgValue, $actualValue]; - - continue; - } - - $assoc = $class->associationMappings[$propName]; - - // Persistent collection was exchanged with the "originally" - // created one. This can only mean it was cloned and replaced - // on another entity. - if ($actualValue instanceof PersistentCollection) { - assert($assoc->isToMany()); - $owner = $actualValue->getOwner(); - if ($owner === null) { // cloned - $actualValue->setOwner($entity, $assoc); - } elseif ($owner !== $entity) { // no clone, we have to fix - if (! $actualValue->isInitialized()) { - $actualValue->initialize(); // we have to do this otherwise the cols share state - } - - $newValue = clone $actualValue; - $newValue->setOwner($entity, $assoc); - $class->reflFields[$propName]->setValue($entity, $newValue); - } - } - - if ($orgValue instanceof PersistentCollection) { - // A PersistentCollection was de-referenced, so delete it. - $coid = spl_object_id($orgValue); - - if (isset($this->collectionDeletions[$coid])) { - continue; - } - - $this->collectionDeletions[$coid] = $orgValue; - $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored. - - continue; - } - - if ($assoc->isToOne()) { - if ($assoc->isOwningSide()) { - $changeSet[$propName] = [$orgValue, $actualValue]; - } - - if ($orgValue !== null && $assoc->orphanRemoval) { - assert(is_object($orgValue)); - $this->scheduleOrphanRemoval($orgValue); - } - } - } - - if ($changeSet) { - $this->entityChangeSets[$oid] = $changeSet; - $this->originalEntityData[$oid] = $actualData; - $this->entityUpdates[$oid] = $entity; - } - } - - // Look for changes in associations of the entity - foreach ($class->associationMappings as $field => $assoc) { - $val = $class->reflFields[$field]->getValue($entity); - if ($val === null) { - continue; - } - - $this->computeAssociationChanges($assoc, $val); - - if ( - ! isset($this->entityChangeSets[$oid]) && - $assoc->isManyToManyOwningSide() && - $val instanceof PersistentCollection && - $val->isDirty() - ) { - $this->entityChangeSets[$oid] = []; - $this->originalEntityData[$oid] = $actualData; - $this->entityUpdates[$oid] = $entity; - } - } - } - - /** - * Computes all the changes that have been done to entities and collections - * since the last commit and stores these changes in the _entityChangeSet map - * temporarily for access by the persisters, until the UoW commit is finished. - */ - public function computeChangeSets(): void - { - // Compute changes for INSERTed entities first. This must always happen. - $this->computeScheduleInsertsChangeSets(); - - // Compute changes for other MANAGED entities. Change tracking policies take effect here. - foreach ($this->identityMap as $className => $entities) { - $class = $this->em->getClassMetadata($className); - - // Skip class if instances are read-only - if ($class->isReadOnly) { - continue; - } - - $entitiesToProcess = match (true) { - $class->isChangeTrackingDeferredImplicit() => $entities, - isset($this->scheduledForSynchronization[$className]) => $this->scheduledForSynchronization[$className], - default => [], - }; - - foreach ($entitiesToProcess as $entity) { - // Ignore uninitialized proxy objects - if ($this->isUninitializedObject($entity)) { - continue; - } - - // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION OR DELETION are processed here. - $oid = spl_object_id($entity); - - if (! isset($this->entityInsertions[$oid]) && ! isset($this->entityDeletions[$oid]) && isset($this->entityStates[$oid])) { - $this->computeChangeSet($class, $entity); - } - } - } - } - - /** - * Computes the changes of an association. - * - * @param mixed $value The value of the association. - * - * @throws ORMInvalidArgumentException - * @throws ORMException - */ - private function computeAssociationChanges(AssociationMapping $assoc, mixed $value): void - { - if ($this->isUninitializedObject($value)) { - return; - } - - // If this collection is dirty, schedule it for updates - if ($value instanceof PersistentCollection && $value->isDirty()) { - $coid = spl_object_id($value); - - $this->collectionUpdates[$coid] = $value; - $this->visitedCollections[$coid] = $value; - } - - // Look through the entities, and in any of their associations, - // for transient (new) entities, recursively. ("Persistence by reachability") - // Unwrap. Uninitialized collections will simply be empty. - $unwrappedValue = $assoc->isToOne() ? [$value] : $value->unwrap(); - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - foreach ($unwrappedValue as $key => $entry) { - if (! ($entry instanceof $targetClass->name)) { - throw ORMInvalidArgumentException::invalidAssociation($targetClass, $assoc, $entry); - } - - $state = $this->getEntityState($entry, self::STATE_NEW); - - if (! ($entry instanceof $assoc->targetEntity)) { - throw UnexpectedAssociationValue::create( - $assoc->sourceEntity, - $assoc->fieldName, - get_debug_type($entry), - $assoc->targetEntity, - ); - } - - switch ($state) { - case self::STATE_NEW: - if (! $assoc->isCascadePersist()) { - /* - * For now just record the details, because this may - * not be an issue if we later discover another pathway - * through the object-graph where cascade-persistence - * is enabled for this object. - */ - $this->nonCascadedNewDetectedEntities[spl_object_id($entry)] = [$assoc, $entry]; - - break; - } - - $this->persistNew($targetClass, $entry); - $this->computeChangeSet($targetClass, $entry); - - break; - - case self::STATE_REMOVED: - // Consume the $value as array (it's either an array or an ArrayAccess) - // and remove the element from Collection. - if (! $assoc->isToMany()) { - break; - } - - $coid = spl_object_id($value); - $this->visitedCollections[$coid] = $value; - - if (! isset($this->pendingCollectionElementRemovals[$coid])) { - $this->pendingCollectionElementRemovals[$coid] = []; - } - - $this->pendingCollectionElementRemovals[$coid][$key] = true; - break; - - case self::STATE_DETACHED: - // Can actually not happen right now as we assume STATE_NEW, - // so the exception will be raised from the DBAL layer (constraint violation). - throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry); - - default: - // MANAGED associated entities are already taken into account - // during changeset calculation anyway, since they are in the identity map. - } - } - } - - /** - * @psalm-param ClassMetadata $class - * @psalm-param T $entity - * - * @template T of object - */ - private function persistNew(ClassMetadata $class, object $entity): void - { - $oid = spl_object_id($entity); - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::prePersist); - - if ($invoke !== ListenersInvoker::INVOKE_NONE) { - $this->listenersInvoker->invoke($class, Events::prePersist, $entity, new PrePersistEventArgs($entity, $this->em), $invoke); - } - - $idGen = $class->idGenerator; - - if (! $idGen->isPostInsertGenerator()) { - $idValue = $idGen->generateId($this->em, $entity); - - if (! $idGen instanceof AssignedGenerator) { - $idValue = [$class->getSingleIdentifierFieldName() => $this->convertSingleFieldIdentifierToPHPValue($class, $idValue)]; - - $class->setIdentifierValues($entity, $idValue); - } - - // Some identifiers may be foreign keys to new entities. - // In this case, we don't have the value yet and should treat it as if we have a post-insert generator - if (! $this->hasMissingIdsWhichAreForeignKeys($class, $idValue)) { - $this->entityIdentifiers[$oid] = $idValue; - } - } - - $this->entityStates[$oid] = self::STATE_MANAGED; - - $this->scheduleForInsert($entity); - } - - /** @param mixed[] $idValue */ - private function hasMissingIdsWhichAreForeignKeys(ClassMetadata $class, array $idValue): bool - { - foreach ($idValue as $idField => $idFieldValue) { - if ($idFieldValue === null && isset($class->associationMappings[$idField])) { - return true; - } - } - - return false; - } - - /** - * INTERNAL: - * Computes the changeset of an individual entity, independently of the - * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit(). - * - * The passed entity must be a managed entity. If the entity already has a change set - * because this method is invoked during a commit cycle then the change sets are added. - * whereby changes detected in this method prevail. - * - * @param ClassMetadata $class The class descriptor of the entity. - * @param object $entity The entity for which to (re)calculate the change set. - * @psalm-param ClassMetadata $class - * @psalm-param T $entity - * - * @throws ORMInvalidArgumentException If the passed entity is not MANAGED. - * - * @template T of object - * @ignore - */ - public function recomputeSingleEntityChangeSet(ClassMetadata $class, object $entity): void - { - $oid = spl_object_id($entity); - - if (! isset($this->entityStates[$oid]) || $this->entityStates[$oid] !== self::STATE_MANAGED) { - throw ORMInvalidArgumentException::entityNotManaged($entity); - } - - if (! $class->isInheritanceTypeNone()) { - $class = $this->em->getClassMetadata($entity::class); - } - - $actualData = []; - - foreach ($class->reflFields as $name => $refProp) { - if ( - ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) - && ($name !== $class->versionField) - && ! $class->isCollectionValuedAssociation($name) - ) { - $actualData[$name] = $refProp->getValue($entity); - } - } - - if (! isset($this->originalEntityData[$oid])) { - throw new RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.'); - } - - $originalData = $this->originalEntityData[$oid]; - $changeSet = []; - - foreach ($actualData as $propName => $actualValue) { - $orgValue = $originalData[$propName] ?? null; - - if (isset($class->fieldMappings[$propName]->enumType)) { - if (is_array($orgValue)) { - foreach ($orgValue as $id => $val) { - if ($val instanceof BackedEnum) { - $orgValue[$id] = $val->value; - } - } - } else { - if ($orgValue instanceof BackedEnum) { - $orgValue = $orgValue->value; - } - } - } - - if ($orgValue !== $actualValue) { - $changeSet[$propName] = [$orgValue, $actualValue]; - } - } - - if ($changeSet) { - if (isset($this->entityChangeSets[$oid])) { - $this->entityChangeSets[$oid] = [...$this->entityChangeSets[$oid], ...$changeSet]; - } elseif (! isset($this->entityInsertions[$oid])) { - $this->entityChangeSets[$oid] = $changeSet; - $this->entityUpdates[$oid] = $entity; - } - - $this->originalEntityData[$oid] = $actualData; - } - } - - /** - * Executes entity insertions - */ - private function executeInserts(): void - { - $entities = $this->computeInsertExecutionOrder(); - $eventsToDispatch = []; - - foreach ($entities as $entity) { - $oid = spl_object_id($entity); - $class = $this->em->getClassMetadata($entity::class); - $persister = $this->getEntityPersister($class->name); - - $persister->addInsert($entity); - - unset($this->entityInsertions[$oid]); - - $persister->executeInserts(); - - if (! isset($this->entityIdentifiers[$oid])) { - //entity was not added to identity map because some identifiers are foreign keys to new entities. - //add it now - $this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity); - } - - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist); - - if ($invoke !== ListenersInvoker::INVOKE_NONE) { - $eventsToDispatch[] = ['class' => $class, 'entity' => $entity, 'invoke' => $invoke]; - } - } - - // Defer dispatching `postPersist` events to until all entities have been inserted and post-insert - // IDs have been assigned. - foreach ($eventsToDispatch as $event) { - $this->listenersInvoker->invoke( - $event['class'], - Events::postPersist, - $event['entity'], - new PostPersistEventArgs($event['entity'], $this->em), - $event['invoke'], - ); - } - } - - /** - * @psalm-param ClassMetadata $class - * @psalm-param T $entity - * - * @template T of object - */ - private function addToEntityIdentifiersAndEntityMap( - ClassMetadata $class, - int $oid, - object $entity, - ): void { - $identifier = []; - - foreach ($class->getIdentifierFieldNames() as $idField) { - $origValue = $class->getFieldValue($entity, $idField); - - $value = null; - if (isset($class->associationMappings[$idField])) { - // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. - $value = $this->getSingleIdentifierValue($origValue); - } - - $identifier[$idField] = $value ?? $origValue; - $this->originalEntityData[$oid][$idField] = $origValue; - } - - $this->entityStates[$oid] = self::STATE_MANAGED; - $this->entityIdentifiers[$oid] = $identifier; - - $this->addToIdentityMap($entity); - } - - /** - * Executes all entity updates - */ - private function executeUpdates(): void - { - foreach ($this->entityUpdates as $oid => $entity) { - $class = $this->em->getClassMetadata($entity::class); - $persister = $this->getEntityPersister($class->name); - $preUpdateInvoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preUpdate); - $postUpdateInvoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postUpdate); - - if ($preUpdateInvoke !== ListenersInvoker::INVOKE_NONE) { - $this->listenersInvoker->invoke($class, Events::preUpdate, $entity, new PreUpdateEventArgs($entity, $this->em, $this->getEntityChangeSet($entity)), $preUpdateInvoke); - - $this->recomputeSingleEntityChangeSet($class, $entity); - } - - if (! empty($this->entityChangeSets[$oid])) { - $persister->update($entity); - } - - unset($this->entityUpdates[$oid]); - - if ($postUpdateInvoke !== ListenersInvoker::INVOKE_NONE) { - $this->listenersInvoker->invoke($class, Events::postUpdate, $entity, new PostUpdateEventArgs($entity, $this->em), $postUpdateInvoke); - } - } - } - - /** - * Executes all entity deletions - */ - private function executeDeletions(): void - { - $entities = $this->computeDeleteExecutionOrder(); - $eventsToDispatch = []; - - foreach ($entities as $entity) { - $this->removeFromIdentityMap($entity); - - $oid = spl_object_id($entity); - $class = $this->em->getClassMetadata($entity::class); - $persister = $this->getEntityPersister($class->name); - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postRemove); - - $persister->delete($entity); - - unset( - $this->entityDeletions[$oid], - $this->entityIdentifiers[$oid], - $this->originalEntityData[$oid], - $this->entityStates[$oid], - ); - - // Entity with this $oid after deletion treated as NEW, even if the $oid - // is obtained by a new entity because the old one went out of scope. - //$this->entityStates[$oid] = self::STATE_NEW; - if (! $class->isIdentifierNatural()) { - $class->reflFields[$class->identifier[0]]->setValue($entity, null); - } - - if ($invoke !== ListenersInvoker::INVOKE_NONE) { - $eventsToDispatch[] = ['class' => $class, 'entity' => $entity, 'invoke' => $invoke]; - } - } - - // Defer dispatching `postRemove` events to until all entities have been removed. - foreach ($eventsToDispatch as $event) { - $this->listenersInvoker->invoke( - $event['class'], - Events::postRemove, - $event['entity'], - new PostRemoveEventArgs($event['entity'], $this->em), - $event['invoke'], - ); - } - } - - /** @return list */ - private function computeInsertExecutionOrder(): array - { - $sort = new TopologicalSort(); - - // First make sure we have all the nodes - foreach ($this->entityInsertions as $entity) { - $sort->addNode($entity); - } - - // Now add edges - foreach ($this->entityInsertions as $entity) { - $class = $this->em->getClassMetadata($entity::class); - - foreach ($class->associationMappings as $assoc) { - // We only need to consider the owning sides of to-one associations, - // since many-to-many associations are persisted at a later step and - // have no insertion order problems (all entities already in the database - // at that time). - if (! $assoc->isToOneOwningSide()) { - continue; - } - - $targetEntity = $class->getFieldValue($entity, $assoc->fieldName); - - // If there is no entity that we need to refer to, or it is already in the - // database (i. e. does not have to be inserted), no need to consider it. - if ($targetEntity === null || ! $sort->hasNode($targetEntity)) { - continue; - } - - // An entity that references back to itself _and_ uses an application-provided ID - // (the "NONE" generator strategy) can be exempted from commit order computation. - // See https://github.com/doctrine/orm/pull/10735/ for more details on this edge case. - // A non-NULLable self-reference would be a cycle in the graph. - if ($targetEntity === $entity && $class->isIdentifierNatural()) { - continue; - } - - // According to https://www.doctrine-project.org/projects/doctrine-orm/en/2.14/reference/annotations-reference.html#annref_joincolumn, - // the default for "nullable" is true. Unfortunately, it seems this default is not applied at the metadata driver, factory or other - // level, but in fact we may have an undefined 'nullable' key here, so we must assume that default here as well. - // - // Same in \Doctrine\ORM\Tools\EntityGenerator::isAssociationIsNullable or \Doctrine\ORM\Persisters\Entity\BasicEntityPersister::getJoinSQLForJoinColumns, - // to give two examples. - $joinColumns = reset($assoc->joinColumns); - $isNullable = ! isset($joinColumns->nullable) || $joinColumns->nullable; - - // Add dependency. The dependency direction implies that "$entity depends on $targetEntity". The - // topological sort result will output the depended-upon nodes first, which means we can insert - // entities in that order. - $sort->addEdge($entity, $targetEntity, $isNullable); - } - } - - return $sort->sort(); - } - - /** @return list */ - private function computeDeleteExecutionOrder(): array - { - $stronglyConnectedComponents = new StronglyConnectedComponents(); - $sort = new TopologicalSort(); - - foreach ($this->entityDeletions as $entity) { - $stronglyConnectedComponents->addNode($entity); - $sort->addNode($entity); - } - - // First, consider only "on delete cascade" associations between entities - // and find strongly connected groups. Once we delete any one of the entities - // in such a group, _all_ of the other entities will be removed as well. So, - // we need to treat those groups like a single entity when performing delete - // order topological sorting. - foreach ($this->entityDeletions as $entity) { - $class = $this->em->getClassMetadata($entity::class); - - foreach ($class->associationMappings as $assoc) { - // We only need to consider the owning sides of to-one associations, - // since many-to-many associations can always be (and have already been) - // deleted in a preceding step. - if (! $assoc->isToOneOwningSide()) { - continue; - } - - $joinColumns = reset($assoc->joinColumns); - if (! isset($joinColumns->onDelete)) { - continue; - } - - $onDeleteOption = strtolower($joinColumns->onDelete); - if ($onDeleteOption !== 'cascade') { - continue; - } - - $targetEntity = $class->getFieldValue($entity, $assoc->fieldName); - - // If the association does not refer to another entity or that entity - // is not to be deleted, there is no ordering problem and we can - // skip this particular association. - if ($targetEntity === null || ! $stronglyConnectedComponents->hasNode($targetEntity)) { - continue; - } - - $stronglyConnectedComponents->addEdge($entity, $targetEntity); - } - } - - $stronglyConnectedComponents->findStronglyConnectedComponents(); - - // Now do the actual topological sorting to find the delete order. - foreach ($this->entityDeletions as $entity) { - $class = $this->em->getClassMetadata($entity::class); - - // Get the entities representing the SCC - $entityComponent = $stronglyConnectedComponents->getNodeRepresentingStronglyConnectedComponent($entity); - - // When $entity is part of a non-trivial strongly connected component group - // (a group containing not only those entities alone), make sure we process it _after_ the - // entity representing the group. - // The dependency direction implies that "$entity depends on $entityComponent - // being deleted first". The topological sort will output the depended-upon nodes first. - if ($entityComponent !== $entity) { - $sort->addEdge($entity, $entityComponent, false); - } - - foreach ($class->associationMappings as $assoc) { - // We only need to consider the owning sides of to-one associations, - // since many-to-many associations can always be (and have already been) - // deleted in a preceding step. - if (! $assoc->isToOneOwningSide()) { - continue; - } - - // For associations that implement a database-level set null operation, - // we do not have to follow a particular order: If the referred-to entity is - // deleted first, the DBMS will temporarily set the foreign key to NULL (SET NULL). - // So, we can skip it in the computation. - $joinColumns = reset($assoc->joinColumns); - if (isset($joinColumns->onDelete)) { - $onDeleteOption = strtolower($joinColumns->onDelete); - if ($onDeleteOption === 'set null') { - continue; - } - } - - $targetEntity = $class->getFieldValue($entity, $assoc->fieldName); - - // If the association does not refer to another entity or that entity - // is not to be deleted, there is no ordering problem and we can - // skip this particular association. - if ($targetEntity === null || ! $sort->hasNode($targetEntity)) { - continue; - } - - // Get the entities representing the SCC - $targetEntityComponent = $stronglyConnectedComponents->getNodeRepresentingStronglyConnectedComponent($targetEntity); - - // When we have a dependency between two different groups of strongly connected nodes, - // add it to the computation. - // The dependency direction implies that "$targetEntityComponent depends on $entityComponent - // being deleted first". The topological sort will output the depended-upon nodes first, - // so we can work through the result in the returned order. - if ($targetEntityComponent !== $entityComponent) { - $sort->addEdge($targetEntityComponent, $entityComponent, false); - } - } - } - - return $sort->sort(); - } - - /** - * Schedules an entity for insertion into the database. - * If the entity already has an identifier, it will be added to the identity map. - * - * @throws ORMInvalidArgumentException - * @throws InvalidArgumentException - */ - public function scheduleForInsert(object $entity): void - { - $oid = spl_object_id($entity); - - if (isset($this->entityUpdates[$oid])) { - throw new InvalidArgumentException('Dirty entity can not be scheduled for insertion.'); - } - - if (isset($this->entityDeletions[$oid])) { - throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity); - } - - if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) { - throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity); - } - - if (isset($this->entityInsertions[$oid])) { - throw ORMInvalidArgumentException::scheduleInsertTwice($entity); - } - - $this->entityInsertions[$oid] = $entity; - - if (isset($this->entityIdentifiers[$oid])) { - $this->addToIdentityMap($entity); - } - } - - /** - * Checks whether an entity is scheduled for insertion. - */ - public function isScheduledForInsert(object $entity): bool - { - return isset($this->entityInsertions[spl_object_id($entity)]); - } - - /** - * Schedules an entity for being updated. - * - * @throws ORMInvalidArgumentException - */ - public function scheduleForUpdate(object $entity): void - { - $oid = spl_object_id($entity); - - if (! isset($this->entityIdentifiers[$oid])) { - throw ORMInvalidArgumentException::entityHasNoIdentity($entity, 'scheduling for update'); - } - - if (isset($this->entityDeletions[$oid])) { - throw ORMInvalidArgumentException::entityIsRemoved($entity, 'schedule for update'); - } - - if (! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) { - $this->entityUpdates[$oid] = $entity; - } - } - - /** - * INTERNAL: - * Schedules an extra update that will be executed immediately after the - * regular entity updates within the currently running commit cycle. - * - * Extra updates for entities are stored as (entity, changeset) tuples. - * - * @psalm-param array $changeset The changeset of the entity (what to update). - * - * @ignore - */ - public function scheduleExtraUpdate(object $entity, array $changeset): void - { - $oid = spl_object_id($entity); - $extraUpdate = [$entity, $changeset]; - - if (isset($this->extraUpdates[$oid])) { - [, $changeset2] = $this->extraUpdates[$oid]; - - $extraUpdate = [$entity, $changeset + $changeset2]; - } - - $this->extraUpdates[$oid] = $extraUpdate; - } - - /** - * Checks whether an entity is registered as dirty in the unit of work. - * Note: Is not very useful currently as dirty entities are only registered - * at commit time. - */ - public function isScheduledForUpdate(object $entity): bool - { - return isset($this->entityUpdates[spl_object_id($entity)]); - } - - /** - * Checks whether an entity is registered to be checked in the unit of work. - */ - public function isScheduledForDirtyCheck(object $entity): bool - { - $rootEntityName = $this->em->getClassMetadata($entity::class)->rootEntityName; - - return isset($this->scheduledForSynchronization[$rootEntityName][spl_object_id($entity)]); - } - - /** - * INTERNAL: - * Schedules an entity for deletion. - */ - public function scheduleForDelete(object $entity): void - { - $oid = spl_object_id($entity); - - if (isset($this->entityInsertions[$oid])) { - if ($this->isInIdentityMap($entity)) { - $this->removeFromIdentityMap($entity); - } - - unset($this->entityInsertions[$oid], $this->entityStates[$oid]); - - return; // entity has not been persisted yet, so nothing more to do. - } - - if (! $this->isInIdentityMap($entity)) { - return; - } - - unset($this->entityUpdates[$oid]); - - if (! isset($this->entityDeletions[$oid])) { - $this->entityDeletions[$oid] = $entity; - $this->entityStates[$oid] = self::STATE_REMOVED; - } - } - - /** - * Checks whether an entity is registered as removed/deleted with the unit - * of work. - */ - public function isScheduledForDelete(object $entity): bool - { - return isset($this->entityDeletions[spl_object_id($entity)]); - } - - /** - * Checks whether an entity is scheduled for insertion, update or deletion. - */ - public function isEntityScheduled(object $entity): bool - { - $oid = spl_object_id($entity); - - return isset($this->entityInsertions[$oid]) - || isset($this->entityUpdates[$oid]) - || isset($this->entityDeletions[$oid]); - } - - /** - * INTERNAL: - * Registers an entity in the identity map. - * Note that entities in a hierarchy are registered with the class name of - * the root entity. - * - * @return bool TRUE if the registration was successful, FALSE if the identity of - * the entity in question is already managed. - * - * @throws ORMInvalidArgumentException - * @throws EntityIdentityCollisionException - * - * @ignore - */ - public function addToIdentityMap(object $entity): bool - { - $classMetadata = $this->em->getClassMetadata($entity::class); - $idHash = $this->getIdHashByEntity($entity); - $className = $classMetadata->rootEntityName; - - if (isset($this->identityMap[$className][$idHash])) { - if ($this->identityMap[$className][$idHash] !== $entity) { - throw EntityIdentityCollisionException::create($this->identityMap[$className][$idHash], $entity, $idHash); - } - - return false; - } - - $this->identityMap[$className][$idHash] = $entity; - - return true; - } - - /** - * Gets the id hash of an entity by its identifier. - * - * @param array $identifier The identifier of an entity - * - * @return string The entity id hash. - */ - final public static function getIdHashByIdentifier(array $identifier): string - { - foreach ($identifier as $k => $value) { - if ($value instanceof BackedEnum) { - $identifier[$k] = $value->value; - } - } - - return implode( - ' ', - $identifier, - ); - } - - /** - * Gets the id hash of an entity. - * - * @param object $entity The entity managed by Unit Of Work - * - * @return string The entity id hash. - */ - public function getIdHashByEntity(object $entity): string - { - $identifier = $this->entityIdentifiers[spl_object_id($entity)]; - - if (empty($identifier) || in_array(null, $identifier, true)) { - $classMetadata = $this->em->getClassMetadata($entity::class); - - throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity); - } - - return self::getIdHashByIdentifier($identifier); - } - - /** - * Gets the state of an entity with regard to the current unit of work. - * - * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED). - * This parameter can be set to improve performance of entity state detection - * by potentially avoiding a database lookup if the distinction between NEW and DETACHED - * is either known or does not matter for the caller of the method. - * @psalm-param self::STATE_*|null $assume - * - * @psalm-return self::STATE_* - */ - public function getEntityState(object $entity, int|null $assume = null): int - { - $oid = spl_object_id($entity); - - if (isset($this->entityStates[$oid])) { - return $this->entityStates[$oid]; - } - - if ($assume !== null) { - return $assume; - } - - // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known. - // Note that you can not remember the NEW or DETACHED state in _entityStates since - // the UoW does not hold references to such objects and the object hash can be reused. - // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it. - $class = $this->em->getClassMetadata($entity::class); - $id = $class->getIdentifierValues($entity); - - if (! $id) { - return self::STATE_NEW; - } - - if ($class->containsForeignIdentifier || $class->containsEnumIdentifier) { - $id = $this->identifierFlattener->flattenIdentifier($class, $id); - } - - switch (true) { - case $class->isIdentifierNatural(): - // Check for a version field, if available, to avoid a db lookup. - if ($class->isVersioned) { - assert($class->versionField !== null); - - return $class->getFieldValue($entity, $class->versionField) - ? self::STATE_DETACHED - : self::STATE_NEW; - } - - // Last try before db lookup: check the identity map. - if ($this->tryGetById($id, $class->rootEntityName)) { - return self::STATE_DETACHED; - } - - // db lookup - if ($this->getEntityPersister($class->name)->exists($entity)) { - return self::STATE_DETACHED; - } - - return self::STATE_NEW; - - case ! $class->idGenerator->isPostInsertGenerator(): - // if we have a pre insert generator we can't be sure that having an id - // really means that the entity exists. We have to verify this through - // the last resort: a db lookup - - // Last try before db lookup: check the identity map. - if ($this->tryGetById($id, $class->rootEntityName)) { - return self::STATE_DETACHED; - } - - // db lookup - if ($this->getEntityPersister($class->name)->exists($entity)) { - return self::STATE_DETACHED; - } - - return self::STATE_NEW; - - default: - return self::STATE_DETACHED; - } - } - - /** - * INTERNAL: - * Removes an entity from the identity map. This effectively detaches the - * entity from the persistence management of Doctrine. - * - * @throws ORMInvalidArgumentException - * - * @ignore - */ - public function removeFromIdentityMap(object $entity): bool - { - $oid = spl_object_id($entity); - $classMetadata = $this->em->getClassMetadata($entity::class); - $idHash = self::getIdHashByIdentifier($this->entityIdentifiers[$oid]); - - if ($idHash === '') { - throw ORMInvalidArgumentException::entityHasNoIdentity($entity, 'remove from identity map'); - } - - $className = $classMetadata->rootEntityName; - - if (isset($this->identityMap[$className][$idHash])) { - unset($this->identityMap[$className][$idHash], $this->readOnlyObjects[$oid]); - - //$this->entityStates[$oid] = self::STATE_DETACHED; - - return true; - } - - return false; - } - - /** - * INTERNAL: - * Gets an entity in the identity map by its identifier hash. - * - * @ignore - */ - public function getByIdHash(string $idHash, string $rootClassName): object|null - { - return $this->identityMap[$rootClassName][$idHash]; - } - - /** - * INTERNAL: - * Tries to get an entity by its identifier hash. If no entity is found for - * the given hash, FALSE is returned. - * - * @param mixed $idHash (must be possible to cast it to string) - * - * @return false|object The found entity or FALSE. - * - * @ignore - */ - public function tryGetByIdHash(mixed $idHash, string $rootClassName): object|false - { - $stringIdHash = (string) $idHash; - - return $this->identityMap[$rootClassName][$stringIdHash] ?? false; - } - - /** - * Checks whether an entity is registered in the identity map of this UnitOfWork. - */ - public function isInIdentityMap(object $entity): bool - { - $oid = spl_object_id($entity); - - if (empty($this->entityIdentifiers[$oid])) { - return false; - } - - $classMetadata = $this->em->getClassMetadata($entity::class); - $idHash = self::getIdHashByIdentifier($this->entityIdentifiers[$oid]); - - return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]); - } - - /** - * Persists an entity as part of the current unit of work. - */ - public function persist(object $entity): void - { - $visited = []; - - $this->doPersist($entity, $visited); - } - - /** - * Persists an entity as part of the current unit of work. - * - * This method is internally called during persist() cascades as it tracks - * the already visited entities to prevent infinite recursions. - * - * @psalm-param array $visited The already visited entities. - * - * @throws ORMInvalidArgumentException - * @throws UnexpectedValueException - */ - private function doPersist(object $entity, array &$visited): void - { - $oid = spl_object_id($entity); - - if (isset($visited[$oid])) { - return; // Prevent infinite recursion - } - - $visited[$oid] = $entity; // Mark visited - - $class = $this->em->getClassMetadata($entity::class); - - // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation). - // If we would detect DETACHED here we would throw an exception anyway with the same - // consequences (not recoverable/programming error), so just assuming NEW here - // lets us avoid some database lookups for entities with natural identifiers. - $entityState = $this->getEntityState($entity, self::STATE_NEW); - - switch ($entityState) { - case self::STATE_MANAGED: - // Nothing to do, except if policy is "deferred explicit" - if ($class->isChangeTrackingDeferredExplicit()) { - $this->scheduleForDirtyCheck($entity); - } - - break; - - case self::STATE_NEW: - $this->persistNew($class, $entity); - break; - - case self::STATE_REMOVED: - // Entity becomes managed again - unset($this->entityDeletions[$oid]); - $this->addToIdentityMap($entity); - - $this->entityStates[$oid] = self::STATE_MANAGED; - - if ($class->isChangeTrackingDeferredExplicit()) { - $this->scheduleForDirtyCheck($entity); - } - - break; - - case self::STATE_DETACHED: - // Can actually not happen right now since we assume STATE_NEW. - throw ORMInvalidArgumentException::detachedEntityCannot($entity, 'persisted'); - - default: - throw new UnexpectedValueException(sprintf( - 'Unexpected entity state: %s. %s', - $entityState, - self::objToStr($entity), - )); - } - - $this->cascadePersist($entity, $visited); - } - - /** - * Deletes an entity as part of the current unit of work. - */ - public function remove(object $entity): void - { - $visited = []; - - $this->doRemove($entity, $visited); - } - - /** - * Deletes an entity as part of the current unit of work. - * - * This method is internally called during delete() cascades as it tracks - * the already visited entities to prevent infinite recursions. - * - * @psalm-param array $visited The map of the already visited entities. - * - * @throws ORMInvalidArgumentException If the instance is a detached entity. - * @throws UnexpectedValueException - */ - private function doRemove(object $entity, array &$visited): void - { - $oid = spl_object_id($entity); - - if (isset($visited[$oid])) { - return; // Prevent infinite recursion - } - - $visited[$oid] = $entity; // mark visited - - // Cascade first, because scheduleForDelete() removes the entity from the identity map, which - // can cause problems when a lazy proxy has to be initialized for the cascade operation. - $this->cascadeRemove($entity, $visited); - - $class = $this->em->getClassMetadata($entity::class); - $entityState = $this->getEntityState($entity); - - switch ($entityState) { - case self::STATE_NEW: - case self::STATE_REMOVED: - // nothing to do - break; - - case self::STATE_MANAGED: - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preRemove); - - if ($invoke !== ListenersInvoker::INVOKE_NONE) { - $this->listenersInvoker->invoke($class, Events::preRemove, $entity, new PreRemoveEventArgs($entity, $this->em), $invoke); - } - - $this->scheduleForDelete($entity); - break; - - case self::STATE_DETACHED: - throw ORMInvalidArgumentException::detachedEntityCannot($entity, 'removed'); - - default: - throw new UnexpectedValueException(sprintf( - 'Unexpected entity state: %s. %s', - $entityState, - self::objToStr($entity), - )); - } - } - - /** - * Detaches an entity from the persistence management. It's persistence will - * no longer be managed by Doctrine. - */ - public function detach(object $entity): void - { - $visited = []; - - $this->doDetach($entity, $visited); - } - - /** - * Executes a detach operation on the given entity. - * - * @param mixed[] $visited - * @param bool $noCascade if true, don't cascade detach operation. - */ - private function doDetach( - object $entity, - array &$visited, - bool $noCascade = false, - ): void { - $oid = spl_object_id($entity); - - if (isset($visited[$oid])) { - return; // Prevent infinite recursion - } - - $visited[$oid] = $entity; // mark visited - - switch ($this->getEntityState($entity, self::STATE_DETACHED)) { - case self::STATE_MANAGED: - if ($this->isInIdentityMap($entity)) { - $this->removeFromIdentityMap($entity); - } - - unset( - $this->entityInsertions[$oid], - $this->entityUpdates[$oid], - $this->entityDeletions[$oid], - $this->entityIdentifiers[$oid], - $this->entityStates[$oid], - $this->originalEntityData[$oid], - ); - break; - case self::STATE_NEW: - case self::STATE_DETACHED: - return; - } - - if (! $noCascade) { - $this->cascadeDetach($entity, $visited); - } - } - - /** - * Refreshes the state of the given entity from the database, overwriting - * any local, unpersisted changes. - * - * @psalm-param LockMode::*|null $lockMode - * - * @throws InvalidArgumentException If the entity is not MANAGED. - * @throws TransactionRequiredException - */ - public function refresh(object $entity, LockMode|int|null $lockMode = null): void - { - $visited = []; - - $this->doRefresh($entity, $visited, $lockMode); - } - - /** - * Executes a refresh operation on an entity. - * - * @psalm-param array $visited The already visited entities during cascades. - * @psalm-param LockMode::*|null $lockMode - * - * @throws ORMInvalidArgumentException If the entity is not MANAGED. - * @throws TransactionRequiredException - */ - private function doRefresh(object $entity, array &$visited, LockMode|int|null $lockMode = null): void - { - switch (true) { - case $lockMode === LockMode::PESSIMISTIC_READ: - case $lockMode === LockMode::PESSIMISTIC_WRITE: - if (! $this->em->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } - } - - $oid = spl_object_id($entity); - - if (isset($visited[$oid])) { - return; // Prevent infinite recursion - } - - $visited[$oid] = $entity; // mark visited - - $class = $this->em->getClassMetadata($entity::class); - - if ($this->getEntityState($entity) !== self::STATE_MANAGED) { - throw ORMInvalidArgumentException::entityNotManaged($entity); - } - - $this->getEntityPersister($class->name)->refresh( - array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), - $entity, - $lockMode, - ); - - $this->cascadeRefresh($entity, $visited, $lockMode); - } - - /** - * Cascades a refresh operation to associated entities. - * - * @psalm-param array $visited - * @psalm-param LockMode::*|null $lockMode - */ - private function cascadeRefresh(object $entity, array &$visited, LockMode|int|null $lockMode = null): void - { - $class = $this->em->getClassMetadata($entity::class); - - $associationMappings = array_filter( - $class->associationMappings, - static fn (AssociationMapping $assoc): bool => $assoc->isCascadeRefresh() - ); - - foreach ($associationMappings as $assoc) { - $relatedEntities = $class->reflFields[$assoc->fieldName]->getValue($entity); - - switch (true) { - case $relatedEntities instanceof PersistentCollection: - // Unwrap so that foreach() does not initialize - $relatedEntities = $relatedEntities->unwrap(); - // break; is commented intentionally! - - case $relatedEntities instanceof Collection: - case is_array($relatedEntities): - foreach ($relatedEntities as $relatedEntity) { - $this->doRefresh($relatedEntity, $visited, $lockMode); - } - - break; - - case $relatedEntities !== null: - $this->doRefresh($relatedEntities, $visited, $lockMode); - break; - - default: - // Do nothing - } - } - } - - /** - * Cascades a detach operation to associated entities. - * - * @param array $visited - */ - private function cascadeDetach(object $entity, array &$visited): void - { - $class = $this->em->getClassMetadata($entity::class); - - $associationMappings = array_filter( - $class->associationMappings, - static fn (AssociationMapping $assoc): bool => $assoc->isCascadeDetach() - ); - - foreach ($associationMappings as $assoc) { - $relatedEntities = $class->reflFields[$assoc->fieldName]->getValue($entity); - - switch (true) { - case $relatedEntities instanceof PersistentCollection: - // Unwrap so that foreach() does not initialize - $relatedEntities = $relatedEntities->unwrap(); - // break; is commented intentionally! - - case $relatedEntities instanceof Collection: - case is_array($relatedEntities): - foreach ($relatedEntities as $relatedEntity) { - $this->doDetach($relatedEntity, $visited); - } - - break; - - case $relatedEntities !== null: - $this->doDetach($relatedEntities, $visited); - break; - - default: - // Do nothing - } - } - } - - /** - * Cascades the save operation to associated entities. - * - * @psalm-param array $visited - */ - private function cascadePersist(object $entity, array &$visited): void - { - if ($this->isUninitializedObject($entity)) { - // nothing to do - proxy is not initialized, therefore we don't do anything with it - return; - } - - $class = $this->em->getClassMetadata($entity::class); - - $associationMappings = array_filter( - $class->associationMappings, - static fn (AssociationMapping $assoc): bool => $assoc->isCascadePersist() - ); - - foreach ($associationMappings as $assoc) { - $relatedEntities = $class->reflFields[$assoc->fieldName]->getValue($entity); - - switch (true) { - case $relatedEntities instanceof PersistentCollection: - // Unwrap so that foreach() does not initialize - $relatedEntities = $relatedEntities->unwrap(); - // break; is commented intentionally! - - case $relatedEntities instanceof Collection: - case is_array($relatedEntities): - if ($assoc->isToMany() <= 0) { - throw ORMInvalidArgumentException::invalidAssociation( - $this->em->getClassMetadata($assoc->targetEntity), - $assoc, - $relatedEntities, - ); - } - - foreach ($relatedEntities as $relatedEntity) { - $this->doPersist($relatedEntity, $visited); - } - - break; - - case $relatedEntities !== null: - if (! $relatedEntities instanceof $assoc->targetEntity) { - throw ORMInvalidArgumentException::invalidAssociation( - $this->em->getClassMetadata($assoc->targetEntity), - $assoc, - $relatedEntities, - ); - } - - $this->doPersist($relatedEntities, $visited); - break; - - default: - // Do nothing - } - } - } - - /** - * Cascades the delete operation to associated entities. - * - * @psalm-param array $visited - */ - private function cascadeRemove(object $entity, array &$visited): void - { - $class = $this->em->getClassMetadata($entity::class); - - $associationMappings = array_filter( - $class->associationMappings, - static fn (AssociationMapping $assoc): bool => $assoc->isCascadeRemove() - ); - - if ($associationMappings) { - $this->initializeObject($entity); - } - - $entitiesToCascade = []; - - foreach ($associationMappings as $assoc) { - $relatedEntities = $class->reflFields[$assoc->fieldName]->getValue($entity); - - switch (true) { - case $relatedEntities instanceof Collection: - case is_array($relatedEntities): - // If its a PersistentCollection initialization is intended! No unwrap! - foreach ($relatedEntities as $relatedEntity) { - $entitiesToCascade[] = $relatedEntity; - } - - break; - - case $relatedEntities !== null: - $entitiesToCascade[] = $relatedEntities; - break; - - default: - // Do nothing - } - } - - foreach ($entitiesToCascade as $relatedEntity) { - $this->doRemove($relatedEntity, $visited); - } - } - - /** - * Acquire a lock on the given entity. - * - * @psalm-param LockMode::* $lockMode - * - * @throws ORMInvalidArgumentException - * @throws TransactionRequiredException - * @throws OptimisticLockException - */ - public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void - { - if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) { - throw ORMInvalidArgumentException::entityNotManaged($entity); - } - - $class = $this->em->getClassMetadata($entity::class); - - switch (true) { - case $lockMode === LockMode::OPTIMISTIC: - if (! $class->isVersioned) { - throw OptimisticLockException::notVersioned($class->name); - } - - if ($lockVersion === null) { - return; - } - - $this->initializeObject($entity); - - assert($class->versionField !== null); - $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); - - // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator - if ($entityVersion != $lockVersion) { - throw OptimisticLockException::lockFailedVersionMismatch($entity, $lockVersion, $entityVersion); - } - - break; - - case $lockMode === LockMode::NONE: - case $lockMode === LockMode::PESSIMISTIC_READ: - case $lockMode === LockMode::PESSIMISTIC_WRITE: - if (! $this->em->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } - - $oid = spl_object_id($entity); - - $this->getEntityPersister($class->name)->lock( - array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), - $lockMode, - ); - break; - - default: - // Do nothing - } - } - - /** - * Clears the UnitOfWork. - */ - public function clear(): void - { - $this->identityMap = - $this->entityIdentifiers = - $this->originalEntityData = - $this->entityChangeSets = - $this->entityStates = - $this->scheduledForSynchronization = - $this->entityInsertions = - $this->entityUpdates = - $this->entityDeletions = - $this->nonCascadedNewDetectedEntities = - $this->collectionDeletions = - $this->collectionUpdates = - $this->extraUpdates = - $this->readOnlyObjects = - $this->pendingCollectionElementRemovals = - $this->visitedCollections = - $this->eagerLoadingEntities = - $this->eagerLoadingCollections = - $this->orphanRemovals = []; - - if ($this->evm->hasListeners(Events::onClear)) { - $this->evm->dispatchEvent(Events::onClear, new OnClearEventArgs($this->em)); - } - } - - /** - * INTERNAL: - * Schedules an orphaned entity for removal. The remove() operation will be - * invoked on that entity at the beginning of the next commit of this - * UnitOfWork. - * - * @ignore - */ - public function scheduleOrphanRemoval(object $entity): void - { - $this->orphanRemovals[spl_object_id($entity)] = $entity; - } - - /** - * INTERNAL: - * Cancels a previously scheduled orphan removal. - * - * @ignore - */ - public function cancelOrphanRemoval(object $entity): void - { - unset($this->orphanRemovals[spl_object_id($entity)]); - } - - /** - * INTERNAL: - * Schedules a complete collection for removal when this UnitOfWork commits. - */ - public function scheduleCollectionDeletion(PersistentCollection $coll): void - { - $coid = spl_object_id($coll); - - // TODO: if $coll is already scheduled for recreation ... what to do? - // Just remove $coll from the scheduled recreations? - unset($this->collectionUpdates[$coid]); - - $this->collectionDeletions[$coid] = $coll; - } - - public function isCollectionScheduledForDeletion(PersistentCollection $coll): bool - { - return isset($this->collectionDeletions[spl_object_id($coll)]); - } - - /** - * INTERNAL: - * Creates an entity. Used for reconstitution of persistent entities. - * - * Internal note: Highly performance-sensitive method. - * - * @param string $className The name of the entity class. - * @param mixed[] $data The data for the entity. - * @param mixed[] $hints Any hints to account for during reconstitution/lookup of the entity. - * @psalm-param class-string $className - * @psalm-param array $hints - * - * @return object The managed entity instance. - * - * @ignore - * @todo Rename: getOrCreateEntity - */ - public function createEntity(string $className, array $data, array &$hints = []): object - { - $class = $this->em->getClassMetadata($className); - - $id = $this->identifierFlattener->flattenIdentifier($class, $data); - $idHash = self::getIdHashByIdentifier($id); - - if (isset($this->identityMap[$class->rootEntityName][$idHash])) { - $entity = $this->identityMap[$class->rootEntityName][$idHash]; - $oid = spl_object_id($entity); - - if ( - isset($hints[Query::HINT_REFRESH], $hints[Query::HINT_REFRESH_ENTITY]) - ) { - $unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]; - if ( - $unmanagedProxy !== $entity - && $this->isIdentifierEquals($unmanagedProxy, $entity) - ) { - // We will hydrate the given un-managed proxy anyway: - // continue work, but consider it the entity from now on - $entity = $unmanagedProxy; - } - } - - if ($this->isUninitializedObject($entity)) { - $entity->__setInitialized(true); - } else { - if ( - ! isset($hints[Query::HINT_REFRESH]) - || (isset($hints[Query::HINT_REFRESH_ENTITY]) && $hints[Query::HINT_REFRESH_ENTITY] !== $entity) - ) { - return $entity; - } - } - - $this->originalEntityData[$oid] = $data; - } else { - $entity = $class->newInstance(); - $oid = spl_object_id($entity); - $this->registerManaged($entity, $id, $data); - - if (isset($hints[Query::HINT_READ_ONLY])) { - $this->readOnlyObjects[$oid] = true; - } - } - - foreach ($data as $field => $value) { - if (isset($class->fieldMappings[$field])) { - $class->reflFields[$field]->setValue($entity, $value); - } - } - - // Loading the entity right here, if its in the eager loading map get rid of it there. - unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]); - - if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && ! $this->eagerLoadingEntities[$class->rootEntityName]) { - unset($this->eagerLoadingEntities[$class->rootEntityName]); - } - - foreach ($class->associationMappings as $field => $assoc) { - // Check if the association is not among the fetch-joined associations already. - if (isset($hints['fetchAlias'], $hints['fetched'][$hints['fetchAlias']][$field])) { - continue; - } - - if (! isset($hints['fetchMode'][$class->name][$field])) { - $hints['fetchMode'][$class->name][$field] = $assoc->fetch; - } - - $targetClass = $this->em->getClassMetadata($assoc->targetEntity); - - switch (true) { - case $assoc->isToOne(): - if (! $assoc->isOwningSide()) { - // use the given entity association - if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_id($data[$field])])) { - $this->originalEntityData[$oid][$field] = $data[$field]; - - $class->reflFields[$field]->setValue($entity, $data[$field]); - $targetClass->reflFields[$assoc->mappedBy]->setValue($data[$field], $entity); - - continue 2; - } - - // Inverse side of x-to-one can never be lazy - $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc->targetEntity)->loadOneToOneEntity($assoc, $entity)); - - continue 2; - } - - // use the entity association - if (isset($data[$field]) && is_object($data[$field]) && isset($this->entityStates[spl_object_id($data[$field])])) { - $class->reflFields[$field]->setValue($entity, $data[$field]); - $this->originalEntityData[$oid][$field] = $data[$field]; - - break; - } - - $associatedId = []; - - assert($assoc->isToOneOwningSide()); - // TODO: Is this even computed right in all cases of composite keys? - foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) { - $joinColumnValue = $data[$srcColumn] ?? null; - - if ($joinColumnValue !== null) { - if ($joinColumnValue instanceof BackedEnum) { - $joinColumnValue = $joinColumnValue->value; - } - - if ($targetClass->containsForeignIdentifier) { - $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue; - } else { - $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue; - } - } elseif (in_array($targetClass->getFieldForColumn($targetColumn), $targetClass->identifier, true)) { - // the missing key is part of target's entity primary key - $associatedId = []; - break; - } - } - - if (! $associatedId) { - // Foreign key is NULL - $class->reflFields[$field]->setValue($entity, null); - $this->originalEntityData[$oid][$field] = null; - - break; - } - - // Foreign key is set - // Check identity map first - // FIXME: Can break easily with composite keys if join column values are in - // wrong order. The correct order is the one in ClassMetadata#identifier. - $relatedIdHash = self::getIdHashByIdentifier($associatedId); - - switch (true) { - case isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash]): - $newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash]; - - // If this is an uninitialized proxy, we are deferring eager loads, - // this association is marked as eager fetch, and its an uninitialized proxy (wtf!) - // then we can append this entity for eager loading! - if ( - $hints['fetchMode'][$class->name][$field] === ClassMetadata::FETCH_EAGER && - isset($hints[self::HINT_DEFEREAGERLOAD]) && - ! $targetClass->isIdentifierComposite && - $this->isUninitializedObject($newValue) - ) { - $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId); - } - - break; - - case $targetClass->subClasses: - // If it might be a subtype, it can not be lazy. There isn't even - // a way to solve this with deferred eager loading, which means putting - // an entity with subclasses at a *-to-one location is really bad! (performance-wise) - $newValue = $this->getEntityPersister($assoc->targetEntity)->loadOneToOneEntity($assoc, $entity, $associatedId); - break; - - default: - $normalizedAssociatedId = $this->normalizeIdentifier($targetClass, $associatedId); - - switch (true) { - // We are negating the condition here. Other cases will assume it is valid! - case $hints['fetchMode'][$class->name][$field] !== ClassMetadata::FETCH_EAGER: - $newValue = $this->em->getProxyFactory()->getProxy($assoc->targetEntity, $normalizedAssociatedId); - $this->registerManaged($newValue, $associatedId, []); - break; - - // Deferred eager load only works for single identifier classes - case isset($hints[self::HINT_DEFEREAGERLOAD]) && - $hints[self::HINT_DEFEREAGERLOAD] && - ! $targetClass->isIdentifierComposite: - // TODO: Is there a faster approach? - $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($normalizedAssociatedId); - - $newValue = $this->em->getProxyFactory()->getProxy($assoc->targetEntity, $normalizedAssociatedId); - $this->registerManaged($newValue, $associatedId, []); - break; - - default: - // TODO: This is very imperformant, ignore it? - $newValue = $this->em->find($assoc->targetEntity, $normalizedAssociatedId); - break; - } - } - - $this->originalEntityData[$oid][$field] = $newValue; - $class->reflFields[$field]->setValue($entity, $newValue); - - if ($assoc->inversedBy !== null && $assoc->isOneToOne() && $newValue !== null) { - $inverseAssoc = $targetClass->associationMappings[$assoc->inversedBy]; - $targetClass->reflFields[$inverseAssoc->fieldName]->setValue($newValue, $entity); - } - - break; - - default: - assert($assoc->isToMany()); - // Ignore if its a cached collection - if (isset($hints[Query::HINT_CACHE_ENABLED]) && $class->getFieldValue($entity, $field) instanceof PersistentCollection) { - break; - } - - // use the given collection - if (isset($data[$field]) && $data[$field] instanceof PersistentCollection) { - $data[$field]->setOwner($entity, $assoc); - - $class->reflFields[$field]->setValue($entity, $data[$field]); - $this->originalEntityData[$oid][$field] = $data[$field]; - - break; - } - - // Inject collection - $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection()); - $pColl->setOwner($entity, $assoc); - $pColl->setInitialized(false); - - $reflField = $class->reflFields[$field]; - $reflField->setValue($entity, $pColl); - - if ($hints['fetchMode'][$class->name][$field] === ClassMetadata::FETCH_EAGER) { - $isIteration = isset($hints[Query::HINT_INTERNAL_ITERATION]) && $hints[Query::HINT_INTERNAL_ITERATION]; - if (! $isIteration && $assoc->isOneToMany() && ! $targetClass->isIdentifierComposite && ! $assoc->isIndexed()) { - $this->scheduleCollectionForBatchLoading($pColl, $class); - } else { - $this->loadCollection($pColl); - $pColl->takeSnapshot(); - } - } - - $this->originalEntityData[$oid][$field] = $pColl; - break; - } - } - - // defer invoking of postLoad event to hydration complete step - $this->hydrationCompleteHandler->deferPostLoadInvoking($class, $entity); - - return $entity; - } - - public function triggerEagerLoads(): void - { - if (! $this->eagerLoadingEntities && ! $this->eagerLoadingCollections) { - return; - } - - // avoid infinite recursion - $eagerLoadingEntities = $this->eagerLoadingEntities; - $this->eagerLoadingEntities = []; - - foreach ($eagerLoadingEntities as $entityName => $ids) { - if (! $ids) { - continue; - } - - $class = $this->em->getClassMetadata($entityName); - $batches = array_chunk($ids, $this->em->getConfiguration()->getEagerFetchBatchSize()); - - foreach ($batches as $batchedIds) { - $this->getEntityPersister($entityName)->loadAll( - array_combine($class->identifier, [$batchedIds]), - ); - } - } - - $eagerLoadingCollections = $this->eagerLoadingCollections; // avoid recursion - $this->eagerLoadingCollections = []; - - foreach ($eagerLoadingCollections as $group) { - $this->eagerLoadCollections($group['items'], $group['mapping']); - } - } - - /** - * Load all data into the given collections, according to the specified mapping - * - * @param PersistentCollection[] $collections - */ - private function eagerLoadCollections(array $collections, ToManyInverseSideMapping $mapping): void - { - $targetEntity = $mapping->targetEntity; - $class = $this->em->getClassMetadata($mapping->sourceEntity); - $mappedBy = $mapping->mappedBy; - - $batches = array_chunk($collections, $this->em->getConfiguration()->getEagerFetchBatchSize(), true); - - foreach ($batches as $collectionBatch) { - $entities = []; - - foreach ($collectionBatch as $collection) { - $entities[] = $collection->getOwner(); - } - - $found = $this->getEntityPersister($targetEntity)->loadAll([$mappedBy => $entities], $mapping->orderBy); - - $targetClass = $this->em->getClassMetadata($targetEntity); - $targetProperty = $targetClass->getReflectionProperty($mappedBy); - assert($targetProperty !== null); - - foreach ($found as $targetValue) { - $sourceEntity = $targetProperty->getValue($targetValue); - - if ($sourceEntity === null && isset($targetClass->associationMappings[$mappedBy]->joinColumns)) { - // case where the hydration $targetValue itself has not yet fully completed, for example - // in case a bi-directional association is being hydrated and deferring eager loading is - // not possible due to subclassing. - $data = $this->getOriginalEntityData($targetValue); - $id = []; - foreach ($targetClass->associationMappings[$mappedBy]->joinColumns as $joinColumn) { - $id[] = $data[$joinColumn->name]; - } - } else { - $id = $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($sourceEntity)); - } - - $idHash = implode(' ', $id); - - if ($mapping->indexBy !== null) { - $indexByProperty = $targetClass->getReflectionProperty($mapping->indexBy); - assert($indexByProperty !== null); - $collectionBatch[$idHash]->hydrateSet($indexByProperty->getValue($targetValue), $targetValue); - } else { - $collectionBatch[$idHash]->add($targetValue); - } - } - } - - foreach ($collections as $association) { - $association->setInitialized(true); - $association->takeSnapshot(); - } - } - - /** - * Initializes (loads) an uninitialized persistent collection of an entity. - * - * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733. - */ - public function loadCollection(PersistentCollection $collection): void - { - $assoc = $collection->getMapping(); - $persister = $this->getEntityPersister($assoc->targetEntity); - - switch ($assoc->type()) { - case ClassMetadata::ONE_TO_MANY: - $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection); - break; - - case ClassMetadata::MANY_TO_MANY: - $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection); - break; - } - - $collection->setInitialized(true); - } - - /** - * Schedule this collection for batch loading at the end of the UnitOfWork - */ - private function scheduleCollectionForBatchLoading(PersistentCollection $collection, ClassMetadata $sourceClass): void - { - $mapping = $collection->getMapping(); - $name = $mapping->sourceEntity . '#' . $mapping->fieldName; - - if (! isset($this->eagerLoadingCollections[$name])) { - $this->eagerLoadingCollections[$name] = [ - 'items' => [], - 'mapping' => $mapping, - ]; - } - - $owner = $collection->getOwner(); - assert($owner !== null); - - $id = $this->identifierFlattener->flattenIdentifier( - $sourceClass, - $sourceClass->getIdentifierValues($owner), - ); - $idHash = implode(' ', $id); - - $this->eagerLoadingCollections[$name]['items'][$idHash] = $collection; - } - - /** - * Gets the identity map of the UnitOfWork. - * - * @psalm-return array> - */ - public function getIdentityMap(): array - { - return $this->identityMap; - } - - /** - * Gets the original data of an entity. The original data is the data that was - * present at the time the entity was reconstituted from the database. - * - * @psalm-return array - */ - public function getOriginalEntityData(object $entity): array - { - $oid = spl_object_id($entity); - - return $this->originalEntityData[$oid] ?? []; - } - - /** - * @param mixed[] $data - * - * @ignore - */ - public function setOriginalEntityData(object $entity, array $data): void - { - $this->originalEntityData[spl_object_id($entity)] = $data; - } - - /** - * INTERNAL: - * Sets a property value of the original data array of an entity. - * - * @ignore - */ - public function setOriginalEntityProperty(int $oid, string $property, mixed $value): void - { - $this->originalEntityData[$oid][$property] = $value; - } - - /** - * Gets the identifier of an entity. - * The returned value is always an array of identifier values. If the entity - * has a composite identifier then the identifier values are in the same - * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames(). - * - * @return mixed[] The identifier values. - */ - public function getEntityIdentifier(object $entity): array - { - return $this->entityIdentifiers[spl_object_id($entity)] - ?? throw EntityNotFoundException::noIdentifierFound(get_debug_type($entity)); - } - - /** - * Processes an entity instance to extract their identifier values. - * - * @return mixed A scalar value. - * - * @throws ORMInvalidArgumentException - */ - public function getSingleIdentifierValue(object $entity): mixed - { - $class = $this->em->getClassMetadata($entity::class); - - if ($class->isIdentifierComposite) { - throw ORMInvalidArgumentException::invalidCompositeIdentifier(); - } - - $values = $this->isInIdentityMap($entity) - ? $this->getEntityIdentifier($entity) - : $class->getIdentifierValues($entity); - - return $values[$class->identifier[0]] ?? null; - } - - /** - * Tries to find an entity with the given identifier in the identity map of - * this UnitOfWork. - * - * @param mixed $id The entity identifier to look for. - * @param string $rootClassName The name of the root class of the mapped entity hierarchy. - * @psalm-param class-string $rootClassName - * - * @return object|false Returns the entity with the specified identifier if it exists in - * this UnitOfWork, FALSE otherwise. - */ - public function tryGetById(mixed $id, string $rootClassName): object|false - { - $idHash = self::getIdHashByIdentifier((array) $id); - - return $this->identityMap[$rootClassName][$idHash] ?? false; - } - - /** - * Schedules an entity for dirty-checking at commit-time. - * - * @todo Rename: scheduleForSynchronization - */ - public function scheduleForDirtyCheck(object $entity): void - { - $rootClassName = $this->em->getClassMetadata($entity::class)->rootEntityName; - - $this->scheduledForSynchronization[$rootClassName][spl_object_id($entity)] = $entity; - } - - /** - * Checks whether the UnitOfWork has any pending insertions. - */ - public function hasPendingInsertions(): bool - { - return ! empty($this->entityInsertions); - } - - /** - * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the - * number of entities in the identity map. - */ - public function size(): int - { - return array_sum(array_map('count', $this->identityMap)); - } - - /** - * Gets the EntityPersister for an Entity. - * - * @psalm-param class-string $entityName - */ - public function getEntityPersister(string $entityName): EntityPersister - { - if (isset($this->persisters[$entityName])) { - return $this->persisters[$entityName]; - } - - $class = $this->em->getClassMetadata($entityName); - - $persister = match (true) { - $class->isInheritanceTypeNone() => new BasicEntityPersister($this->em, $class), - $class->isInheritanceTypeSingleTable() => new SingleTablePersister($this->em, $class), - $class->isInheritanceTypeJoined() => new JoinedSubclassPersister($this->em, $class), - default => throw new RuntimeException('No persister found for entity.'), - }; - - if ($this->hasCache && $class->cache !== null) { - $persister = $this->em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheFactory() - ->buildCachedEntityPersister($this->em, $persister, $class); - } - - $this->persisters[$entityName] = $persister; - - return $this->persisters[$entityName]; - } - - /** Gets a collection persister for a collection-valued association. */ - public function getCollectionPersister(AssociationMapping $association): CollectionPersister - { - $role = isset($association->cache) - ? $association->sourceEntity . '::' . $association->fieldName - : $association->type(); - - if (isset($this->collectionPersisters[$role])) { - return $this->collectionPersisters[$role]; - } - - $persister = $association->type() === ClassMetadata::ONE_TO_MANY - ? new OneToManyPersister($this->em) - : new ManyToManyPersister($this->em); - - if ($this->hasCache && isset($association->cache)) { - $persister = $this->em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheFactory() - ->buildCachedCollectionPersister($this->em, $persister, $association); - } - - $this->collectionPersisters[$role] = $persister; - - return $this->collectionPersisters[$role]; - } - - /** - * INTERNAL: - * Registers an entity as managed. - * - * @param mixed[] $id The identifier values. - * @param mixed[] $data The original entity data. - */ - public function registerManaged(object $entity, array $id, array $data): void - { - $oid = spl_object_id($entity); - - $this->entityIdentifiers[$oid] = $id; - $this->entityStates[$oid] = self::STATE_MANAGED; - $this->originalEntityData[$oid] = $data; - - $this->addToIdentityMap($entity); - } - - /* PropertyChangedListener implementation */ - - /** - * Notifies this UnitOfWork of a property change in an entity. - * - * {@inheritDoc} - */ - public function propertyChanged(object $sender, string $propertyName, mixed $oldValue, mixed $newValue): void - { - $oid = spl_object_id($sender); - $class = $this->em->getClassMetadata($sender::class); - - $isAssocField = isset($class->associationMappings[$propertyName]); - - if (! $isAssocField && ! isset($class->fieldMappings[$propertyName])) { - return; // ignore non-persistent fields - } - - // Update changeset and mark entity for synchronization - $this->entityChangeSets[$oid][$propertyName] = [$oldValue, $newValue]; - - if (! isset($this->scheduledForSynchronization[$class->rootEntityName][$oid])) { - $this->scheduleForDirtyCheck($sender); - } - } - - /** - * Gets the currently scheduled entity insertions in this UnitOfWork. - * - * @psalm-return array - */ - public function getScheduledEntityInsertions(): array - { - return $this->entityInsertions; - } - - /** - * Gets the currently scheduled entity updates in this UnitOfWork. - * - * @psalm-return array - */ - public function getScheduledEntityUpdates(): array - { - return $this->entityUpdates; - } - - /** - * Gets the currently scheduled entity deletions in this UnitOfWork. - * - * @psalm-return array - */ - public function getScheduledEntityDeletions(): array - { - return $this->entityDeletions; - } - - /** - * Gets the currently scheduled complete collection deletions - * - * @psalm-return array> - */ - public function getScheduledCollectionDeletions(): array - { - return $this->collectionDeletions; - } - - /** - * Gets the currently scheduled collection inserts, updates and deletes. - * - * @psalm-return array> - */ - public function getScheduledCollectionUpdates(): array - { - return $this->collectionUpdates; - } - - /** - * Helper method to initialize a lazy loading proxy or persistent collection. - */ - public function initializeObject(object $obj): void - { - if ($obj instanceof InternalProxy) { - $obj->__load(); - - return; - } - - if ($obj instanceof PersistentCollection) { - $obj->initialize(); - } - } - - /** - * Tests if a value is an uninitialized entity. - * - * @psalm-assert-if-true InternalProxy $obj - */ - public function isUninitializedObject(mixed $obj): bool - { - return $obj instanceof InternalProxy && ! $obj->__isInitialized(); - } - - /** - * Helper method to show an object as string. - */ - private static function objToStr(object $obj): string - { - return $obj instanceof Stringable ? (string) $obj : get_debug_type($obj) . '@' . spl_object_id($obj); - } - - /** - * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit(). - * - * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information - * on this object that might be necessary to perform a correct update. - * - * @throws ORMInvalidArgumentException - */ - public function markReadOnly(object $object): void - { - if (! $this->isInIdentityMap($object)) { - throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object); - } - - $this->readOnlyObjects[spl_object_id($object)] = true; - } - - /** - * Is this entity read only? - * - * @throws ORMInvalidArgumentException - */ - public function isReadOnly(object $object): bool - { - return isset($this->readOnlyObjects[spl_object_id($object)]); - } - - /** - * Perform whatever processing is encapsulated here after completion of the transaction. - */ - private function afterTransactionComplete(): void - { - $this->performCallbackOnCachedPersister(static function (CachedPersister $persister): void { - $persister->afterTransactionComplete(); - }); - } - - /** - * Perform whatever processing is encapsulated here after completion of the rolled-back. - */ - private function afterTransactionRolledBack(): void - { - $this->performCallbackOnCachedPersister(static function (CachedPersister $persister): void { - $persister->afterTransactionRolledBack(); - }); - } - - /** - * Performs an action after the transaction. - */ - private function performCallbackOnCachedPersister(callable $callback): void - { - if (! $this->hasCache) { - return; - } - - foreach ([...$this->persisters, ...$this->collectionPersisters] as $persister) { - if ($persister instanceof CachedPersister) { - $callback($persister); - } - } - } - - private function dispatchOnFlushEvent(): void - { - if ($this->evm->hasListeners(Events::onFlush)) { - $this->evm->dispatchEvent(Events::onFlush, new OnFlushEventArgs($this->em)); - } - } - - private function dispatchPostFlushEvent(): void - { - if ($this->evm->hasListeners(Events::postFlush)) { - $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em)); - } - } - - /** - * Verifies if two given entities actually are the same based on identifier comparison - */ - private function isIdentifierEquals(object $entity1, object $entity2): bool - { - if ($entity1 === $entity2) { - return true; - } - - $class = $this->em->getClassMetadata($entity1::class); - - if ($class !== $this->em->getClassMetadata($entity2::class)) { - return false; - } - - $oid1 = spl_object_id($entity1); - $oid2 = spl_object_id($entity2); - - $id1 = $this->entityIdentifiers[$oid1] ?? $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity1)); - $id2 = $this->entityIdentifiers[$oid2] ?? $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity2)); - - return $id1 === $id2 || self::getIdHashByIdentifier($id1) === self::getIdHashByIdentifier($id2); - } - - /** @throws ORMInvalidArgumentException */ - private function assertThatThereAreNoUnintentionallyNonPersistedAssociations(): void - { - $entitiesNeedingCascadePersist = array_diff_key($this->nonCascadedNewDetectedEntities, $this->entityInsertions); - - $this->nonCascadedNewDetectedEntities = []; - - if ($entitiesNeedingCascadePersist) { - throw ORMInvalidArgumentException::newEntitiesFoundThroughRelationships( - array_values($entitiesNeedingCascadePersist), - ); - } - } - - /** - * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle. - * Unit of work able to fire deferred events, related to loading events here. - * - * @internal should be called internally from object hydrators - */ - public function hydrationComplete(): void - { - $this->hydrationCompleteHandler->hydrationComplete(); - } - - /** @throws MappingException if the entity has more than a single identifier. */ - private function convertSingleFieldIdentifierToPHPValue(ClassMetadata $class, mixed $identifierValue): mixed - { - return $this->em->getConnection()->convertToPHPValue( - $identifierValue, - $class->getTypeOfField($class->getSingleIdentifierFieldName()), - ); - } - - /** - * Given a flat identifier, this method will produce another flat identifier, but with all - * association fields that are mapped as identifiers replaced by entity references, recursively. - * - * @param mixed[] $flatIdentifier - * - * @return array - */ - private function normalizeIdentifier(ClassMetadata $targetClass, array $flatIdentifier): array - { - $normalizedAssociatedId = []; - - foreach ($targetClass->getIdentifierFieldNames() as $name) { - if (! array_key_exists($name, $flatIdentifier)) { - continue; - } - - if (! $targetClass->isSingleValuedAssociation($name)) { - $normalizedAssociatedId[$name] = $flatIdentifier[$name]; - continue; - } - - $targetIdMetadata = $this->em->getClassMetadata($targetClass->getAssociationTargetClass($name)); - - // Note: the ORM prevents using an entity with a composite identifier as an identifier association - // therefore, reset($targetIdMetadata->identifier) is always correct - $normalizedAssociatedId[$name] = $this->em->getReference( - $targetIdMetadata->getName(), - $this->normalizeIdentifier( - $targetIdMetadata, - [(string) reset($targetIdMetadata->identifier) => $flatIdentifier[$name]], - ), - ); - } - - return $normalizedAssociatedId; - } - - /** - * Assign a post-insert generated ID to an entity - * - * This is used by EntityPersisters after they inserted entities into the database. - * It will place the assigned ID values in the entity's fields and start tracking - * the entity in the identity map. - */ - final public function assignPostInsertId(object $entity, mixed $generatedId): void - { - $class = $this->em->getClassMetadata($entity::class); - $idField = $class->getSingleIdentifierFieldName(); - $idValue = $this->convertSingleFieldIdentifierToPHPValue($class, $generatedId); - $oid = spl_object_id($entity); - - $class->reflFields[$idField]->setValue($entity, $idValue); - - $this->entityIdentifiers[$oid] = [$idField => $idValue]; - $this->entityStates[$oid] = self::STATE_MANAGED; - $this->originalEntityData[$oid][$idField] = $idValue; - - $this->addToIdentityMap($entity); - } -} diff --git a/vendor/doctrine/orm/src/Utility/HierarchyDiscriminatorResolver.php b/vendor/doctrine/orm/src/Utility/HierarchyDiscriminatorResolver.php deleted file mode 100644 index b682125..0000000 --- a/vendor/doctrine/orm/src/Utility/HierarchyDiscriminatorResolver.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ - public static function resolveDiscriminatorsForClass( - ClassMetadata $rootClassMetadata, - EntityManagerInterface $entityManager, - ): array { - $hierarchyClasses = $rootClassMetadata->subClasses; - $hierarchyClasses[] = $rootClassMetadata->name; - - $discriminators = []; - - foreach ($hierarchyClasses as $class) { - $currentMetadata = $entityManager->getClassMetadata($class); - $currentDiscriminator = $currentMetadata->discriminatorValue; - - if ($currentDiscriminator !== null) { - $discriminators[$currentDiscriminator] = null; - } - } - - return $discriminators; - } -} diff --git a/vendor/doctrine/orm/src/Utility/IdentifierFlattener.php b/vendor/doctrine/orm/src/Utility/IdentifierFlattener.php deleted file mode 100644 index 3792d33..0000000 --- a/vendor/doctrine/orm/src/Utility/IdentifierFlattener.php +++ /dev/null @@ -1,83 +0,0 @@ - - */ - public function flattenIdentifier(ClassMetadata $class, array $id): array - { - $flatId = []; - - foreach ($class->identifier as $field) { - if (isset($class->associationMappings[$field]) && isset($id[$field]) && is_a($id[$field], $class->associationMappings[$field]->targetEntity)) { - $targetClassMetadata = $this->metadataFactory->getMetadataFor( - $class->associationMappings[$field]->targetEntity, - ); - assert($targetClassMetadata instanceof ClassMetadata); - - if ($this->unitOfWork->isInIdentityMap($id[$field])) { - $associatedId = $this->flattenIdentifier($targetClassMetadata, $this->unitOfWork->getEntityIdentifier($id[$field])); - } else { - $associatedId = $this->flattenIdentifier($targetClassMetadata, $targetClassMetadata->getIdentifierValues($id[$field])); - } - - $flatId[$field] = implode(' ', $associatedId); - } elseif (isset($class->associationMappings[$field])) { - assert($class->associationMappings[$field]->isToOneOwningSide()); - $associatedId = []; - - foreach ($class->associationMappings[$field]->joinColumns as $joinColumn) { - $associatedId[] = $id[$joinColumn->name]; - } - - $flatId[$field] = implode(' ', $associatedId); - } else { - if ($id[$field] instanceof BackedEnum) { - $flatId[$field] = $id[$field]->value; - } else { - $flatId[$field] = $id[$field]; - } - } - } - - return $flatId; - } -} diff --git a/vendor/doctrine/orm/src/Utility/LockSqlHelper.php b/vendor/doctrine/orm/src/Utility/LockSqlHelper.php deleted file mode 100644 index 7d135eb..0000000 --- a/vendor/doctrine/orm/src/Utility/LockSqlHelper.php +++ /dev/null @@ -1,35 +0,0 @@ - 'LOCK IN SHARE MODE', - $platform instanceof PostgreSQLPlatform => 'FOR SHARE', - default => $this->getWriteLockSQL($platform), - }; - } - - private function getWriteLockSQL(AbstractPlatform $platform): string - { - return match (true) { - $platform instanceof DB2Platform => 'WITH RR USE AND KEEP UPDATE LOCKS', - $platform instanceof SQLitePlatform, - $platform instanceof SQLServerPlatform => '', - default => 'FOR UPDATE', - }; - } -} diff --git a/vendor/doctrine/orm/src/Utility/PersisterHelper.php b/vendor/doctrine/orm/src/Utility/PersisterHelper.php deleted file mode 100644 index 76e9242..0000000 --- a/vendor/doctrine/orm/src/Utility/PersisterHelper.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * @throws QueryException - */ - public static function getTypeOfField(string $fieldName, ClassMetadata $class, EntityManagerInterface $em): array - { - if (isset($class->fieldMappings[$fieldName])) { - return [$class->fieldMappings[$fieldName]->type]; - } - - if (! isset($class->associationMappings[$fieldName])) { - return []; - } - - $assoc = $class->associationMappings[$fieldName]; - - if (! $assoc->isOwningSide()) { - return self::getTypeOfField($assoc->mappedBy, $em->getClassMetadata($assoc->targetEntity), $em); - } - - if ($assoc->isManyToManyOwningSide()) { - $joinData = $assoc->joinTable; - } else { - $joinData = $assoc; - } - - $types = []; - $targetClass = $em->getClassMetadata($assoc->targetEntity); - - foreach ($joinData->joinColumns as $joinColumn) { - $types[] = self::getTypeOfColumn($joinColumn->referencedColumnName, $targetClass, $em); - } - - return $types; - } - - /** @throws RuntimeException */ - public static function getTypeOfColumn(string $columnName, ClassMetadata $class, EntityManagerInterface $em): string - { - if (isset($class->fieldNames[$columnName])) { - $fieldName = $class->fieldNames[$columnName]; - - if (isset($class->fieldMappings[$fieldName])) { - return $class->fieldMappings[$fieldName]->type; - } - } - - // iterate over to-one association mappings - foreach ($class->associationMappings as $assoc) { - if (! $assoc->isToOneOwningSide()) { - continue; - } - - foreach ($assoc->joinColumns as $joinColumn) { - if ($joinColumn->name === $columnName) { - $targetColumnName = $joinColumn->referencedColumnName; - $targetClass = $em->getClassMetadata($assoc->targetEntity); - - return self::getTypeOfColumn($targetColumnName, $targetClass, $em); - } - } - } - - // iterate over to-many association mappings - foreach ($class->associationMappings as $assoc) { - if (! $assoc->isManyToManyOwningSide()) { - continue; - } - - foreach ($assoc->joinTable->joinColumns as $joinColumn) { - if ($joinColumn->name === $columnName) { - $targetColumnName = $joinColumn->referencedColumnName; - $targetClass = $em->getClassMetadata($assoc->targetEntity); - - return self::getTypeOfColumn($targetColumnName, $targetClass, $em); - } - } - } - - throw new RuntimeException(sprintf( - 'Could not resolve type of column "%s" of class "%s"', - $columnName, - $class->getName(), - )); - } -} -- cgit v1.2.3