ing($mapping); } public function mapManyToMany(array $mapping) { $mapping['type'] = self::MANY_TO_MANY; $mapping = $this->_validateAndCompleteManyToManyMapping($mapping); $this->_storeAssociationMapping($mapping); } protected function _storeAssociationMapping(array $assocMapping) { $sourceFieldName = $assocMapping['fieldName']; $this->assertFieldNotMapped($sourceFieldName); $this->associationMappings[$sourceFieldName] = $assocMapping; } public function setCustomRepositoryClass($repositoryClassName) { $this->customRepositoryClassName = $this->fullyQualifiedClassName($repositoryClassName); } public function invokeLifecycleCallbacks($lifecycleEvent, $entity) { foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) { $entity->{$callback}(); } } public function hasLifecycleCallbacks($lifecycleEvent) { return isset($this->lifecycleCallbacks[$lifecycleEvent]); } public function getLifecycleCallbacks($event) { return $this->lifecycleCallbacks[$event] ?? []; } public function addLifecycleCallback($callback, $event) { if ($this->isEmbeddedClass) { Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/8381', 'Registering lifecycle callback %s on Embedded class %s is not doing anything and will throw exception in 3.0', $event, $this->name); } if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], \true)) { return; } $this->lifecycleCallbacks[$event][] = $callback; } public function setLifecycleCallbacks(array $callbacks) { $this->lifecycleCallbacks = $callbacks; } public function addEntityListener($eventName, $class, $method) { $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; } public function setDiscriminatorColumn($columnDef) { 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']); } if (!isset($columnDef['fieldName'])) { $columnDef['fieldName'] = $columnDef['name']; } if (!isset($columnDef['type'])) { $columnDef['type'] = 'string'; } if (in_array($columnDef['type'], ['boolean', 'array', 'object', 'datetime', 'time', 'date'], \true)) { throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']); } $this->discriminatorColumn = $columnDef; } } public final function getDiscriminatorColumn() : array { if ($this->discriminatorColumn === null) { throw new LogicException('The discriminator column was not set.'); } return $this->discriminatorColumn; } public function setDiscriminatorMap(array $map) { foreach ($map as $value => $className) { $this->addDiscriminatorMapClass($value, $className); } } public function addDiscriminatorMapClass($name, $className) { $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); } 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 \MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadataFactory::doLoadMetadata. if (is_subclass_of($className, $this->name) && !in_array($className, $this->subClasses, \true)) { $this->subClasses[] = $className; } } public function hasNamedQuery($queryName) { return isset($this->namedQueries[$queryName]); } public function hasNamedNativeQuery($queryName) { return isset($this->namedNativeQueries[$queryName]); } public function hasSqlResultSetMapping($name) { return isset($this->sqlResultSetMappings[$name]); } public function hasAssociation($fieldName) { return isset($this->associationMappings[$fieldName]); } public function isSingleValuedAssociation($fieldName) { return isset($this->associationMappings[$fieldName]) && $this->associationMappings[$fieldName]['type'] & self::TO_ONE; } public function isCollectionValuedAssociation($fieldName) { return isset($this->associationMappings[$fieldName]) && !($this->associationMappings[$fieldName]['type'] & self::TO_ONE); } public function isAssociationWithSingleJoinColumn($fieldName) { return isset($this->associationMappings[$fieldName]) && isset($this->associationMappings[$fieldName]['joinColumns'][0]) && !isset($this->associationMappings[$fieldName]['joinColumns'][1]); } public function getSingleAssociationJoinColumnName($fieldName) { if (!$this->isAssociationWithSingleJoinColumn($fieldName)) { throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); } return $this->associationMappings[$fieldName]['joinColumns'][0]['name']; } public function getSingleAssociationReferencedJoinColumnName($fieldName) { if (!$this->isAssociationWithSingleJoinColumn($fieldName)) { throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); } return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName']; } public function getFieldForColumn($columnName) { if (isset($this->fieldNames[$columnName])) { return $this->fieldNames[$columnName]; } foreach ($this->associationMappings as $assocName => $mapping) { if ($this->isAssociationWithSingleJoinColumn($assocName) && $this->associationMappings[$assocName]['joinColumns'][0]['name'] === $columnName) { return $assocName; } } throw MappingException::noFieldNameFoundForColumn($this->name, $columnName); } public function setIdGenerator($generator) { $this->idGenerator = $generator; } public function setCustomGeneratorDefinition(array $definition) { $this->customGeneratorDefinition = $definition; } public function setSequenceGeneratorDefinition(array $definition) { 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; } public function setVersionMapping(array &$mapping) { $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']); } } } public function setVersioned($bool) { $this->isVersioned = $bool; if ($bool) { $this->requiresFetchAfterChange = \true; } } public function setVersionField($versionField) { $this->versionField = $versionField; } public function markReadOnly() { $this->isReadOnly = \true; } public function getFieldNames() { return array_keys($this->fieldMappings); } public function getAssociationNames() { return array_keys($this->associationMappings); } public function getAssociationTargetClass($assocName) { if (!isset($this->associationMappings[$assocName])) { throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association."); } return $this->associationMappings[$assocName]['targetEntity']; } public function getName() { return $this->name; } public function getQuotedIdentifierColumnNames($platform) { $quotedColumnNames = []; foreach ($this->identifier as $idProperty) { if (isset($this->fieldMappings[$idProperty])) { $quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName']) : $this->fieldMappings[$idProperty]['columnName']; continue; } // Association defined as Id field $joinColumns = $this->associationMappings[$idProperty]['joinColumns']; $assocQuotedColumnNames = array_map(static function ($joinColumn) use($platform) { return isset($joinColumn['quoted']) ? $platform->quoteIdentifier($joinColumn['name']) : $joinColumn['name']; }, $joinColumns); $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames); } return $quotedColumnNames; } public function getQuotedColumnName($field, $platform) { return isset($this->fieldMappings[$field]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : $this->fieldMappings[$field]['columnName']; } public function getQuotedTableName($platform) { return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name']; } public function getQuotedJoinTableName(array $assoc, $platform) { return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name']; } public function isAssociationInverseSide($fieldName) { return isset($this->associationMappings[$fieldName]) && !$this->associationMappings[$fieldName]['isOwningSide']; } public function getAssociationMappedByTargetField($fieldName) { if (!$this->isAssociationInverseSide($fieldName)) { Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/11309', 'Calling %s with owning side field %s is deprecated and will no longer be supported in Doctrine ORM 3.0. Call %s::isAssociationInverseSide() to check first.', __METHOD__, $fieldName, self::class); } return $this->associationMappings[$fieldName]['mappedBy']; } public function getAssociationsByTargetClass($targetClass) { $relations = []; foreach ($this->associationMappings as $mapping) { if ($mapping['targetEntity'] === $targetClass) { $relations[$mapping['fieldName']] = $mapping; } } return $relations; } public function fullyQualifiedClassName($className) { if (empty($className)) { return $className; } if (!str_contains($className, '\\') && $this->namespace) { return $this->namespace . '\\' . $className; } return $className; } public function getMetadataValue($name) { if (isset($this->{$name})) { return $this->{$name}; } return null; } public function mapEmbedded(array $mapping) { $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']); } $fqcn = $this->fullyQualifiedClassName($mapping['class']); assert($fqcn !== null); $this->embeddedClasses[$mapping['fieldName']] = ['class' => $fqcn, 'columnPrefix' => $mapping['columnPrefix'] ?? null, 'declaredField' => $mapping['declaredField'] ?? null, 'originalField' => $mapping['originalField'] ?? null]; } public function inlineEmbeddable($property, ClassMetadataInfo $embeddable) { foreach ($embeddable->fieldMappings as $fieldMapping) { $fieldMapping['originalClass'] = $fieldMapping['originalClass'] ?? $embeddable->name; $fieldMapping['declaredField'] = isset($fieldMapping['declaredField']) ? $property . '.' . $fieldMapping['declaredField'] : $property; $fieldMapping['originalField'] = $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) { $fieldMapping['columnName'] = $this->namingStrategy->embeddedFieldToColumnName($property, $fieldMapping['columnName'], $this->reflClass->name, $embeddable->reflClass->name); } $this->mapField($fieldMapping); } } 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); } } public function getSequenceName(AbstractPlatform $platform) { $sequencePrefix = $this->getSequencePrefix($platform); $columnName = $this->getSingleIdentifierColumnName(); return $sequencePrefix . '_' . $columnName . '_seq'; } public function getSequencePrefix(AbstractPlatform $platform) { $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; // @phpstan-ignore method.deprecated if (!$platform->supportsSchemas() && $platform->canEmulateSchemas()) { $sequencePrefix = $schemaName . '__' . $tableName; } } return $sequencePrefix; } private function assertMappingOrderBy(array $mapping) : void { if (isset($mapping['orderBy']) && !is_array($mapping['orderBy'])) { throw new InvalidArgumentException("'orderBy' is expected to be an array, not " . gettype($mapping['orderBy'])); } } private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field) : ?ReflectionProperty { $reflectionProperty = $reflService->getAccessibleProperty($class, $field); if ($reflectionProperty !== null && PHP_VERSION_ID >= 80100 && $reflectionProperty->isReadOnly()) { $declaringClass = $reflectionProperty->class; if ($declaringClass !== $class) { $reflectionProperty = $reflService->getAccessibleProperty($declaringClass, $field); } if ($reflectionProperty !== null) { $reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty); } } if (PHP_VERSION_ID >= 80400 && $reflectionProperty !== null && count($reflectionProperty->getHooks()) > 0) { throw new LogicException('Doctrine ORM does not support property hooks in this version. Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.'); } return $reflectionProperty; } }