PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.36.0
MailPoet – Newsletters, Email Marketing, and Automation v5.36.0
5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / doctrine / orm / src / Mapping / ClassMetadataInfo.php
mailpoet / vendor-prefixed / doctrine / orm / src / Mapping Last commit date
Builder 9 months ago Driver 9 months ago Exception 9 months ago Reflection 9 months ago Annotation.php 9 months ago AnsiQuoteStrategy.php 9 months ago AssociationOverride.php 9 months ago AssociationOverrides.php 9 months ago AttributeOverride.php 9 months ago AttributeOverrides.php 9 months ago Cache.php 9 months ago ChainTypedFieldMapper.php 9 months ago ChangeTrackingPolicy.php 9 months ago ClassMetadata.php 9 months ago ClassMetadataFactory.php 9 months ago ClassMetadataInfo.php 9 months ago Column.php 9 months ago ColumnResult.php 9 months ago CustomIdGenerator.php 9 months ago DefaultEntityListenerResolver.php 9 months ago DefaultNamingStrategy.php 9 months ago DefaultQuoteStrategy.php 9 months ago DefaultTypedFieldMapper.php 9 months ago DiscriminatorColumn.php 9 months ago DiscriminatorMap.php 9 months ago Embeddable.php 9 months ago Embedded.php 9 months ago Entity.php 9 months ago EntityListenerResolver.php 9 months ago EntityListeners.php 9 months ago EntityResult.php 9 months ago FieldResult.php 9 months ago GeneratedValue.php 9 months ago HasLifecycleCallbacks.php 9 months ago Id.php 9 months ago Index.php 9 months ago InheritanceType.php 9 months ago InverseJoinColumn.php 9 months ago JoinColumn.php 9 months ago JoinColumnProperties.php 9 months ago JoinColumns.php 9 months ago JoinTable.php 9 months ago ManyToMany.php 9 months ago ManyToOne.php 9 months ago MappedSuperclass.php 9 months ago MappingAttribute.php 9 months ago MappingException.php 9 months ago NamedNativeQueries.php 9 months ago NamedNativeQuery.php 9 months ago NamedQueries.php 9 months ago NamedQuery.php 9 months ago NamingStrategy.php 9 months ago OneToMany.php 9 months ago OneToOne.php 9 months ago OrderBy.php 9 months ago PostLoad.php 9 months ago PostPersist.php 9 months ago PostRemove.php 9 months ago PostUpdate.php 9 months ago PreFlush.php 9 months ago PrePersist.php 9 months ago PreRemove.php 9 months ago PreUpdate.php 9 months ago QuoteStrategy.php 9 months ago ReflectionEmbeddedProperty.php 9 months ago ReflectionEnumProperty.php 9 months ago ReflectionReadonlyProperty.php 9 months ago SequenceGenerator.php 9 months ago SqlResultSetMapping.php 9 months ago SqlResultSetMappings.php 9 months ago Table.php 9 months ago TypedFieldMapper.php 9 months ago UnderscoreNamingStrategy.php 9 months ago UniqueConstraint.php 9 months ago Version.php 9 months ago
ClassMetadataInfo.php
1588 lines
1 <?php
2 declare (strict_types=1);
3 namespace MailPoetVendor\Doctrine\ORM\Mapping;
4 if (!defined('ABSPATH')) exit;
5 use BackedEnum;
6 use BadMethodCallException;
7 use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractPlatform;
8 use MailPoetVendor\Doctrine\DBAL\Types\Type;
9 use MailPoetVendor\Doctrine\Deprecations\Deprecation;
10 use MailPoetVendor\Doctrine\Instantiator\Instantiator;
11 use MailPoetVendor\Doctrine\Instantiator\InstantiatorInterface;
12 use MailPoetVendor\Doctrine\ORM\Cache\Exception\NonCacheableEntityAssociation;
13 use MailPoetVendor\Doctrine\ORM\EntityRepository;
14 use MailPoetVendor\Doctrine\ORM\Id\AbstractIdGenerator;
15 use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata;
16 use MailPoetVendor\Doctrine\Persistence\Mapping\ReflectionService;
17 use InvalidArgumentException;
18 use LogicException;
19 use ReflectionClass;
20 use ReflectionNamedType;
21 use ReflectionProperty;
22 use RuntimeException;
23 use function array_diff;
24 use function array_flip;
25 use function array_intersect;
26 use function array_keys;
27 use function array_map;
28 use function array_merge;
29 use function array_pop;
30 use function array_values;
31 use function assert;
32 use function class_exists;
33 use function count;
34 use function enum_exists;
35 use function explode;
36 use function gettype;
37 use function in_array;
38 use function interface_exists;
39 use function is_array;
40 use function is_subclass_of;
41 use function ltrim;
42 use function method_exists;
43 use function spl_object_id;
44 use function str_contains;
45 use function str_replace;
46 use function strtolower;
47 use function trait_exists;
48 use function trim;
49 use const PHP_VERSION_ID;
50 class ClassMetadataInfo implements ClassMetadata
51 {
52 public const INHERITANCE_TYPE_NONE = 1;
53 public const INHERITANCE_TYPE_JOINED = 2;
54 public const INHERITANCE_TYPE_SINGLE_TABLE = 3;
55 public const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
56 public const GENERATOR_TYPE_AUTO = 1;
57 public const GENERATOR_TYPE_SEQUENCE = 2;
58 public const GENERATOR_TYPE_TABLE = 3;
59 public const GENERATOR_TYPE_IDENTITY = 4;
60 public const GENERATOR_TYPE_NONE = 5;
61 public const GENERATOR_TYPE_UUID = 6;
62 public const GENERATOR_TYPE_CUSTOM = 7;
63 public const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
64 public const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
65 public const CHANGETRACKING_NOTIFY = 3;
66 public const FETCH_LAZY = 2;
67 public const FETCH_EAGER = 3;
68 public const FETCH_EXTRA_LAZY = 4;
69 public const ONE_TO_ONE = 1;
70 public const MANY_TO_ONE = 2;
71 public const ONE_TO_MANY = 4;
72 public const MANY_TO_MANY = 8;
73 public const TO_ONE = 3;
74 public const TO_MANY = 12;
75 public const CACHE_USAGE_READ_ONLY = 1;
76 public const CACHE_USAGE_NONSTRICT_READ_WRITE = 2;
77 public const CACHE_USAGE_READ_WRITE = 3;
78 public const GENERATED_NEVER = 0;
79 public const GENERATED_INSERT = 1;
80 public const GENERATED_ALWAYS = 2;
81 public $name;
82 public $namespace;
83 public $rootEntityName;
84 public $customGeneratorDefinition;
85 public $customRepositoryClassName;
86 public $isMappedSuperclass = \false;
87 public $isEmbeddedClass = \false;
88 public $parentClasses = [];
89 public $subClasses = [];
90 public $embeddedClasses = [];
91 public $namedQueries = [];
92 public $namedNativeQueries = [];
93 public $sqlResultSetMappings = [];
94 public $identifier = [];
95 public $inheritanceType = self::INHERITANCE_TYPE_NONE;
96 public $generatorType = self::GENERATOR_TYPE_NONE;
97 public $fieldMappings = [];
98 public $fieldNames = [];
99 public $columnNames = [];
100 public $discriminatorValue;
101 public $discriminatorMap = [];
102 public $discriminatorColumn;
103 public $table;
104 public $lifecycleCallbacks = [];
105 public $entityListeners = [];
106 public $associationMappings = [];
107 public $isIdentifierComposite = \false;
108 public $containsForeignIdentifier = \false;
109 public $containsEnumIdentifier = \false;
110 public $idGenerator;
111 public $sequenceGeneratorDefinition;
112 public $tableGeneratorDefinition;
113 public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
114 public $requiresFetchAfterChange = \false;
115 public $isVersioned = \false;
116 public $versionField;
117 public $cache;
118 public $reflClass;
119 public $isReadOnly = \false;
120 protected $namingStrategy;
121 public $reflFields = [];
122 private $instantiator;
123 private $typedFieldMapper;
124 public function __construct($entityName, ?NamingStrategy $namingStrategy = null, ?TypedFieldMapper $typedFieldMapper = null)
125 {
126 $this->name = $entityName;
127 $this->rootEntityName = $entityName;
128 $this->namingStrategy = $namingStrategy ?? new DefaultNamingStrategy();
129 $this->instantiator = new Instantiator();
130 $this->typedFieldMapper = $typedFieldMapper ?? new DefaultTypedFieldMapper();
131 }
132 public function getReflectionProperties()
133 {
134 return $this->reflFields;
135 }
136 public function getReflectionProperty($name)
137 {
138 return $this->reflFields[$name];
139 }
140 public function getSingleIdReflectionProperty()
141 {
142 if ($this->isIdentifierComposite) {
143 throw new BadMethodCallException('Class ' . $this->name . ' has a composite identifier.');
144 }
145 return $this->reflFields[$this->identifier[0]];
146 }
147 public function getIdentifierValues($entity)
148 {
149 if ($this->isIdentifierComposite) {
150 $id = [];
151 foreach ($this->identifier as $idField) {
152 $value = $this->reflFields[$idField]->getValue($entity);
153 if ($value !== null) {
154 $id[$idField] = $value;
155 }
156 }
157 return $id;
158 }
159 $id = $this->identifier[0];
160 $value = $this->reflFields[$id]->getValue($entity);
161 if ($value === null) {
162 return [];
163 }
164 return [$id => $value];
165 }
166 public function setIdentifierValues($entity, array $id)
167 {
168 foreach ($id as $idField => $idValue) {
169 $this->reflFields[$idField]->setValue($entity, $idValue);
170 }
171 }
172 public function setFieldValue($entity, $field, $value)
173 {
174 $this->reflFields[$field]->setValue($entity, $value);
175 }
176 public function getFieldValue($entity, $field)
177 {
178 return $this->reflFields[$field]->getValue($entity);
179 }
180 public function __toString()
181 {
182 return self::class . '@' . spl_object_id($this);
183 }
184 public function __sleep()
185 {
186 // This metadata is always serialized/cached.
187 $serialized = [
188 'associationMappings',
189 'columnNames',
190 //TODO: 3.0 Remove this. Can use fieldMappings[$fieldName]['columnName']
191 'fieldMappings',
192 'fieldNames',
193 'embeddedClasses',
194 'identifier',
195 'isIdentifierComposite',
196 // TODO: REMOVE
197 'name',
198 'namespace',
199 // TODO: REMOVE
200 'table',
201 'rootEntityName',
202 'idGenerator',
203 ];
204 // The rest of the metadata is only serialized if necessary.
205 if ($this->changeTrackingPolicy !== self::CHANGETRACKING_DEFERRED_IMPLICIT) {
206 $serialized[] = 'changeTrackingPolicy';
207 }
208 if ($this->customRepositoryClassName) {
209 $serialized[] = 'customRepositoryClassName';
210 }
211 if ($this->inheritanceType !== self::INHERITANCE_TYPE_NONE) {
212 $serialized[] = 'inheritanceType';
213 $serialized[] = 'discriminatorColumn';
214 $serialized[] = 'discriminatorValue';
215 $serialized[] = 'discriminatorMap';
216 $serialized[] = 'parentClasses';
217 $serialized[] = 'subClasses';
218 }
219 if ($this->generatorType !== self::GENERATOR_TYPE_NONE) {
220 $serialized[] = 'generatorType';
221 if ($this->generatorType === self::GENERATOR_TYPE_SEQUENCE) {
222 $serialized[] = 'sequenceGeneratorDefinition';
223 }
224 }
225 if ($this->isMappedSuperclass) {
226 $serialized[] = 'isMappedSuperclass';
227 }
228 if ($this->isEmbeddedClass) {
229 $serialized[] = 'isEmbeddedClass';
230 }
231 if ($this->containsForeignIdentifier) {
232 $serialized[] = 'containsForeignIdentifier';
233 }
234 if ($this->containsEnumIdentifier) {
235 $serialized[] = 'containsEnumIdentifier';
236 }
237 if ($this->isVersioned) {
238 $serialized[] = 'isVersioned';
239 $serialized[] = 'versionField';
240 }
241 if ($this->lifecycleCallbacks) {
242 $serialized[] = 'lifecycleCallbacks';
243 }
244 if ($this->entityListeners) {
245 $serialized[] = 'entityListeners';
246 }
247 if ($this->namedQueries) {
248 $serialized[] = 'namedQueries';
249 }
250 if ($this->namedNativeQueries) {
251 $serialized[] = 'namedNativeQueries';
252 }
253 if ($this->sqlResultSetMappings) {
254 $serialized[] = 'sqlResultSetMappings';
255 }
256 if ($this->isReadOnly) {
257 $serialized[] = 'isReadOnly';
258 }
259 if ($this->customGeneratorDefinition) {
260 $serialized[] = 'customGeneratorDefinition';
261 }
262 if ($this->cache) {
263 $serialized[] = 'cache';
264 }
265 if ($this->requiresFetchAfterChange) {
266 $serialized[] = 'requiresFetchAfterChange';
267 }
268 return $serialized;
269 }
270 public function newInstance()
271 {
272 return $this->instantiator->instantiate($this->name);
273 }
274 public function wakeupReflection($reflService)
275 {
276 // Restore ReflectionClass and properties
277 $this->reflClass = $reflService->getClass($this->name);
278 $this->instantiator = $this->instantiator ?: new Instantiator();
279 $parentReflFields = [];
280 foreach ($this->embeddedClasses as $property => $embeddedClass) {
281 if (isset($embeddedClass['declaredField'])) {
282 assert($embeddedClass['originalField'] !== null);
283 $childProperty = $this->getAccessibleProperty($reflService, $this->embeddedClasses[$embeddedClass['declaredField']]['class'], $embeddedClass['originalField']);
284 assert($childProperty !== null);
285 $parentReflFields[$property] = new ReflectionEmbeddedProperty($parentReflFields[$embeddedClass['declaredField']], $childProperty, $this->embeddedClasses[$embeddedClass['declaredField']]['class']);
286 continue;
287 }
288 $fieldRefl = $this->getAccessibleProperty($reflService, $embeddedClass['declared'] ?? $this->name, $property);
289 $parentReflFields[$property] = $fieldRefl;
290 $this->reflFields[$property] = $fieldRefl;
291 }
292 foreach ($this->fieldMappings as $field => $mapping) {
293 if (isset($mapping['declaredField']) && isset($parentReflFields[$mapping['declaredField']])) {
294 $childProperty = $this->getAccessibleProperty($reflService, $mapping['originalClass'], $mapping['originalField']);
295 assert($childProperty !== null);
296 if (isset($mapping['enumType'])) {
297 $childProperty = new ReflectionEnumProperty($childProperty, $mapping['enumType']);
298 }
299 $this->reflFields[$field] = new ReflectionEmbeddedProperty($parentReflFields[$mapping['declaredField']], $childProperty, $mapping['originalClass']);
300 continue;
301 }
302 $this->reflFields[$field] = isset($mapping['declared']) ? $this->getAccessibleProperty($reflService, $mapping['declared'], $field) : $this->getAccessibleProperty($reflService, $this->name, $field);
303 if (isset($mapping['enumType']) && $this->reflFields[$field] !== null) {
304 $this->reflFields[$field] = new ReflectionEnumProperty($this->reflFields[$field], $mapping['enumType']);
305 }
306 }
307 foreach ($this->associationMappings as $field => $mapping) {
308 $this->reflFields[$field] = isset($mapping['declared']) ? $this->getAccessibleProperty($reflService, $mapping['declared'], $field) : $this->getAccessibleProperty($reflService, $this->name, $field);
309 }
310 }
311 public function initializeReflection($reflService)
312 {
313 $this->reflClass = $reflService->getClass($this->name);
314 $this->namespace = $reflService->getClassNamespace($this->name);
315 if ($this->reflClass) {
316 $this->name = $this->rootEntityName = $this->reflClass->name;
317 }
318 $this->table['name'] = $this->namingStrategy->classToTableName($this->name);
319 }
320 public function validateIdentifier()
321 {
322 if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
323 return;
324 }
325 // Verify & complete identifier mapping
326 if (!$this->identifier) {
327 throw MappingException::identifierRequired($this->name);
328 }
329 if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
330 throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
331 }
332 }
333 public function validateAssociations()
334 {
335 foreach ($this->associationMappings as $mapping) {
336 if (!class_exists($mapping['targetEntity']) && !interface_exists($mapping['targetEntity']) && !trait_exists($mapping['targetEntity'])) {
337 throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
338 }
339 }
340 }
341 public function validateLifecycleCallbacks($reflService)
342 {
343 foreach ($this->lifecycleCallbacks as $callbacks) {
344 foreach ($callbacks as $callbackFuncName) {
345 if (!$reflService->hasPublicMethod($this->name, $callbackFuncName)) {
346 throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
347 }
348 }
349 }
350 }
351 public function getReflectionClass()
352 {
353 return $this->reflClass;
354 }
355 public function enableCache(array $cache)
356 {
357 if (!isset($cache['usage'])) {
358 $cache['usage'] = self::CACHE_USAGE_READ_ONLY;
359 }
360 if (!isset($cache['region'])) {
361 $cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName));
362 }
363 $this->cache = $cache;
364 }
365 public function enableAssociationCache($fieldName, array $cache)
366 {
367 $this->associationMappings[$fieldName]['cache'] = $this->getAssociationCacheDefaults($fieldName, $cache);
368 }
369 public function getAssociationCacheDefaults($fieldName, array $cache)
370 {
371 if (!isset($cache['usage'])) {
372 $cache['usage'] = $this->cache['usage'] ?? self::CACHE_USAGE_READ_ONLY;
373 }
374 if (!isset($cache['region'])) {
375 $cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName)) . '__' . $fieldName;
376 }
377 return $cache;
378 }
379 public function setChangeTrackingPolicy($policy)
380 {
381 $this->changeTrackingPolicy = $policy;
382 }
383 public function isChangeTrackingDeferredExplicit()
384 {
385 return $this->changeTrackingPolicy === self::CHANGETRACKING_DEFERRED_EXPLICIT;
386 }
387 public function isChangeTrackingDeferredImplicit()
388 {
389 return $this->changeTrackingPolicy === self::CHANGETRACKING_DEFERRED_IMPLICIT;
390 }
391 public function isChangeTrackingNotify()
392 {
393 return $this->changeTrackingPolicy === self::CHANGETRACKING_NOTIFY;
394 }
395 public function isIdentifier($fieldName)
396 {
397 if (!$this->identifier) {
398 return \false;
399 }
400 if (!$this->isIdentifierComposite) {
401 return $fieldName === $this->identifier[0];
402 }
403 return in_array($fieldName, $this->identifier, \true);
404 }
405 public function isUniqueField($fieldName)
406 {
407 $mapping = $this->getFieldMapping($fieldName);
408 return $mapping !== \false && isset($mapping['unique']) && $mapping['unique'];
409 }
410 public function isNullable($fieldName)
411 {
412 $mapping = $this->getFieldMapping($fieldName);
413 return $mapping !== \false && isset($mapping['nullable']) && $mapping['nullable'];
414 }
415 public function getColumnName($fieldName)
416 {
417 // @phpstan-ignore property.deprecated
418 return $this->columnNames[$fieldName] ?? $fieldName;
419 }
420 public function getFieldMapping($fieldName)
421 {
422 if (!isset($this->fieldMappings[$fieldName])) {
423 throw MappingException::mappingNotFound($this->name, $fieldName);
424 }
425 return $this->fieldMappings[$fieldName];
426 }
427 public function getAssociationMapping($fieldName)
428 {
429 if (!isset($this->associationMappings[$fieldName])) {
430 throw MappingException::mappingNotFound($this->name, $fieldName);
431 }
432 return $this->associationMappings[$fieldName];
433 }
434 public function getAssociationMappings()
435 {
436 return $this->associationMappings;
437 }
438 public function getFieldName($columnName)
439 {
440 return $this->fieldNames[$columnName] ?? $columnName;
441 }
442 public function getNamedQuery($queryName)
443 {
444 if (!isset($this->namedQueries[$queryName])) {
445 throw MappingException::queryNotFound($this->name, $queryName);
446 }
447 return $this->namedQueries[$queryName]['dql'];
448 }
449 public function getNamedQueries()
450 {
451 return $this->namedQueries;
452 }
453 public function getNamedNativeQuery($queryName)
454 {
455 if (!isset($this->namedNativeQueries[$queryName])) {
456 throw MappingException::queryNotFound($this->name, $queryName);
457 }
458 return $this->namedNativeQueries[$queryName];
459 }
460 public function getNamedNativeQueries()
461 {
462 return $this->namedNativeQueries;
463 }
464 public function getSqlResultSetMapping($name)
465 {
466 if (!isset($this->sqlResultSetMappings[$name])) {
467 throw MappingException::resultMappingNotFound($this->name, $name);
468 }
469 return $this->sqlResultSetMappings[$name];
470 }
471 public function getSqlResultSetMappings()
472 {
473 return $this->sqlResultSetMappings;
474 }
475 private function isTypedProperty(string $name) : bool
476 {
477 return PHP_VERSION_ID >= 70400 && isset($this->reflClass) && $this->reflClass->hasProperty($name) && $this->reflClass->getProperty($name)->hasType();
478 }
479 private function validateAndCompleteTypedFieldMapping(array $mapping) : array
480 {
481 $field = $this->reflClass->getProperty($mapping['fieldName']);
482 $mapping = $this->typedFieldMapper->validateAndComplete($mapping, $field);
483 return $mapping;
484 }
485 private function validateAndCompleteTypedAssociationMapping(array $mapping) : array
486 {
487 $type = $this->reflClass->getProperty($mapping['fieldName'])->getType();
488 if ($type === null || ($mapping['type'] & self::TO_ONE) === 0) {
489 return $mapping;
490 }
491 if (!isset($mapping['targetEntity']) && $type instanceof ReflectionNamedType) {
492 $mapping['targetEntity'] = $type->getName();
493 }
494 return $mapping;
495 }
496 protected function validateAndCompleteFieldMapping(array $mapping) : array
497 {
498 // Check mandatory fields
499 if (!isset($mapping['fieldName']) || !$mapping['fieldName']) {
500 throw MappingException::missingFieldName($this->name);
501 }
502 if ($this->isTypedProperty($mapping['fieldName'])) {
503 $mapping = $this->validateAndCompleteTypedFieldMapping($mapping);
504 }
505 if (!isset($mapping['type'])) {
506 // Default to string
507 $mapping['type'] = 'string';
508 }
509 // Complete fieldName and columnName mapping
510 if (!isset($mapping['columnName'])) {
511 $mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName'], $this->name);
512 }
513 if ($mapping['columnName'][0] === '`') {
514 $mapping['columnName'] = trim($mapping['columnName'], '`');
515 $mapping['quoted'] = \true;
516 }
517 // @phpstan-ignore property.deprecated
518 $this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
519 if (isset($this->fieldNames[$mapping['columnName']]) || $this->discriminatorColumn && $this->discriminatorColumn['name'] === $mapping['columnName']) {
520 throw MappingException::duplicateColumnName($this->name, $mapping['columnName']);
521 }
522 $this->fieldNames[$mapping['columnName']] = $mapping['fieldName'];
523 // Complete id mapping
524 if (isset($mapping['id']) && $mapping['id'] === \true) {
525 if ($this->versionField === $mapping['fieldName']) {
526 throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
527 }
528 if (!in_array($mapping['fieldName'], $this->identifier, \true)) {
529 $this->identifier[] = $mapping['fieldName'];
530 }
531 // Check for composite key
532 if (!$this->isIdentifierComposite && count($this->identifier) > 1) {
533 $this->isIdentifierComposite = \true;
534 }
535 }
536 // @phpstan-ignore method.deprecated
537 if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
538 if (isset($mapping['id']) && $mapping['id'] === \true) {
539 throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
540 }
541 $mapping['requireSQLConversion'] = \true;
542 }
543 if (isset($mapping['generated'])) {
544 if (!in_array($mapping['generated'], [self::GENERATED_NEVER, self::GENERATED_INSERT, self::GENERATED_ALWAYS])) {
545 throw MappingException::invalidGeneratedMode($mapping['generated']);
546 }
547 if ($mapping['generated'] === self::GENERATED_NEVER) {
548 unset($mapping['generated']);
549 }
550 }
551 if (isset($mapping['enumType'])) {
552 if (PHP_VERSION_ID < 80100) {
553 throw MappingException::enumsRequirePhp81($this->name, $mapping['fieldName']);
554 }
555 if (!enum_exists($mapping['enumType'])) {
556 throw MappingException::nonEnumTypeMapped($this->name, $mapping['fieldName'], $mapping['enumType']);
557 }
558 if (!empty($mapping['id'])) {
559 $this->containsEnumIdentifier = \true;
560 }
561 }
562 return $mapping;
563 }
564 protected function _validateAndCompleteAssociationMapping(array $mapping)
565 {
566 if (!isset($mapping['mappedBy'])) {
567 $mapping['mappedBy'] = null;
568 }
569 if (!isset($mapping['inversedBy'])) {
570 $mapping['inversedBy'] = null;
571 }
572 $mapping['isOwningSide'] = \true;
573 // assume owning side until we hit mappedBy
574 if (empty($mapping['indexBy'])) {
575 unset($mapping['indexBy']);
576 }
577 // If targetEntity is unqualified, assume it is in the same namespace as
578 // the sourceEntity.
579 $mapping['sourceEntity'] = $this->name;
580 if ($this->isTypedProperty($mapping['fieldName'])) {
581 $mapping = $this->validateAndCompleteTypedAssociationMapping($mapping);
582 }
583 if (isset($mapping['targetEntity'])) {
584 $mapping['targetEntity'] = $this->fullyQualifiedClassName($mapping['targetEntity']);
585 $mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
586 }
587 if (($mapping['type'] & self::MANY_TO_ONE) > 0 && isset($mapping['orphanRemoval']) && $mapping['orphanRemoval']) {
588 throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
589 }
590 // Complete id mapping
591 if (isset($mapping['id']) && $mapping['id'] === \true) {
592 if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval']) {
593 throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
594 }
595 if (!in_array($mapping['fieldName'], $this->identifier, \true)) {
596 if (isset($mapping['joinColumns']) && count($mapping['joinColumns']) >= 2) {
597 throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId($mapping['targetEntity'], $this->name, $mapping['fieldName']);
598 }
599 $this->identifier[] = $mapping['fieldName'];
600 $this->containsForeignIdentifier = \true;
601 }
602 // Check for composite key
603 if (!$this->isIdentifierComposite && count($this->identifier) > 1) {
604 $this->isIdentifierComposite = \true;
605 }
606 if ($this->cache && !isset($mapping['cache'])) {
607 throw NonCacheableEntityAssociation::fromEntityAndField($this->name, $mapping['fieldName']);
608 }
609 }
610 // Mandatory attributes for both sides
611 // Mandatory: fieldName, targetEntity
612 if (!isset($mapping['fieldName']) || !$mapping['fieldName']) {
613 throw MappingException::missingFieldName($this->name);
614 }
615 if (!isset($mapping['targetEntity'])) {
616 throw MappingException::missingTargetEntity($mapping['fieldName']);
617 }
618 // Mandatory and optional attributes for either side
619 if (!$mapping['mappedBy']) {
620 if (isset($mapping['joinTable']) && $mapping['joinTable']) {
621 if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') {
622 $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
623 $mapping['joinTable']['quoted'] = \true;
624 }
625 }
626 } else {
627 $mapping['isOwningSide'] = \false;
628 }
629 if (isset($mapping['id']) && $mapping['id'] === \true && $mapping['type'] & self::TO_MANY) {
630 throw MappingException::illegalToManyIdentifierAssociation($this->name, $mapping['fieldName']);
631 }
632 // Fetch mode. Default fetch mode to LAZY, if not set.
633 if (!isset($mapping['fetch'])) {
634 $mapping['fetch'] = self::FETCH_LAZY;
635 }
636 // Cascades
637 $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : [];
638 $allCascades = ['remove', 'persist', 'refresh', 'merge', 'detach'];
639 if (in_array('all', $cascades, \true)) {
640 $cascades = $allCascades;
641 } elseif (count($cascades) !== count(array_intersect($cascades, $allCascades))) {
642 throw MappingException::invalidCascadeOption(array_diff($cascades, $allCascades), $this->name, $mapping['fieldName']);
643 }
644 $mapping['cascade'] = $cascades;
645 $mapping['isCascadeRemove'] = in_array('remove', $cascades, \true);
646 $mapping['isCascadePersist'] = in_array('persist', $cascades, \true);
647 $mapping['isCascadeRefresh'] = in_array('refresh', $cascades, \true);
648 $mapping['isCascadeMerge'] = in_array('merge', $cascades, \true);
649 $mapping['isCascadeDetach'] = in_array('detach', $cascades, \true);
650 return $mapping;
651 }
652 protected function _validateAndCompleteOneToOneMapping(array $mapping)
653 {
654 $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
655 if (isset($mapping['joinColumns']) && $mapping['joinColumns'] && !$mapping['isOwningSide']) {
656 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10654', 'JoinColumn configuration is not allowed on the inverse side of one-to-one associations, and will throw a MappingException in Doctrine ORM 3.0');
657 }
658 if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
659 $mapping['isOwningSide'] = \true;
660 }
661 if ($mapping['isOwningSide']) {
662 if (empty($mapping['joinColumns'])) {
663 // Apply default join column
664 $mapping['joinColumns'] = [['name' => $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name), 'referencedColumnName' => $this->namingStrategy->referenceColumnName()]];
665 }
666 $uniqueConstraintColumns = [];
667 foreach ($mapping['joinColumns'] as &$joinColumn) {
668 if ($mapping['type'] === self::ONE_TO_ONE && !$this->isInheritanceTypeSingleTable()) {
669 if (count($mapping['joinColumns']) === 1) {
670 if (empty($mapping['id'])) {
671 $joinColumn['unique'] = \true;
672 }
673 } else {
674 $uniqueConstraintColumns[] = $joinColumn['name'];
675 }
676 }
677 if (empty($joinColumn['name'])) {
678 $joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name);
679 }
680 if (empty($joinColumn['referencedColumnName'])) {
681 $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
682 }
683 if ($joinColumn['name'][0] === '`') {
684 $joinColumn['name'] = trim($joinColumn['name'], '`');
685 $joinColumn['quoted'] = \true;
686 }
687 if ($joinColumn['referencedColumnName'][0] === '`') {
688 $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
689 $joinColumn['quoted'] = \true;
690 }
691 $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
692 $mapping['joinColumnFieldNames'][$joinColumn['name']] = $joinColumn['fieldName'] ?? $joinColumn['name'];
693 }
694 if ($uniqueConstraintColumns) {
695 if (!$this->table) {
696 throw new RuntimeException('ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.');
697 }
698 $this->table['uniqueConstraints'][$mapping['fieldName'] . '_uniq'] = ['columns' => $uniqueConstraintColumns];
699 }
700 $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
701 }
702 $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
703 $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] || $mapping['isCascadeRemove'];
704 if ($mapping['orphanRemoval']) {
705 unset($mapping['unique']);
706 }
707 if (isset($mapping['id']) && $mapping['id'] === \true && !$mapping['isOwningSide']) {
708 throw MappingException::illegalInverseIdentifierAssociation($this->name, $mapping['fieldName']);
709 }
710 return $mapping;
711 }
712 protected function _validateAndCompleteOneToManyMapping(array $mapping)
713 {
714 $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
715 // OneToMany-side MUST be inverse (must have mappedBy)
716 if (!isset($mapping['mappedBy'])) {
717 throw MappingException::oneToManyRequiresMappedBy($this->name, $mapping['fieldName']);
718 }
719 $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
720 $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] || $mapping['isCascadeRemove'];
721 $this->assertMappingOrderBy($mapping);
722 return $mapping;
723 }
724 protected function _validateAndCompleteManyToManyMapping(array $mapping)
725 {
726 $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
727 if ($mapping['isOwningSide']) {
728 // owning side MUST have a join table
729 if (!isset($mapping['joinTable']['name'])) {
730 $mapping['joinTable']['name'] = $this->namingStrategy->joinTableName($mapping['sourceEntity'], $mapping['targetEntity'], $mapping['fieldName']);
731 }
732 $selfReferencingEntityWithoutJoinColumns = $mapping['sourceEntity'] === $mapping['targetEntity'] && !(isset($mapping['joinTable']['joinColumns']) || isset($mapping['joinTable']['inverseJoinColumns']));
733 if (!isset($mapping['joinTable']['joinColumns'])) {
734 $mapping['joinTable']['joinColumns'] = [['name' => $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $selfReferencingEntityWithoutJoinColumns ? 'source' : null), 'referencedColumnName' => $this->namingStrategy->referenceColumnName(), 'onDelete' => 'CASCADE']];
735 }
736 if (!isset($mapping['joinTable']['inverseJoinColumns'])) {
737 $mapping['joinTable']['inverseJoinColumns'] = [['name' => $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $selfReferencingEntityWithoutJoinColumns ? 'target' : null), 'referencedColumnName' => $this->namingStrategy->referenceColumnName(), 'onDelete' => 'CASCADE']];
738 }
739 $mapping['joinTableColumns'] = [];
740 foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
741 if (empty($joinColumn['name'])) {
742 $joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']);
743 }
744 if (empty($joinColumn['referencedColumnName'])) {
745 $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
746 }
747 if ($joinColumn['name'][0] === '`') {
748 $joinColumn['name'] = trim($joinColumn['name'], '`');
749 $joinColumn['quoted'] = \true;
750 }
751 if ($joinColumn['referencedColumnName'][0] === '`') {
752 $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
753 $joinColumn['quoted'] = \true;
754 }
755 if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) === 'cascade') {
756 $mapping['isOnDeleteCascade'] = \true;
757 }
758 $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
759 $mapping['joinTableColumns'][] = $joinColumn['name'];
760 }
761 foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
762 if (empty($inverseJoinColumn['name'])) {
763 $inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']);
764 }
765 if (empty($inverseJoinColumn['referencedColumnName'])) {
766 $inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
767 }
768 if ($inverseJoinColumn['name'][0] === '`') {
769 $inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`');
770 $inverseJoinColumn['quoted'] = \true;
771 }
772 if ($inverseJoinColumn['referencedColumnName'][0] === '`') {
773 $inverseJoinColumn['referencedColumnName'] = trim($inverseJoinColumn['referencedColumnName'], '`');
774 $inverseJoinColumn['quoted'] = \true;
775 }
776 if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) === 'cascade') {
777 $mapping['isOnDeleteCascade'] = \true;
778 }
779 $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
780 $mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
781 }
782 }
783 $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
784 $this->assertMappingOrderBy($mapping);
785 return $mapping;
786 }
787 public function getIdentifierFieldNames()
788 {
789 return $this->identifier;
790 }
791 public function getSingleIdentifierFieldName()
792 {
793 if ($this->isIdentifierComposite) {
794 throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name);
795 }
796 if (!isset($this->identifier[0])) {
797 throw MappingException::noIdDefined($this->name);
798 }
799 return $this->identifier[0];
800 }
801 public function getSingleIdentifierColumnName()
802 {
803 return $this->getColumnName($this->getSingleIdentifierFieldName());
804 }
805 public function setIdentifier(array $identifier)
806 {
807 $this->identifier = $identifier;
808 $this->isIdentifierComposite = count($this->identifier) > 1;
809 }
810 public function getIdentifier()
811 {
812 return $this->identifier;
813 }
814 public function hasField($fieldName)
815 {
816 return isset($this->fieldMappings[$fieldName]) || isset($this->embeddedClasses[$fieldName]);
817 }
818 public function getColumnNames(?array $fieldNames = null)
819 {
820 if ($fieldNames === null) {
821 return array_keys($this->fieldNames);
822 }
823 return array_values(array_map([$this, 'getColumnName'], $fieldNames));
824 }
825 public function getIdentifierColumnNames()
826 {
827 $columnNames = [];
828 foreach ($this->identifier as $idProperty) {
829 if (isset($this->fieldMappings[$idProperty])) {
830 $columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
831 continue;
832 }
833 // Association defined as Id field
834 $joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
835 $assocColumnNames = array_map(static function ($joinColumn) {
836 return $joinColumn['name'];
837 }, $joinColumns);
838 $columnNames = array_merge($columnNames, $assocColumnNames);
839 }
840 return $columnNames;
841 }
842 public function setIdGeneratorType($generatorType)
843 {
844 $this->generatorType = $generatorType;
845 }
846 public function usesIdGenerator()
847 {
848 return $this->generatorType !== self::GENERATOR_TYPE_NONE;
849 }
850 public function isInheritanceTypeNone()
851 {
852 return $this->inheritanceType === self::INHERITANCE_TYPE_NONE;
853 }
854 public function isInheritanceTypeJoined()
855 {
856 return $this->inheritanceType === self::INHERITANCE_TYPE_JOINED;
857 }
858 public function isInheritanceTypeSingleTable()
859 {
860 return $this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_TABLE;
861 }
862 public function isInheritanceTypeTablePerClass()
863 {
864 Deprecation::triggerIfCalledFromOutside('doctrine/orm', 'https://github.com/doctrine/orm/pull/10414/', 'Concrete table inheritance has never been implemented, and its stubs will be removed in Doctrine ORM 3.0 with no replacement');
865 return $this->inheritanceType === self::INHERITANCE_TYPE_TABLE_PER_CLASS;
866 }
867 public function isIdGeneratorIdentity()
868 {
869 return $this->generatorType === self::GENERATOR_TYPE_IDENTITY;
870 }
871 public function isIdGeneratorSequence()
872 {
873 return $this->generatorType === self::GENERATOR_TYPE_SEQUENCE;
874 }
875 public function isIdGeneratorTable()
876 {
877 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/9046', '%s is deprecated', __METHOD__);
878 return \false;
879 }
880 public function isIdentifierNatural()
881 {
882 return $this->generatorType === self::GENERATOR_TYPE_NONE;
883 }
884 public function isIdentifierUuid()
885 {
886 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/9046', '%s is deprecated', __METHOD__);
887 return $this->generatorType === self::GENERATOR_TYPE_UUID;
888 }
889 public function getTypeOfField($fieldName)
890 {
891 return isset($this->fieldMappings[$fieldName]) ? $this->fieldMappings[$fieldName]['type'] : null;
892 }
893 public function getTypeOfColumn($columnName)
894 {
895 return $this->getTypeOfField($this->getFieldName($columnName));
896 }
897 public function getTableName()
898 {
899 return $this->table['name'];
900 }
901 public function getSchemaName()
902 {
903 return $this->table['schema'] ?? null;
904 }
905 public function getTemporaryIdTableName()
906 {
907 // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
908 return str_replace('.', '_', $this->getTableName() . '_id_tmp');
909 }
910 public function setSubclasses(array $subclasses)
911 {
912 foreach ($subclasses as $subclass) {
913 $this->subClasses[] = $this->fullyQualifiedClassName($subclass);
914 }
915 }
916 public function setParentClasses(array $classNames)
917 {
918 $this->parentClasses = $classNames;
919 if (count($classNames) > 0) {
920 $this->rootEntityName = array_pop($classNames);
921 }
922 }
923 public function setInheritanceType($type)
924 {
925 if (!$this->isInheritanceType($type)) {
926 throw MappingException::invalidInheritanceType($this->name, $type);
927 }
928 $this->inheritanceType = $type;
929 }
930 public function setAssociationOverride($fieldName, array $overrideMapping)
931 {
932 if (!isset($this->associationMappings[$fieldName])) {
933 throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
934 }
935 $mapping = $this->associationMappings[$fieldName];
936 if (isset($mapping['inherited'])) {
937 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10470', '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. This is a misconfiguration and will be an error in Doctrine ORM 3.0.', $this->name, $fieldName, $mapping['inherited']);
938 }
939 if (isset($overrideMapping['joinColumns'])) {
940 $mapping['joinColumns'] = $overrideMapping['joinColumns'];
941 }
942 if (isset($overrideMapping['inversedBy'])) {
943 $mapping['inversedBy'] = $overrideMapping['inversedBy'];
944 }
945 if (isset($overrideMapping['joinTable'])) {
946 $mapping['joinTable'] = $overrideMapping['joinTable'];
947 }
948 if (isset($overrideMapping['fetch'])) {
949 $mapping['fetch'] = $overrideMapping['fetch'];
950 }
951 $mapping['joinColumnFieldNames'] = null;
952 $mapping['joinTableColumns'] = null;
953 $mapping['sourceToTargetKeyColumns'] = null;
954 $mapping['relationToSourceKeyColumns'] = null;
955 $mapping['relationToTargetKeyColumns'] = null;
956 switch ($mapping['type']) {
957 case self::ONE_TO_ONE:
958 $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
959 break;
960 case self::ONE_TO_MANY:
961 $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
962 break;
963 case self::MANY_TO_ONE:
964 $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
965 break;
966 case self::MANY_TO_MANY:
967 $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
968 break;
969 }
970 $this->associationMappings[$fieldName] = $mapping;
971 }
972 public function setAttributeOverride($fieldName, array $overrideMapping)
973 {
974 if (!isset($this->fieldMappings[$fieldName])) {
975 throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
976 }
977 $mapping = $this->fieldMappings[$fieldName];
978 if (isset($mapping['inherited'])) {
979 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10470', '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. This is a misconfiguration and will be an error in Doctrine ORM 3.0.', $this->name, $fieldName, $mapping['inherited']);
980 //throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName);
981 }
982 if (isset($mapping['id'])) {
983 $overrideMapping['id'] = $mapping['id'];
984 }
985 if (isset($mapping['declared'])) {
986 $overrideMapping['declared'] = $mapping['declared'];
987 }
988 if (!isset($overrideMapping['type'])) {
989 $overrideMapping['type'] = $mapping['type'];
990 }
991 if (!isset($overrideMapping['fieldName'])) {
992 $overrideMapping['fieldName'] = $mapping['fieldName'];
993 }
994 if ($overrideMapping['type'] !== $mapping['type']) {
995 throw MappingException::invalidOverrideFieldType($this->name, $fieldName);
996 }
997 unset($this->fieldMappings[$fieldName]);
998 unset($this->fieldNames[$mapping['columnName']]);
999 // @phpstan-ignore property.deprecated
1000 unset($this->columnNames[$mapping['fieldName']]);
1001 $overrideMapping = $this->validateAndCompleteFieldMapping($overrideMapping);
1002 $this->fieldMappings[$fieldName] = $overrideMapping;
1003 }
1004 public function isInheritedField($fieldName)
1005 {
1006 return isset($this->fieldMappings[$fieldName]['inherited']);
1007 }
1008 public function isRootEntity()
1009 {
1010 return $this->name === $this->rootEntityName;
1011 }
1012 public function isInheritedAssociation($fieldName)
1013 {
1014 return isset($this->associationMappings[$fieldName]['inherited']);
1015 }
1016 public function isInheritedEmbeddedClass($fieldName)
1017 {
1018 return isset($this->embeddedClasses[$fieldName]['inherited']);
1019 }
1020 public function setTableName($tableName)
1021 {
1022 $this->table['name'] = $tableName;
1023 }
1024 public function setPrimaryTable(array $table)
1025 {
1026 if (isset($table['name'])) {
1027 // Split schema and table name from a table name like "myschema.mytable"
1028 if (str_contains($table['name'], '.')) {
1029 [$this->table['schema'], $table['name']] = explode('.', $table['name'], 2);
1030 }
1031 if ($table['name'][0] === '`') {
1032 $table['name'] = trim($table['name'], '`');
1033 $this->table['quoted'] = \true;
1034 }
1035 $this->table['name'] = $table['name'];
1036 }
1037 if (isset($table['quoted'])) {
1038 $this->table['quoted'] = $table['quoted'];
1039 }
1040 if (isset($table['schema'])) {
1041 $this->table['schema'] = $table['schema'];
1042 }
1043 if (isset($table['indexes'])) {
1044 $this->table['indexes'] = $table['indexes'];
1045 }
1046 if (isset($table['uniqueConstraints'])) {
1047 $this->table['uniqueConstraints'] = $table['uniqueConstraints'];
1048 }
1049 if (isset($table['options'])) {
1050 $this->table['options'] = $table['options'];
1051 }
1052 }
1053 private function isInheritanceType(int $type) : bool
1054 {
1055 // @phpstan-ignore classConstant.deprecated
1056 if ($type === self::INHERITANCE_TYPE_TABLE_PER_CLASS) {
1057 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10414/', 'Concrete table inheritance has never been implemented, and its stubs will be removed in Doctrine ORM 3.0 with no replacement');
1058 }
1059 return $type === self::INHERITANCE_TYPE_NONE || $type === self::INHERITANCE_TYPE_SINGLE_TABLE || $type === self::INHERITANCE_TYPE_JOINED || $type === self::INHERITANCE_TYPE_TABLE_PER_CLASS;
1060 }
1061 public function mapField(array $mapping)
1062 {
1063 $mapping = $this->validateAndCompleteFieldMapping($mapping);
1064 $this->assertFieldNotMapped($mapping['fieldName']);
1065 if (isset($mapping['generated'])) {
1066 $this->requiresFetchAfterChange = \true;
1067 }
1068 $this->fieldMappings[$mapping['fieldName']] = $mapping;
1069 }
1070 public function addInheritedAssociationMapping(array $mapping)
1071 {
1072 if (isset($this->associationMappings[$mapping['fieldName']])) {
1073 throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
1074 }
1075 $this->associationMappings[$mapping['fieldName']] = $mapping;
1076 }
1077 public function addInheritedFieldMapping(array $fieldMapping)
1078 {
1079 $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1080 // @phpstan-ignore property.deprecated
1081 $this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
1082 $this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
1083 if (isset($fieldMapping['generated'])) {
1084 $this->requiresFetchAfterChange = \true;
1085 }
1086 }
1087 public function addNamedQuery(array $queryMapping)
1088 {
1089 if (!isset($queryMapping['name'])) {
1090 throw MappingException::nameIsMandatoryForQueryMapping($this->name);
1091 }
1092 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/issues/8592', 'Named Queries are deprecated, here "%s" on entity %s. Move the query logic into EntityRepository', $queryMapping['name'], $this->name);
1093 if (isset($this->namedQueries[$queryMapping['name']])) {
1094 throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
1095 }
1096 if (!isset($queryMapping['query'])) {
1097 throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
1098 }
1099 $name = $queryMapping['name'];
1100 $query = $queryMapping['query'];
1101 $dql = str_replace('__CLASS__', $this->name, $query);
1102 $this->namedQueries[$name] = ['name' => $name, 'query' => $query, 'dql' => $dql];
1103 }
1104 public function addNamedNativeQuery(array $queryMapping)
1105 {
1106 if (!isset($queryMapping['name'])) {
1107 throw MappingException::nameIsMandatoryForQueryMapping($this->name);
1108 }
1109 Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/issues/8592', 'Named Native Queries are deprecated, here "%s" on entity %s. Move the query logic into EntityRepository', $queryMapping['name'], $this->name);
1110 if (isset($this->namedNativeQueries[$queryMapping['name']])) {
1111 throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
1112 }
1113 if (!isset($queryMapping['query'])) {
1114 throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
1115 }
1116 if (!isset($queryMapping['resultClass']) && !isset($queryMapping['resultSetMapping'])) {
1117 throw MappingException::missingQueryMapping($this->name, $queryMapping['name']);
1118 }
1119 $queryMapping['isSelfClass'] = \false;
1120 if (isset($queryMapping['resultClass'])) {
1121 if ($queryMapping['resultClass'] === '__CLASS__') {
1122 $queryMapping['isSelfClass'] = \true;
1123 $queryMapping['resultClass'] = $this->name;
1124 }
1125 $queryMapping['resultClass'] = $this->fullyQualifiedClassName($queryMapping['resultClass']);
1126 $queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\');
1127 }
1128 $this->namedNativeQueries[$queryMapping['name']] = $queryMapping;
1129 }
1130 public function addSqlResultSetMapping(array $resultMapping)
1131 {
1132 if (!isset($resultMapping['name'])) {
1133 throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->name);
1134 }
1135 if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
1136 throw MappingException::duplicateResultSetMapping($this->name, $resultMapping['name']);
1137 }
1138 if (isset($resultMapping['entities'])) {
1139 foreach ($resultMapping['entities'] as $key => $entityResult) {
1140 if (!isset($entityResult['entityClass'])) {
1141 throw MappingException::missingResultSetMappingEntity($this->name, $resultMapping['name']);
1142 }
1143 $entityResult['isSelfClass'] = \false;
1144 if ($entityResult['entityClass'] === '__CLASS__') {
1145 $entityResult['isSelfClass'] = \true;
1146 $entityResult['entityClass'] = $this->name;
1147 }
1148 $entityResult['entityClass'] = $this->fullyQualifiedClassName($entityResult['entityClass']);
1149 $resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\');
1150 $resultMapping['entities'][$key]['isSelfClass'] = $entityResult['isSelfClass'];
1151 if (isset($entityResult['fields'])) {
1152 foreach ($entityResult['fields'] as $k => $field) {
1153 if (!isset($field['name'])) {
1154 throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']);
1155 }
1156 if (!isset($field['column'])) {
1157 $fieldName = $field['name'];
1158 if (str_contains($fieldName, '.')) {
1159 [, $fieldName] = explode('.', $fieldName);
1160 }
1161 $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
1162 }
1163 }
1164 }
1165 }
1166 }
1167 $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
1168 }
1169 public function mapOneToOne(array $mapping)
1170 {
1171 $mapping['type'] = self::ONE_TO_ONE;
1172 $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
1173 $this->_storeAssociationMapping($mapping);
1174 }
1175 public function mapOneToMany(array $mapping)
1176 {
1177 $mapping['type'] = self::ONE_TO_MANY;
1178 $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
1179 $this->_storeAssociationMapping($mapping);
1180 }
1181 public function mapManyToOne(array $mapping)
1182 {
1183 $mapping['type'] = self::MANY_TO_ONE;
1184 // A many-to-one mapping is essentially a one-one backreference
1185 $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
1186 $this->_storeAssociationMapping($mapping);
1187 }
1188 public function mapManyToMany(array $mapping)
1189 {
1190 $mapping['type'] = self::MANY_TO_MANY;
1191 $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
1192 $this->_storeAssociationMapping($mapping);
1193 }
1194 protected function _storeAssociationMapping(array $assocMapping)
1195 {
1196 $sourceFieldName = $assocMapping['fieldName'];
1197 $this->assertFieldNotMapped($sourceFieldName);
1198 $this->associationMappings[$sourceFieldName] = $assocMapping;
1199 }
1200 public function setCustomRepositoryClass($repositoryClassName)
1201 {
1202 $this->customRepositoryClassName = $this->fullyQualifiedClassName($repositoryClassName);
1203 }
1204 public function invokeLifecycleCallbacks($lifecycleEvent, $entity)
1205 {
1206 foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) {
1207 $entity->{$callback}();
1208 }
1209 }
1210 public function hasLifecycleCallbacks($lifecycleEvent)
1211 {
1212 return isset($this->lifecycleCallbacks[$lifecycleEvent]);
1213 }
1214 public function getLifecycleCallbacks($event)
1215 {
1216 return $this->lifecycleCallbacks[$event] ?? [];
1217 }
1218 public function addLifecycleCallback($callback, $event)
1219 {
1220 if ($this->isEmbeddedClass) {
1221 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);
1222 }
1223 if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], \true)) {
1224 return;
1225 }
1226 $this->lifecycleCallbacks[$event][] = $callback;
1227 }
1228 public function setLifecycleCallbacks(array $callbacks)
1229 {
1230 $this->lifecycleCallbacks = $callbacks;
1231 }
1232 public function addEntityListener($eventName, $class, $method)
1233 {
1234 $class = $this->fullyQualifiedClassName($class);
1235 $listener = ['class' => $class, 'method' => $method];
1236 if (!class_exists($class)) {
1237 throw MappingException::entityListenerClassNotFound($class, $this->name);
1238 }
1239 if (!method_exists($class, $method)) {
1240 throw MappingException::entityListenerMethodNotFound($class, $method, $this->name);
1241 }
1242 if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName], \true)) {
1243 throw MappingException::duplicateEntityListener($class, $method, $this->name);
1244 }
1245 $this->entityListeners[$eventName][] = $listener;
1246 }
1247 public function setDiscriminatorColumn($columnDef)
1248 {
1249 if ($columnDef !== null) {
1250 if (!isset($columnDef['name'])) {
1251 throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name);
1252 }
1253 if (isset($this->fieldNames[$columnDef['name']])) {
1254 throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
1255 }
1256 if (!isset($columnDef['fieldName'])) {
1257 $columnDef['fieldName'] = $columnDef['name'];
1258 }
1259 if (!isset($columnDef['type'])) {
1260 $columnDef['type'] = 'string';
1261 }
1262 if (in_array($columnDef['type'], ['boolean', 'array', 'object', 'datetime', 'time', 'date'], \true)) {
1263 throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
1264 }
1265 $this->discriminatorColumn = $columnDef;
1266 }
1267 }
1268 public final function getDiscriminatorColumn() : array
1269 {
1270 if ($this->discriminatorColumn === null) {
1271 throw new LogicException('The discriminator column was not set.');
1272 }
1273 return $this->discriminatorColumn;
1274 }
1275 public function setDiscriminatorMap(array $map)
1276 {
1277 foreach ($map as $value => $className) {
1278 $this->addDiscriminatorMapClass($value, $className);
1279 }
1280 }
1281 public function addDiscriminatorMapClass($name, $className)
1282 {
1283 $className = $this->fullyQualifiedClassName($className);
1284 $className = ltrim($className, '\\');
1285 $this->discriminatorMap[$name] = $className;
1286 if ($this->name === $className) {
1287 $this->discriminatorValue = $name;
1288 return;
1289 }
1290 if (!(class_exists($className) || interface_exists($className))) {
1291 throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
1292 }
1293 $this->addSubClass($className);
1294 }
1295 public function addSubClasses(array $classes) : void
1296 {
1297 foreach ($classes as $className) {
1298 $this->addSubClass($className);
1299 }
1300 }
1301 public function addSubClass(string $className) : void
1302 {
1303 // By ignoring classes that are not subclasses of the current class, we simplify inheriting
1304 // the subclass list from a parent class at the beginning of \MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadataFactory::doLoadMetadata.
1305 if (is_subclass_of($className, $this->name) && !in_array($className, $this->subClasses, \true)) {
1306 $this->subClasses[] = $className;
1307 }
1308 }
1309 public function hasNamedQuery($queryName)
1310 {
1311 return isset($this->namedQueries[$queryName]);
1312 }
1313 public function hasNamedNativeQuery($queryName)
1314 {
1315 return isset($this->namedNativeQueries[$queryName]);
1316 }
1317 public function hasSqlResultSetMapping($name)
1318 {
1319 return isset($this->sqlResultSetMappings[$name]);
1320 }
1321 public function hasAssociation($fieldName)
1322 {
1323 return isset($this->associationMappings[$fieldName]);
1324 }
1325 public function isSingleValuedAssociation($fieldName)
1326 {
1327 return isset($this->associationMappings[$fieldName]) && $this->associationMappings[$fieldName]['type'] & self::TO_ONE;
1328 }
1329 public function isCollectionValuedAssociation($fieldName)
1330 {
1331 return isset($this->associationMappings[$fieldName]) && !($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
1332 }
1333 public function isAssociationWithSingleJoinColumn($fieldName)
1334 {
1335 return isset($this->associationMappings[$fieldName]) && isset($this->associationMappings[$fieldName]['joinColumns'][0]) && !isset($this->associationMappings[$fieldName]['joinColumns'][1]);
1336 }
1337 public function getSingleAssociationJoinColumnName($fieldName)
1338 {
1339 if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
1340 throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
1341 }
1342 return $this->associationMappings[$fieldName]['joinColumns'][0]['name'];
1343 }
1344 public function getSingleAssociationReferencedJoinColumnName($fieldName)
1345 {
1346 if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
1347 throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
1348 }
1349 return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName'];
1350 }
1351 public function getFieldForColumn($columnName)
1352 {
1353 if (isset($this->fieldNames[$columnName])) {
1354 return $this->fieldNames[$columnName];
1355 }
1356 foreach ($this->associationMappings as $assocName => $mapping) {
1357 if ($this->isAssociationWithSingleJoinColumn($assocName) && $this->associationMappings[$assocName]['joinColumns'][0]['name'] === $columnName) {
1358 return $assocName;
1359 }
1360 }
1361 throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
1362 }
1363 public function setIdGenerator($generator)
1364 {
1365 $this->idGenerator = $generator;
1366 }
1367 public function setCustomGeneratorDefinition(array $definition)
1368 {
1369 $this->customGeneratorDefinition = $definition;
1370 }
1371 public function setSequenceGeneratorDefinition(array $definition)
1372 {
1373 if (!isset($definition['sequenceName']) || trim($definition['sequenceName']) === '') {
1374 throw MappingException::missingSequenceName($this->name);
1375 }
1376 if ($definition['sequenceName'][0] === '`') {
1377 $definition['sequenceName'] = trim($definition['sequenceName'], '`');
1378 $definition['quoted'] = \true;
1379 }
1380 if (!isset($definition['allocationSize']) || trim((string) $definition['allocationSize']) === '') {
1381 $definition['allocationSize'] = '1';
1382 }
1383 if (!isset($definition['initialValue']) || trim((string) $definition['initialValue']) === '') {
1384 $definition['initialValue'] = '1';
1385 }
1386 $definition['allocationSize'] = (string) $definition['allocationSize'];
1387 $definition['initialValue'] = (string) $definition['initialValue'];
1388 $this->sequenceGeneratorDefinition = $definition;
1389 }
1390 public function setVersionMapping(array &$mapping)
1391 {
1392 $this->isVersioned = \true;
1393 $this->versionField = $mapping['fieldName'];
1394 $this->requiresFetchAfterChange = \true;
1395 if (!isset($mapping['default'])) {
1396 if (in_array($mapping['type'], ['integer', 'bigint', 'smallint'], \true)) {
1397 $mapping['default'] = 1;
1398 } elseif ($mapping['type'] === 'datetime') {
1399 $mapping['default'] = 'CURRENT_TIMESTAMP';
1400 } else {
1401 throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']);
1402 }
1403 }
1404 }
1405 public function setVersioned($bool)
1406 {
1407 $this->isVersioned = $bool;
1408 if ($bool) {
1409 $this->requiresFetchAfterChange = \true;
1410 }
1411 }
1412 public function setVersionField($versionField)
1413 {
1414 $this->versionField = $versionField;
1415 }
1416 public function markReadOnly()
1417 {
1418 $this->isReadOnly = \true;
1419 }
1420 public function getFieldNames()
1421 {
1422 return array_keys($this->fieldMappings);
1423 }
1424 public function getAssociationNames()
1425 {
1426 return array_keys($this->associationMappings);
1427 }
1428 public function getAssociationTargetClass($assocName)
1429 {
1430 if (!isset($this->associationMappings[$assocName])) {
1431 throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
1432 }
1433 return $this->associationMappings[$assocName]['targetEntity'];
1434 }
1435 public function getName()
1436 {
1437 return $this->name;
1438 }
1439 public function getQuotedIdentifierColumnNames($platform)
1440 {
1441 $quotedColumnNames = [];
1442 foreach ($this->identifier as $idProperty) {
1443 if (isset($this->fieldMappings[$idProperty])) {
1444 $quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName']) : $this->fieldMappings[$idProperty]['columnName'];
1445 continue;
1446 }
1447 // Association defined as Id field
1448 $joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
1449 $assocQuotedColumnNames = array_map(static function ($joinColumn) use($platform) {
1450 return isset($joinColumn['quoted']) ? $platform->quoteIdentifier($joinColumn['name']) : $joinColumn['name'];
1451 }, $joinColumns);
1452 $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
1453 }
1454 return $quotedColumnNames;
1455 }
1456 public function getQuotedColumnName($field, $platform)
1457 {
1458 return isset($this->fieldMappings[$field]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : $this->fieldMappings[$field]['columnName'];
1459 }
1460 public function getQuotedTableName($platform)
1461 {
1462 return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
1463 }
1464 public function getQuotedJoinTableName(array $assoc, $platform)
1465 {
1466 return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
1467 }
1468 public function isAssociationInverseSide($fieldName)
1469 {
1470 return isset($this->associationMappings[$fieldName]) && !$this->associationMappings[$fieldName]['isOwningSide'];
1471 }
1472 public function getAssociationMappedByTargetField($fieldName)
1473 {
1474 if (!$this->isAssociationInverseSide($fieldName)) {
1475 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);
1476 }
1477 return $this->associationMappings[$fieldName]['mappedBy'];
1478 }
1479 public function getAssociationsByTargetClass($targetClass)
1480 {
1481 $relations = [];
1482 foreach ($this->associationMappings as $mapping) {
1483 if ($mapping['targetEntity'] === $targetClass) {
1484 $relations[$mapping['fieldName']] = $mapping;
1485 }
1486 }
1487 return $relations;
1488 }
1489 public function fullyQualifiedClassName($className)
1490 {
1491 if (empty($className)) {
1492 return $className;
1493 }
1494 if (!str_contains($className, '\\') && $this->namespace) {
1495 return $this->namespace . '\\' . $className;
1496 }
1497 return $className;
1498 }
1499 public function getMetadataValue($name)
1500 {
1501 if (isset($this->{$name})) {
1502 return $this->{$name};
1503 }
1504 return null;
1505 }
1506 public function mapEmbedded(array $mapping)
1507 {
1508 $this->assertFieldNotMapped($mapping['fieldName']);
1509 if (!isset($mapping['class']) && $this->isTypedProperty($mapping['fieldName'])) {
1510 $type = $this->reflClass->getProperty($mapping['fieldName'])->getType();
1511 if ($type instanceof ReflectionNamedType) {
1512 $mapping['class'] = $type->getName();
1513 }
1514 }
1515 if (!(isset($mapping['class']) && $mapping['class'])) {
1516 throw MappingException::missingEmbeddedClass($mapping['fieldName']);
1517 }
1518 $fqcn = $this->fullyQualifiedClassName($mapping['class']);
1519 assert($fqcn !== null);
1520 $this->embeddedClasses[$mapping['fieldName']] = ['class' => $fqcn, 'columnPrefix' => $mapping['columnPrefix'] ?? null, 'declaredField' => $mapping['declaredField'] ?? null, 'originalField' => $mapping['originalField'] ?? null];
1521 }
1522 public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
1523 {
1524 foreach ($embeddable->fieldMappings as $fieldMapping) {
1525 $fieldMapping['originalClass'] = $fieldMapping['originalClass'] ?? $embeddable->name;
1526 $fieldMapping['declaredField'] = isset($fieldMapping['declaredField']) ? $property . '.' . $fieldMapping['declaredField'] : $property;
1527 $fieldMapping['originalField'] = $fieldMapping['originalField'] ?? $fieldMapping['fieldName'];
1528 $fieldMapping['fieldName'] = $property . '.' . $fieldMapping['fieldName'];
1529 if (!empty($this->embeddedClasses[$property]['columnPrefix'])) {
1530 $fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
1531 } elseif ($this->embeddedClasses[$property]['columnPrefix'] !== \false) {
1532 $fieldMapping['columnName'] = $this->namingStrategy->embeddedFieldToColumnName($property, $fieldMapping['columnName'], $this->reflClass->name, $embeddable->reflClass->name);
1533 }
1534 $this->mapField($fieldMapping);
1535 }
1536 }
1537 private function assertFieldNotMapped(string $fieldName) : void
1538 {
1539 if (isset($this->fieldMappings[$fieldName]) || isset($this->associationMappings[$fieldName]) || isset($this->embeddedClasses[$fieldName])) {
1540 throw MappingException::duplicateFieldMapping($this->name, $fieldName);
1541 }
1542 }
1543 public function getSequenceName(AbstractPlatform $platform)
1544 {
1545 $sequencePrefix = $this->getSequencePrefix($platform);
1546 $columnName = $this->getSingleIdentifierColumnName();
1547 return $sequencePrefix . '_' . $columnName . '_seq';
1548 }
1549 public function getSequencePrefix(AbstractPlatform $platform)
1550 {
1551 $tableName = $this->getTableName();
1552 $sequencePrefix = $tableName;
1553 // Prepend the schema name to the table name if there is one
1554 $schemaName = $this->getSchemaName();
1555 if ($schemaName) {
1556 $sequencePrefix = $schemaName . '.' . $tableName;
1557 // @phpstan-ignore method.deprecated
1558 if (!$platform->supportsSchemas() && $platform->canEmulateSchemas()) {
1559 $sequencePrefix = $schemaName . '__' . $tableName;
1560 }
1561 }
1562 return $sequencePrefix;
1563 }
1564 private function assertMappingOrderBy(array $mapping) : void
1565 {
1566 if (isset($mapping['orderBy']) && !is_array($mapping['orderBy'])) {
1567 throw new InvalidArgumentException("'orderBy' is expected to be an array, not " . gettype($mapping['orderBy']));
1568 }
1569 }
1570 private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field) : ?ReflectionProperty
1571 {
1572 $reflectionProperty = $reflService->getAccessibleProperty($class, $field);
1573 if ($reflectionProperty !== null && PHP_VERSION_ID >= 80100 && $reflectionProperty->isReadOnly()) {
1574 $declaringClass = $reflectionProperty->class;
1575 if ($declaringClass !== $class) {
1576 $reflectionProperty = $reflService->getAccessibleProperty($declaringClass, $field);
1577 }
1578 if ($reflectionProperty !== null) {
1579 $reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty);
1580 }
1581 }
1582 if (PHP_VERSION_ID >= 80400 && $reflectionProperty !== null && count($reflectionProperty->getHooks()) > 0) {
1583 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.');
1584 }
1585 return $reflectionProperty;
1586 }
1587 }
1588