These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\ODM\MongoDB\Mapping\Driver; |
||
6 | |||
7 | use Doctrine\Common\Annotations\AnnotationReader; |
||
8 | use Doctrine\Common\Annotations\Reader; |
||
9 | use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver; |
||
10 | use Doctrine\ODM\MongoDB\Events; |
||
11 | use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; |
||
12 | use Doctrine\ODM\MongoDB\Mapping\Annotations\AbstractIndex; |
||
13 | use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; |
||
14 | use Doctrine\ODM\MongoDB\Mapping\MappingException; |
||
15 | use ReflectionClass; |
||
16 | use ReflectionMethod; |
||
17 | use const E_USER_DEPRECATED; |
||
18 | use function array_merge; |
||
19 | use function array_replace; |
||
20 | use function assert; |
||
21 | use function constant; |
||
22 | use function get_class; |
||
23 | use function is_array; |
||
24 | use function trigger_error; |
||
25 | |||
26 | /** |
||
27 | * The AnnotationDriver reads the mapping metadata from docblock annotations. |
||
28 | */ |
||
29 | class AnnotationDriver extends AbstractAnnotationDriver |
||
30 | { |
||
31 | 963 | public function isTransient($className) |
|
32 | { |
||
33 | 963 | $classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className)); |
|
34 | |||
35 | 963 | foreach ($classAnnotations as $annot) { |
|
36 | 962 | if ($annot instanceof ODM\AbstractDocument) { |
|
37 | 962 | return false; |
|
38 | } |
||
39 | } |
||
40 | 112 | return true; |
|
41 | } |
||
42 | |||
43 | /** |
||
44 | * {@inheritdoc} |
||
45 | */ |
||
46 | 1493 | public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class) : void |
|
47 | { |
||
48 | 1493 | assert($class instanceof ClassMetadata); |
|
49 | 1493 | $reflClass = $class->getReflectionClass(); |
|
50 | |||
51 | 1493 | $classAnnotations = $this->reader->getClassAnnotations($reflClass); |
|
52 | |||
53 | 1493 | $documentAnnot = null; |
|
54 | 1493 | foreach ($classAnnotations as $annot) { |
|
55 | 1491 | $classAnnotations[get_class($annot)] = $annot; |
|
56 | |||
57 | 1491 | if ($annot instanceof ODM\AbstractDocument) { |
|
58 | 1491 | if ($documentAnnot !== null) { |
|
59 | 5 | throw MappingException::classCanOnlyBeMappedByOneAbstractDocument($className, $documentAnnot, $annot); |
|
60 | } |
||
61 | 1491 | $documentAnnot = $annot; |
|
62 | } |
||
63 | |||
64 | // non-document class annotations |
||
65 | 1491 | if ($annot instanceof ODM\AbstractIndex) { |
|
66 | 6 | $this->addIndex($class, $annot); |
|
67 | } |
||
68 | 1491 | if ($annot instanceof ODM\Indexes) { |
|
69 | // Setting the type to mixed is a workaround until https://github.com/doctrine/annotations/pull/209 is released. |
||
70 | /** @var mixed $value */ |
||
71 | 137 | $value = $annot->value; |
|
72 | 137 | foreach (is_array($value) ? $value : [$value] as $index) { |
|
73 | 137 | $this->addIndex($class, $index); |
|
74 | } |
||
75 | 1491 | } elseif ($annot instanceof ODM\InheritanceType) { |
|
76 | 904 | $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $annot->value)); |
|
77 | 1491 | } elseif ($annot instanceof ODM\DiscriminatorField) { |
|
78 | 175 | $class->setDiscriminatorField($annot->value); |
|
79 | 1491 | } elseif ($annot instanceof ODM\DiscriminatorMap) { |
|
80 | /** @var array $value */ |
||
81 | 174 | $value = $annot->value; |
|
82 | 174 | $class->setDiscriminatorMap($value); |
|
83 | 1491 | } elseif ($annot instanceof ODM\DiscriminatorValue) { |
|
84 | $class->setDiscriminatorValue($annot->value); |
||
85 | 1491 | } elseif ($annot instanceof ODM\ChangeTrackingPolicy) { |
|
86 | 109 | $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . $annot->value)); |
|
87 | 1491 | } elseif ($annot instanceof ODM\DefaultDiscriminatorValue) { |
|
88 | 111 | $class->setDefaultDiscriminatorValue($annot->value); |
|
89 | 1491 | } elseif ($annot instanceof ODM\ReadPreference) { |
|
90 | 6 | $class->setReadPreference($annot->value, $annot->tags ?? []); |
|
91 | } |
||
92 | } |
||
93 | |||
94 | 1488 | if ($documentAnnot === null) { |
|
95 | 3 | throw MappingException::classIsNotAValidDocument($className); |
|
96 | } |
||
97 | |||
98 | 1486 | if ($documentAnnot instanceof ODM\MappedSuperclass) { |
|
99 | 894 | $class->isMappedSuperclass = true; |
|
100 | 1485 | } elseif ($documentAnnot instanceof ODM\EmbeddedDocument) { |
|
101 | 330 | $class->isEmbeddedDocument = true; |
|
102 | 1478 | } elseif ($documentAnnot instanceof ODM\QueryResultDocument) { |
|
103 | 110 | $class->isQueryResultDocument = true; |
|
104 | 1478 | } elseif ($documentAnnot instanceof ODM\File) { |
|
105 | 122 | $class->isFile = true; |
|
106 | |||
107 | 122 | if ($documentAnnot->chunkSizeBytes !== null) { |
|
108 | 121 | $class->setChunkSizeBytes($documentAnnot->chunkSizeBytes); |
|
109 | } |
||
110 | } |
||
111 | |||
112 | 1486 | if (isset($documentAnnot->db)) { |
|
113 | 1 | $class->setDatabase($documentAnnot->db); |
|
0 ignored issues
–
show
|
|||
114 | } |
||
115 | 1486 | if (isset($documentAnnot->collection)) { |
|
116 | 956 | $class->setCollection($documentAnnot->collection); |
|
0 ignored issues
–
show
The property
collection does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
117 | } |
||
118 | // Store bucketName as collection name for GridFS files |
||
119 | 1486 | if (isset($documentAnnot->bucketName)) { |
|
120 | 1 | $class->setBucketName($documentAnnot->bucketName); |
|
0 ignored issues
–
show
The property
bucketName does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
121 | } |
||
122 | 1486 | if (isset($documentAnnot->repositoryClass)) { |
|
123 | 120 | $class->setCustomRepositoryClass($documentAnnot->repositoryClass); |
|
0 ignored issues
–
show
The property
repositoryClass does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
124 | } |
||
125 | 1486 | if (isset($documentAnnot->writeConcern)) { |
|
126 | 10 | $class->setWriteConcern($documentAnnot->writeConcern); |
|
0 ignored issues
–
show
The property
writeConcern does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
127 | } |
||
128 | 1486 | if (isset($documentAnnot->indexes)) { |
|
129 | 1485 | foreach ($documentAnnot->indexes as $index) { |
|
0 ignored issues
–
show
The property
indexes does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
130 | $this->addIndex($class, $index); |
||
131 | } |
||
132 | } |
||
133 | 1486 | if (! empty($documentAnnot->readOnly)) { |
|
0 ignored issues
–
show
The property
readOnly does not exist on object<Doctrine\ODM\Mong...tions\AbstractDocument> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property.
Loading history...
|
|||
134 | 5 | $class->markReadOnly(); |
|
135 | } |
||
136 | |||
137 | 1486 | foreach ($reflClass->getProperties() as $property) { |
|
138 | 1485 | if (($class->isMappedSuperclass && ! $property->isPrivate()) |
|
139 | || |
||
140 | 1485 | ($class->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $class->name)) { |
|
141 | 936 | continue; |
|
142 | } |
||
143 | |||
144 | 1484 | $indexes = []; |
|
145 | 1484 | $mapping = ['fieldName' => $property->getName()]; |
|
146 | 1484 | $fieldAnnot = null; |
|
147 | |||
148 | 1484 | foreach ($this->reader->getPropertyAnnotations($property) as $annot) { |
|
149 | 1484 | if ($annot instanceof ODM\AbstractField) { |
|
150 | 1484 | $fieldAnnot = $annot; |
|
151 | 1484 | if ($annot->isDeprecated()) { |
|
152 | @trigger_error($annot->getDeprecationMessage(), E_USER_DEPRECATED); |
||
153 | } |
||
154 | } |
||
155 | 1484 | if ($annot instanceof ODM\AbstractIndex) { |
|
156 | 225 | $indexes[] = $annot; |
|
157 | } |
||
158 | 1484 | if ($annot instanceof ODM\Indexes) { |
|
159 | // Setting the type to mixed is a workaround until https://github.com/doctrine/annotations/pull/209 is released. |
||
160 | /** @var mixed $value */ |
||
161 | $value = $annot->value; |
||
162 | foreach (is_array($value) ? $value : [$value] as $index) { |
||
163 | $indexes[] = $index; |
||
164 | } |
||
165 | 1484 | } elseif ($annot instanceof ODM\AlsoLoad) { |
|
166 | 15 | $mapping['alsoLoadFields'] = (array) $annot->value; |
|
167 | 1484 | } elseif ($annot instanceof ODM\Version) { |
|
168 | 151 | $mapping['version'] = true; |
|
169 | 1484 | } elseif ($annot instanceof ODM\Lock) { |
|
170 | 22 | $mapping['lock'] = true; |
|
171 | } |
||
172 | } |
||
173 | |||
174 | 1484 | if ($fieldAnnot) { |
|
175 | 1484 | $mapping = array_replace($mapping, (array) $fieldAnnot); |
|
176 | 1484 | $class->mapField($mapping); |
|
177 | } |
||
178 | |||
179 | 1484 | if (! $indexes) { |
|
180 | 1484 | continue; |
|
181 | } |
||
182 | |||
183 | 225 | foreach ($indexes as $index) { |
|
184 | 225 | $name = $mapping['name'] ?? $mapping['fieldName']; |
|
185 | 225 | $keys = [$name => $index->order ?: 'asc']; |
|
186 | 225 | $this->addIndex($class, $index, $keys); |
|
187 | } |
||
188 | } |
||
189 | |||
190 | // Set shard key after all fields to ensure we mapped all its keys |
||
191 | 1483 | if (isset($classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey'])) { |
|
192 | 131 | $this->setShardKey($class, $classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey']); |
|
193 | } |
||
194 | |||
195 | /** @var ReflectionMethod $method */ |
||
196 | 1482 | foreach ($reflClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { |
|
197 | /* Filter for the declaring class only. Callbacks from parent |
||
198 | * classes will already be registered. |
||
199 | */ |
||
200 | 1230 | if ($method->getDeclaringClass()->name !== $reflClass->name) { |
|
201 | 901 | continue; |
|
202 | } |
||
203 | |||
204 | 1230 | foreach ($this->reader->getMethodAnnotations($method) as $annot) { |
|
205 | 895 | if ($annot instanceof ODM\AlsoLoad) { |
|
206 | 13 | $class->registerAlsoLoadMethod($method->getName(), $annot->value); |
|
207 | } |
||
208 | |||
209 | 895 | if (! isset($classAnnotations[ODM\HasLifecycleCallbacks::class])) { |
|
210 | 127 | continue; |
|
211 | } |
||
212 | |||
213 | 876 | if ($annot instanceof ODM\PrePersist) { |
|
214 | 857 | $class->addLifecycleCallback($method->getName(), Events::prePersist); |
|
215 | 138 | } elseif ($annot instanceof ODM\PostPersist) { |
|
216 | 10 | $class->addLifecycleCallback($method->getName(), Events::postPersist); |
|
217 | 138 | } elseif ($annot instanceof ODM\PreUpdate) { |
|
218 | 15 | $class->addLifecycleCallback($method->getName(), Events::preUpdate); |
|
219 | 133 | } elseif ($annot instanceof ODM\PostUpdate) { |
|
220 | 122 | $class->addLifecycleCallback($method->getName(), Events::postUpdate); |
|
221 | 127 | } elseif ($annot instanceof ODM\PreRemove) { |
|
222 | 125 | $class->addLifecycleCallback($method->getName(), Events::preRemove); |
|
223 | 127 | } elseif ($annot instanceof ODM\PostRemove) { |
|
224 | 125 | $class->addLifecycleCallback($method->getName(), Events::postRemove); |
|
225 | 127 | } elseif ($annot instanceof ODM\PreLoad) { |
|
226 | 126 | $class->addLifecycleCallback($method->getName(), Events::preLoad); |
|
227 | 126 | } elseif ($annot instanceof ODM\PostLoad) { |
|
228 | 125 | $class->addLifecycleCallback($method->getName(), Events::postLoad); |
|
229 | 11 | } elseif ($annot instanceof ODM\PreFlush) { |
|
230 | 11 | $class->addLifecycleCallback($method->getName(), Events::preFlush); |
|
231 | } |
||
232 | } |
||
233 | } |
||
234 | 1482 | } |
|
235 | |||
236 | 257 | private function addIndex(ClassMetadata $class, AbstractIndex $index, array $keys = []) : void |
|
237 | { |
||
238 | 257 | $keys = array_merge($keys, $index->keys); |
|
239 | 257 | $options = []; |
|
240 | 257 | $allowed = ['name', 'background', 'unique', 'sparse', 'expireAfterSeconds']; |
|
241 | 257 | foreach ($allowed as $name) { |
|
242 | 257 | if (! isset($index->$name)) { |
|
243 | 257 | continue; |
|
244 | } |
||
245 | |||
246 | 257 | $options[$name] = $index->$name; |
|
247 | } |
||
248 | 257 | if (! empty($index->partialFilterExpression)) { |
|
249 | 2 | $options['partialFilterExpression'] = $index->partialFilterExpression; |
|
250 | } |
||
251 | 257 | $options = array_merge($options, $index->options); |
|
252 | 257 | $class->addIndex($keys, $options); |
|
253 | 257 | } |
|
254 | |||
255 | /** |
||
256 | * @throws MappingException |
||
257 | */ |
||
258 | 131 | private function setShardKey(ClassMetadata $class, ODM\ShardKey $shardKey) : void |
|
259 | { |
||
260 | 131 | $options = []; |
|
261 | 131 | $allowed = ['unique', 'numInitialChunks']; |
|
262 | 131 | foreach ($allowed as $name) { |
|
263 | 131 | if (! isset($shardKey->$name)) { |
|
264 | 131 | continue; |
|
265 | } |
||
266 | |||
267 | $options[$name] = $shardKey->$name; |
||
268 | } |
||
269 | |||
270 | 131 | $class->setShardKey($shardKey->keys, $options); |
|
271 | 130 | } |
|
272 | |||
273 | /** |
||
274 | * Factory method for the Annotation Driver |
||
275 | * |
||
276 | * @param string[]|string $paths |
||
277 | */ |
||
278 | 1756 | public static function create($paths = [], ?Reader $reader = null) : AnnotationDriver |
|
279 | { |
||
280 | 1756 | if ($reader === null) { |
|
281 | 1756 | $reader = new AnnotationReader(); |
|
282 | } |
||
283 | 1756 | return new self($reader, $paths); |
|
284 | } |
||
285 | } |
||
286 |
Since your code implements the magic getter
_get
, this function will be called for any read access on an undefined variable. You can add the@property
annotation to your class or interface to document the existence of this variable.If the property has read access only, you can use the @property-read annotation instead.
Of course, you may also just have mistyped another name, in which case you should fix the error.
See also the PhpDoc documentation for @property.