These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* |
||
3 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
4 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
5 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
6 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
7 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
8 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
9 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
10 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
11 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
12 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
13 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
14 | * |
||
15 | * This software consists of voluntary contributions made by many individuals |
||
16 | * and is licensed under the MIT license. For more information, see |
||
17 | * <http://www.doctrine-project.org>. |
||
18 | */ |
||
19 | |||
20 | namespace Doctrine\ODM\MongoDB\Mapping; |
||
21 | |||
22 | use Doctrine\ODM\MongoDB\Utility\CollectionHelper; |
||
23 | use Doctrine\ODM\MongoDB\LockException; |
||
24 | use Doctrine\ODM\MongoDB\Proxy\Proxy; |
||
25 | use Doctrine\ODM\MongoDB\Types\Type; |
||
26 | use InvalidArgumentException; |
||
27 | |||
28 | /** |
||
29 | * A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata |
||
30 | * of a document and it's references. |
||
31 | * |
||
32 | * Once populated, ClassMetadata instances are usually cached in a serialized form. |
||
33 | * |
||
34 | * <b>IMPORTANT NOTE:</b> |
||
35 | * |
||
36 | * The fields of this class are only public for 2 reasons: |
||
37 | * 1) To allow fast READ access. |
||
38 | * 2) To drastically reduce the size of a serialized instance (private/protected members |
||
39 | * get the whole class name, namespace inclusive, prepended to every property in |
||
40 | * the serialized representation). |
||
41 | * |
||
42 | * @since 1.0 |
||
43 | */ |
||
44 | class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMetadata |
||
45 | { |
||
46 | /* The Id generator types. */ |
||
47 | /** |
||
48 | * AUTO means Doctrine will automatically create a new \MongoId instance for us. |
||
49 | */ |
||
50 | const GENERATOR_TYPE_AUTO = 1; |
||
51 | |||
52 | /** |
||
53 | * INCREMENT means a separate collection is used for maintaining and incrementing id generation. |
||
54 | * Offers full portability. |
||
55 | */ |
||
56 | const GENERATOR_TYPE_INCREMENT = 2; |
||
57 | |||
58 | /** |
||
59 | * UUID means Doctrine will generate a uuid for us. |
||
60 | */ |
||
61 | const GENERATOR_TYPE_UUID = 3; |
||
62 | |||
63 | /** |
||
64 | * ALNUM means Doctrine will generate Alpha-numeric string identifiers, using the INCREMENT |
||
65 | * generator to ensure identifier uniqueness |
||
66 | */ |
||
67 | const GENERATOR_TYPE_ALNUM = 4; |
||
68 | |||
69 | /** |
||
70 | * CUSTOM means Doctrine expect a class parameter. It will then try to initiate that class |
||
71 | * and pass other options to the generator. It will throw an Exception if the class |
||
72 | * does not exist or if an option was passed for that there is not setter in the new |
||
73 | * generator class. |
||
74 | * |
||
75 | * The class will have to be a subtype of AbstractIdGenerator. |
||
76 | */ |
||
77 | const GENERATOR_TYPE_CUSTOM = 5; |
||
78 | |||
79 | /** |
||
80 | * NONE means Doctrine will not generate any id for us and you are responsible for manually |
||
81 | * assigning an id. |
||
82 | */ |
||
83 | const GENERATOR_TYPE_NONE = 6; |
||
84 | |||
85 | /** |
||
86 | * Default discriminator field name. |
||
87 | * |
||
88 | * This is used for associations value for associations where a that do not define a "targetDocument" or |
||
89 | * "discriminatorField" option in their mapping. |
||
90 | */ |
||
91 | const DEFAULT_DISCRIMINATOR_FIELD = '_doctrine_class_name'; |
||
92 | |||
93 | const REFERENCE_ONE = 1; |
||
94 | const REFERENCE_MANY = 2; |
||
95 | const EMBED_ONE = 3; |
||
96 | const EMBED_MANY = 4; |
||
97 | const MANY = 'many'; |
||
98 | const ONE = 'one'; |
||
99 | |||
100 | /** |
||
101 | * The types of storeAs references |
||
102 | */ |
||
103 | const REFERENCE_STORE_AS_ID = 'id'; |
||
104 | const REFERENCE_STORE_AS_DB_REF = 'dbRef'; |
||
105 | const REFERENCE_STORE_AS_DB_REF_WITH_DB = 'dbRefWithDb'; |
||
106 | |||
107 | /* The inheritance mapping types */ |
||
108 | /** |
||
109 | * NONE means the class does not participate in an inheritance hierarchy |
||
110 | * and therefore does not need an inheritance mapping type. |
||
111 | */ |
||
112 | const INHERITANCE_TYPE_NONE = 1; |
||
113 | |||
114 | /** |
||
115 | * SINGLE_COLLECTION means the class will be persisted according to the rules of |
||
116 | * <tt>Single Collection Inheritance</tt>. |
||
117 | */ |
||
118 | const INHERITANCE_TYPE_SINGLE_COLLECTION = 2; |
||
119 | |||
120 | /** |
||
121 | * COLLECTION_PER_CLASS means the class will be persisted according to the rules |
||
122 | * of <tt>Concrete Collection Inheritance</tt>. |
||
123 | */ |
||
124 | const INHERITANCE_TYPE_COLLECTION_PER_CLASS = 3; |
||
125 | |||
126 | /** |
||
127 | * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time |
||
128 | * by doing a property-by-property comparison with the original data. This will |
||
129 | * be done for all entities that are in MANAGED state at commit-time. |
||
130 | * |
||
131 | * This is the default change tracking policy. |
||
132 | */ |
||
133 | const CHANGETRACKING_DEFERRED_IMPLICIT = 1; |
||
134 | |||
135 | /** |
||
136 | * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time |
||
137 | * by doing a property-by-property comparison with the original data. This will |
||
138 | * be done only for entities that were explicitly saved (through persist() or a cascade). |
||
139 | */ |
||
140 | const CHANGETRACKING_DEFERRED_EXPLICIT = 2; |
||
141 | |||
142 | /** |
||
143 | * NOTIFY means that Doctrine relies on the entities sending out notifications |
||
144 | * when their properties change. Such entity classes must implement |
||
145 | * the <tt>NotifyPropertyChanged</tt> interface. |
||
146 | */ |
||
147 | const CHANGETRACKING_NOTIFY = 3; |
||
148 | |||
149 | /** |
||
150 | * SET means that fields will be written to the database using a $set operator |
||
151 | */ |
||
152 | const STORAGE_STRATEGY_SET = 'set'; |
||
153 | |||
154 | /** |
||
155 | * INCREMENT means that fields will be written to the database by calculating |
||
156 | * the difference and using the $inc operator |
||
157 | */ |
||
158 | const STORAGE_STRATEGY_INCREMENT = 'increment'; |
||
159 | |||
160 | const STORAGE_STRATEGY_PUSH_ALL = 'pushAll'; |
||
161 | const STORAGE_STRATEGY_ADD_TO_SET = 'addToSet'; |
||
162 | const STORAGE_STRATEGY_ATOMIC_SET = 'atomicSet'; |
||
163 | const STORAGE_STRATEGY_ATOMIC_SET_ARRAY = 'atomicSetArray'; |
||
164 | const STORAGE_STRATEGY_SET_ARRAY = 'setArray'; |
||
165 | |||
166 | /** |
||
167 | * READ-ONLY: The name of the mongo database the document is mapped to. |
||
168 | */ |
||
169 | public $db; |
||
170 | |||
171 | /** |
||
172 | * READ-ONLY: The name of the mongo collection the document is mapped to. |
||
173 | */ |
||
174 | public $collection; |
||
175 | |||
176 | /** |
||
177 | * READ-ONLY: If the collection should be a fixed size. |
||
178 | */ |
||
179 | public $collectionCapped; |
||
180 | |||
181 | /** |
||
182 | * READ-ONLY: If the collection is fixed size, its size in bytes. |
||
183 | */ |
||
184 | public $collectionSize; |
||
185 | |||
186 | /** |
||
187 | * READ-ONLY: If the collection is fixed size, the maximum number of elements to store in the collection. |
||
188 | */ |
||
189 | public $collectionMax; |
||
190 | |||
191 | /** |
||
192 | * READ-ONLY: Describes the level of acknowledgement requested from MongoDB for write operations. |
||
193 | */ |
||
194 | public $writeConcern; |
||
195 | |||
196 | /** |
||
197 | * READ-ONLY: The field name of the document identifier. |
||
198 | */ |
||
199 | public $identifier; |
||
200 | |||
201 | /** |
||
202 | * READ-ONLY: The field that stores a file reference and indicates the |
||
203 | * document is a file and should be stored on the MongoGridFS. |
||
204 | */ |
||
205 | public $file; |
||
206 | |||
207 | /** |
||
208 | * READ-ONLY: The field that stores the calculated distance when performing geo spatial |
||
209 | * queries. |
||
210 | */ |
||
211 | public $distance; |
||
212 | |||
213 | /** |
||
214 | * READ-ONLY: Whether or not reads for this class are okay to read from a slave. |
||
215 | */ |
||
216 | public $slaveOkay; |
||
217 | |||
218 | /** |
||
219 | * READ-ONLY: The array of indexes for the document collection. |
||
220 | */ |
||
221 | public $indexes = array(); |
||
222 | |||
223 | /** |
||
224 | * READ-ONLY: Keys and options describing shard key. Only for sharded collections. |
||
225 | */ |
||
226 | public $shardKey; |
||
227 | |||
228 | /** |
||
229 | * READ-ONLY: Whether or not queries on this document should require indexes. |
||
230 | * |
||
231 | * @deprecated property was deprecated in 1.2 and will be removed in 2.0 |
||
232 | */ |
||
233 | public $requireIndexes = false; |
||
234 | |||
235 | /** |
||
236 | * READ-ONLY: The name of the document class. |
||
237 | */ |
||
238 | public $name; |
||
239 | |||
240 | /** |
||
241 | * READ-ONLY: The namespace the document class is contained in. |
||
242 | * |
||
243 | * @var string |
||
244 | * @todo Not really needed. Usage could be localized. |
||
245 | */ |
||
246 | public $namespace; |
||
247 | |||
248 | /** |
||
249 | * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance |
||
250 | * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same |
||
251 | * as {@link $documentName}. |
||
252 | * |
||
253 | * @var string |
||
254 | */ |
||
255 | public $rootDocumentName; |
||
256 | |||
257 | /** |
||
258 | * The name of the custom repository class used for the document class. |
||
259 | * (Optional). |
||
260 | * |
||
261 | * @var string |
||
262 | */ |
||
263 | public $customRepositoryClassName; |
||
264 | |||
265 | /** |
||
266 | * READ-ONLY: The names of the parent classes (ancestors). |
||
267 | * |
||
268 | * @var array |
||
269 | */ |
||
270 | public $parentClasses = array(); |
||
271 | |||
272 | /** |
||
273 | * READ-ONLY: The names of all subclasses (descendants). |
||
274 | * |
||
275 | * @var array |
||
276 | */ |
||
277 | public $subClasses = array(); |
||
278 | |||
279 | /** |
||
280 | * The ReflectionProperty instances of the mapped class. |
||
281 | * |
||
282 | * @var \ReflectionProperty[] |
||
283 | */ |
||
284 | public $reflFields = array(); |
||
285 | |||
286 | /** |
||
287 | * READ-ONLY: The inheritance mapping type used by the class. |
||
288 | * |
||
289 | * @var integer |
||
290 | */ |
||
291 | public $inheritanceType = self::INHERITANCE_TYPE_NONE; |
||
292 | |||
293 | /** |
||
294 | * READ-ONLY: The Id generator type used by the class. |
||
295 | * |
||
296 | * @var string |
||
297 | */ |
||
298 | public $generatorType = self::GENERATOR_TYPE_AUTO; |
||
299 | |||
300 | /** |
||
301 | * READ-ONLY: The Id generator options. |
||
302 | * |
||
303 | * @var array |
||
304 | */ |
||
305 | public $generatorOptions = array(); |
||
306 | |||
307 | /** |
||
308 | * READ-ONLY: The ID generator used for generating IDs for this class. |
||
309 | * |
||
310 | * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator |
||
311 | */ |
||
312 | public $idGenerator; |
||
313 | |||
314 | /** |
||
315 | * READ-ONLY: The field mappings of the class. |
||
316 | * Keys are field names and values are mapping definitions. |
||
317 | * |
||
318 | * The mapping definition array has the following values: |
||
319 | * |
||
320 | * - <b>fieldName</b> (string) |
||
321 | * The name of the field in the Document. |
||
322 | * |
||
323 | * - <b>id</b> (boolean, optional) |
||
324 | * Marks the field as the primary key of the document. Multiple fields of an |
||
325 | * document can have the id attribute, forming a composite key. |
||
326 | * |
||
327 | * @var array |
||
328 | */ |
||
329 | public $fieldMappings = array(); |
||
330 | |||
331 | /** |
||
332 | * READ-ONLY: The association mappings of the class. |
||
333 | * Keys are field names and values are mapping definitions. |
||
334 | * |
||
335 | * @var array |
||
336 | */ |
||
337 | public $associationMappings = array(); |
||
338 | |||
339 | /** |
||
340 | * READ-ONLY: Array of fields to also load with a given method. |
||
341 | * |
||
342 | * @var array |
||
343 | */ |
||
344 | public $alsoLoadMethods = array(); |
||
345 | |||
346 | /** |
||
347 | * READ-ONLY: The registered lifecycle callbacks for documents of this class. |
||
348 | * |
||
349 | * @var array |
||
350 | */ |
||
351 | public $lifecycleCallbacks = array(); |
||
352 | |||
353 | /** |
||
354 | * READ-ONLY: The discriminator value of this class. |
||
355 | * |
||
356 | * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies |
||
357 | * where a discriminator field is used.</b> |
||
358 | * |
||
359 | * @var mixed |
||
360 | * @see discriminatorField |
||
361 | */ |
||
362 | public $discriminatorValue; |
||
363 | |||
364 | /** |
||
365 | * READ-ONLY: The discriminator map of all mapped classes in the hierarchy. |
||
366 | * |
||
367 | * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy |
||
368 | * where a discriminator field is used.</b> |
||
369 | * |
||
370 | * @var mixed |
||
371 | * @see discriminatorField |
||
372 | */ |
||
373 | public $discriminatorMap = array(); |
||
374 | |||
375 | /** |
||
376 | * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION |
||
377 | * inheritance mapping. |
||
378 | * |
||
379 | * @var string |
||
380 | */ |
||
381 | public $discriminatorField; |
||
382 | |||
383 | /** |
||
384 | * READ-ONLY: The default value for discriminatorField in case it's not set in the document |
||
385 | * |
||
386 | * @var string |
||
387 | * @see discriminatorField |
||
388 | */ |
||
389 | public $defaultDiscriminatorValue; |
||
390 | |||
391 | /** |
||
392 | * READ-ONLY: Whether this class describes the mapping of a mapped superclass. |
||
393 | * |
||
394 | * @var boolean |
||
395 | */ |
||
396 | public $isMappedSuperclass = false; |
||
397 | |||
398 | /** |
||
399 | * READ-ONLY: Whether this class describes the mapping of a embedded document. |
||
400 | * |
||
401 | * @var boolean |
||
402 | */ |
||
403 | public $isEmbeddedDocument = false; |
||
404 | |||
405 | /** |
||
406 | * READ-ONLY: Whether this class describes the mapping of an aggregation result document. |
||
407 | * |
||
408 | * @var boolean |
||
409 | */ |
||
410 | public $isQueryResultDocument = false; |
||
411 | |||
412 | /** |
||
413 | * READ-ONLY: The policy used for change-tracking on entities of this class. |
||
414 | * |
||
415 | * @var integer |
||
416 | */ |
||
417 | public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT; |
||
418 | |||
419 | /** |
||
420 | * READ-ONLY: A flag for whether or not instances of this class are to be versioned |
||
421 | * with optimistic locking. |
||
422 | * |
||
423 | * @var boolean $isVersioned |
||
424 | */ |
||
425 | public $isVersioned; |
||
426 | |||
427 | /** |
||
428 | * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any). |
||
429 | * |
||
430 | * @var mixed $versionField |
||
431 | */ |
||
432 | public $versionField; |
||
433 | |||
434 | /** |
||
435 | * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic |
||
436 | * locking. |
||
437 | * |
||
438 | * @var boolean $isLockable |
||
439 | */ |
||
440 | public $isLockable; |
||
441 | |||
442 | /** |
||
443 | * READ-ONLY: The name of the field which is used for locking a document. |
||
444 | * |
||
445 | * @var mixed $lockField |
||
446 | */ |
||
447 | public $lockField; |
||
448 | |||
449 | /** |
||
450 | * The ReflectionClass instance of the mapped class. |
||
451 | * |
||
452 | * @var \ReflectionClass |
||
453 | */ |
||
454 | public $reflClass; |
||
455 | |||
456 | /** |
||
457 | * Initializes a new ClassMetadata instance that will hold the object-document mapping |
||
458 | * metadata of the class with the given name. |
||
459 | * |
||
460 | * @param string $documentName The name of the document class the new instance is used for. |
||
461 | */ |
||
462 | 975 | public function __construct($documentName) |
|
463 | { |
||
464 | 975 | $this->name = $documentName; |
|
465 | 975 | $this->rootDocumentName = $documentName; |
|
466 | 975 | } |
|
467 | |||
468 | /** |
||
469 | * {@inheritDoc} |
||
470 | */ |
||
471 | 903 | public function getReflectionClass() |
|
472 | { |
||
473 | 903 | if ( ! $this->reflClass) { |
|
474 | 2 | $this->reflClass = new \ReflectionClass($this->name); |
|
475 | } |
||
476 | |||
477 | 903 | return $this->reflClass; |
|
478 | } |
||
479 | |||
480 | /** |
||
481 | * {@inheritDoc} |
||
482 | */ |
||
483 | 330 | public function isIdentifier($fieldName) |
|
484 | { |
||
485 | 330 | return $this->identifier === $fieldName; |
|
486 | } |
||
487 | |||
488 | /** |
||
489 | * INTERNAL: |
||
490 | * Sets the mapped identifier field of this class. |
||
491 | * |
||
492 | * @param string $identifier |
||
493 | */ |
||
494 | 370 | public function setIdentifier($identifier) |
|
495 | { |
||
496 | 370 | $this->identifier = $identifier; |
|
497 | 370 | } |
|
498 | |||
499 | /** |
||
500 | * {@inheritDoc} |
||
501 | * |
||
502 | * Since MongoDB only allows exactly one identifier field |
||
503 | * this will always return an array with only one value |
||
504 | */ |
||
505 | 40 | public function getIdentifier() |
|
506 | { |
||
507 | 40 | return array($this->identifier); |
|
508 | } |
||
509 | |||
510 | /** |
||
511 | * {@inheritDoc} |
||
512 | * |
||
513 | * Since MongoDB only allows exactly one identifier field |
||
514 | * this will always return an array with only one value |
||
515 | */ |
||
516 | 98 | public function getIdentifierFieldNames() |
|
517 | { |
||
518 | 98 | return array($this->identifier); |
|
519 | } |
||
520 | |||
521 | /** |
||
522 | * {@inheritDoc} |
||
523 | */ |
||
524 | 561 | public function hasField($fieldName) |
|
525 | { |
||
526 | 561 | return isset($this->fieldMappings[$fieldName]); |
|
527 | } |
||
528 | |||
529 | /** |
||
530 | * Sets the inheritance type used by the class and it's subclasses. |
||
531 | * |
||
532 | * @param integer $type |
||
533 | */ |
||
534 | 386 | public function setInheritanceType($type) |
|
535 | { |
||
536 | 386 | $this->inheritanceType = $type; |
|
537 | 386 | } |
|
538 | |||
539 | /** |
||
540 | * Checks whether a mapped field is inherited from an entity superclass. |
||
541 | * |
||
542 | * @param string $fieldName |
||
543 | * |
||
544 | * @return boolean TRUE if the field is inherited, FALSE otherwise. |
||
545 | */ |
||
546 | 903 | public function isInheritedField($fieldName) |
|
547 | { |
||
548 | 903 | return isset($this->fieldMappings[$fieldName]['inherited']); |
|
549 | } |
||
550 | |||
551 | /** |
||
552 | * Registers a custom repository class for the document class. |
||
553 | * |
||
554 | * @param string $repositoryClassName The class name of the custom repository. |
||
555 | */ |
||
556 | 318 | public function setCustomRepositoryClass($repositoryClassName) |
|
557 | { |
||
558 | 318 | if ($this->isEmbeddedDocument || $this->isQueryResultDocument) { |
|
559 | return; |
||
560 | } |
||
561 | |||
562 | 318 | View Code Duplication | if ($repositoryClassName && strpos($repositoryClassName, '\\') === false && strlen($this->namespace)) { |
563 | 4 | $repositoryClassName = $this->namespace . '\\' . $repositoryClassName; |
|
564 | } |
||
565 | |||
566 | 318 | $this->customRepositoryClassName = $repositoryClassName; |
|
567 | 318 | } |
|
568 | |||
569 | /** |
||
570 | * Dispatches the lifecycle event of the given document by invoking all |
||
571 | * registered callbacks. |
||
572 | * |
||
573 | * @param string $event Lifecycle event |
||
574 | * @param object $document Document on which the event occurred |
||
575 | * @param array $arguments Arguments to pass to all callbacks |
||
576 | * @throws \InvalidArgumentException if document class is not this class or |
||
577 | * a Proxy of this class |
||
578 | */ |
||
579 | 660 | public function invokeLifecycleCallbacks($event, $document, array $arguments = null) |
|
580 | { |
||
581 | 660 | if ( ! $document instanceof $this->name) { |
|
582 | 1 | throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document))); |
|
583 | } |
||
584 | |||
585 | 659 | if (empty($this->lifecycleCallbacks[$event])) { |
|
586 | 645 | return; |
|
587 | } |
||
588 | |||
589 | 196 | foreach ($this->lifecycleCallbacks[$event] as $callback) { |
|
590 | 196 | if ($arguments !== null) { |
|
591 | 195 | call_user_func_array(array($document, $callback), $arguments); |
|
592 | } else { |
||
593 | 2 | $document->$callback(); |
|
594 | } |
||
595 | } |
||
596 | 196 | } |
|
597 | |||
598 | /** |
||
599 | * Checks whether the class has callbacks registered for a lifecycle event. |
||
600 | * |
||
601 | * @param string $event Lifecycle event |
||
602 | * |
||
603 | * @return boolean |
||
604 | */ |
||
605 | public function hasLifecycleCallbacks($event) |
||
606 | { |
||
607 | return ! empty($this->lifecycleCallbacks[$event]); |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Gets the registered lifecycle callbacks for an event. |
||
612 | * |
||
613 | * @param string $event |
||
614 | * @return array |
||
615 | */ |
||
616 | public function getLifecycleCallbacks($event) |
||
617 | { |
||
618 | return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array(); |
||
619 | } |
||
620 | |||
621 | /** |
||
622 | * Adds a lifecycle callback for documents of this class. |
||
623 | * |
||
624 | * If the callback is already registered, this is a NOOP. |
||
625 | * |
||
626 | * @param string $callback |
||
627 | * @param string $event |
||
628 | */ |
||
629 | 297 | public function addLifecycleCallback($callback, $event) |
|
630 | { |
||
631 | 297 | if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) { |
|
632 | 1 | return; |
|
633 | } |
||
634 | |||
635 | 297 | $this->lifecycleCallbacks[$event][] = $callback; |
|
636 | 297 | } |
|
637 | |||
638 | /** |
||
639 | * Sets the lifecycle callbacks for documents of this class. |
||
640 | * |
||
641 | * Any previously registered callbacks are overwritten. |
||
642 | * |
||
643 | * @param array $callbacks |
||
644 | */ |
||
645 | 369 | public function setLifecycleCallbacks(array $callbacks) |
|
646 | { |
||
647 | 369 | $this->lifecycleCallbacks = $callbacks; |
|
648 | 369 | } |
|
649 | |||
650 | /** |
||
651 | * Registers a method for loading document data before field hydration. |
||
652 | * |
||
653 | * Note: A method may be registered multiple times for different fields. |
||
654 | * it will be invoked only once for the first field found. |
||
655 | * |
||
656 | * @param string $method Method name |
||
657 | * @param array|string $fields Database field name(s) |
||
658 | */ |
||
659 | 15 | public function registerAlsoLoadMethod($method, $fields) |
|
660 | { |
||
661 | 15 | $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields); |
|
662 | 15 | } |
|
663 | |||
664 | /** |
||
665 | * Sets the AlsoLoad methods for documents of this class. |
||
666 | * |
||
667 | * Any previously registered methods are overwritten. |
||
668 | * |
||
669 | * @param array $methods |
||
670 | */ |
||
671 | 369 | public function setAlsoLoadMethods(array $methods) |
|
672 | { |
||
673 | 369 | $this->alsoLoadMethods = $methods; |
|
674 | 369 | } |
|
675 | |||
676 | /** |
||
677 | * Sets the discriminator field. |
||
678 | * |
||
679 | * The field name is the the unmapped database field. Discriminator values |
||
680 | * are only used to discern the hydration class and are not mapped to class |
||
681 | * properties. |
||
682 | * |
||
683 | * @param string $discriminatorField |
||
684 | * |
||
685 | * @throws MappingException If the discriminator field conflicts with the |
||
686 | * "name" attribute of a mapped field. |
||
687 | */ |
||
688 | 399 | public function setDiscriminatorField($discriminatorField) |
|
689 | { |
||
690 | 399 | if ($discriminatorField === null) { |
|
691 | 326 | $this->discriminatorField = null; |
|
692 | |||
693 | 326 | return; |
|
694 | } |
||
695 | |||
696 | // Handle array argument with name/fieldName keys for BC |
||
697 | 130 | if (is_array($discriminatorField)) { |
|
698 | if (isset($discriminatorField['name'])) { |
||
699 | $discriminatorField = $discriminatorField['name']; |
||
700 | } elseif (isset($discriminatorField['fieldName'])) { |
||
701 | $discriminatorField = $discriminatorField['fieldName']; |
||
702 | } |
||
703 | } |
||
704 | |||
705 | 130 | foreach ($this->fieldMappings as $fieldMapping) { |
|
706 | 4 | if ($discriminatorField == $fieldMapping['name']) { |
|
707 | 1 | throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField); |
|
708 | } |
||
709 | } |
||
710 | |||
711 | 129 | $this->discriminatorField = $discriminatorField; |
|
712 | 129 | } |
|
713 | |||
714 | /** |
||
715 | * Sets the discriminator values used by this class. |
||
716 | * Used for JOINED and SINGLE_TABLE inheritance mapping strategies. |
||
717 | * |
||
718 | * @param array $map |
||
719 | * |
||
720 | * @throws MappingException |
||
721 | */ |
||
722 | 392 | public function setDiscriminatorMap(array $map) |
|
723 | { |
||
724 | 392 | foreach ($map as $value => $className) { |
|
725 | 125 | if (strpos($className, '\\') === false && strlen($this->namespace)) { |
|
726 | 91 | $className = $this->namespace . '\\' . $className; |
|
727 | } |
||
728 | 125 | $this->discriminatorMap[$value] = $className; |
|
729 | 125 | if ($this->name == $className) { |
|
730 | 117 | $this->discriminatorValue = $value; |
|
731 | } else { |
||
732 | 120 | if ( ! class_exists($className)) { |
|
733 | throw MappingException::invalidClassInDiscriminatorMap($className, $this->name); |
||
734 | } |
||
735 | 120 | if (is_subclass_of($className, $this->name)) { |
|
736 | 106 | $this->subClasses[] = $className; |
|
737 | } |
||
738 | } |
||
739 | } |
||
740 | 392 | } |
|
741 | |||
742 | /** |
||
743 | * Sets the default discriminator value to be used for this class |
||
744 | * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value |
||
745 | * |
||
746 | * @param string $defaultDiscriminatorValue |
||
747 | * |
||
748 | * @throws MappingException |
||
749 | */ |
||
750 | 376 | public function setDefaultDiscriminatorValue($defaultDiscriminatorValue) |
|
751 | { |
||
752 | 376 | if ($defaultDiscriminatorValue === null) { |
|
753 | 369 | $this->defaultDiscriminatorValue = null; |
|
754 | |||
755 | 369 | return; |
|
756 | } |
||
757 | |||
758 | 60 | if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) { |
|
759 | throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name); |
||
760 | } |
||
761 | |||
762 | 60 | $this->defaultDiscriminatorValue = $defaultDiscriminatorValue; |
|
763 | 60 | } |
|
764 | |||
765 | /** |
||
766 | * Sets the discriminator value for this class. |
||
767 | * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single |
||
768 | * collection. |
||
769 | * |
||
770 | * @param string $value |
||
771 | */ |
||
772 | 3 | public function setDiscriminatorValue($value) |
|
773 | { |
||
774 | 3 | $this->discriminatorMap[$value] = $this->name; |
|
775 | 3 | $this->discriminatorValue = $value; |
|
776 | 3 | } |
|
777 | |||
778 | /** |
||
779 | * Sets the slaveOkay option applied to collections for this class. |
||
780 | * |
||
781 | * @param boolean|null $slaveOkay |
||
782 | */ |
||
783 | 3 | public function setSlaveOkay($slaveOkay) |
|
784 | { |
||
785 | 3 | $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay; |
|
786 | 3 | } |
|
787 | |||
788 | /** |
||
789 | * Add a index for this Document. |
||
790 | * |
||
791 | * @param array $keys Array of keys for the index. |
||
792 | * @param array $options Array of options for the index. |
||
793 | */ |
||
794 | 232 | public function addIndex($keys, array $options = array()) |
|
795 | { |
||
796 | 232 | $this->indexes[] = array( |
|
797 | View Code Duplication | 'keys' => array_map(function($value) { |
|
798 | 232 | if ($value == 1 || $value == -1) { |
|
799 | 63 | return (int) $value; |
|
800 | } |
||
801 | 224 | if (is_string($value)) { |
|
802 | 224 | $lower = strtolower($value); |
|
803 | 224 | if ($lower === 'asc') { |
|
804 | 217 | return 1; |
|
805 | 11 | } elseif ($lower === 'desc') { |
|
806 | 4 | return -1; |
|
807 | } |
||
808 | } |
||
809 | 7 | return $value; |
|
810 | 232 | }, $keys), |
|
811 | 232 | 'options' => $options |
|
812 | ); |
||
813 | 232 | } |
|
814 | |||
815 | /** |
||
816 | * Set whether or not queries on this document should require indexes. |
||
817 | * |
||
818 | * @param bool $requireIndexes |
||
819 | * |
||
820 | * @deprecated method was deprecated in 1.2 and will be removed in 2.0 |
||
821 | */ |
||
822 | 894 | public function setRequireIndexes($requireIndexes) |
|
823 | { |
||
824 | 894 | @trigger_error( |
|
0 ignored issues
–
show
|
|||
825 | 894 | 'requireIndexes was deprecated in version 1.2 and will be removed altogether in 2.0.', |
|
826 | 894 | E_USER_DEPRECATED |
|
827 | ); |
||
828 | 894 | $this->requireIndexes = $requireIndexes; |
|
829 | 894 | } |
|
830 | |||
831 | /** |
||
832 | * Returns the array of indexes for this Document. |
||
833 | * |
||
834 | * @return array $indexes The array of indexes. |
||
835 | */ |
||
836 | 54 | public function getIndexes() |
|
837 | { |
||
838 | 54 | return $this->indexes; |
|
839 | } |
||
840 | |||
841 | /** |
||
842 | * Checks whether this document has indexes or not. |
||
843 | * |
||
844 | * @return boolean |
||
845 | */ |
||
846 | public function hasIndexes() |
||
847 | { |
||
848 | return $this->indexes ? true : false; |
||
849 | } |
||
850 | |||
851 | /** |
||
852 | * Set shard key for this Document. |
||
853 | * |
||
854 | * @param array $keys Array of document keys. |
||
855 | * @param array $options Array of sharding options. |
||
856 | * |
||
857 | * @throws MappingException |
||
858 | */ |
||
859 | 77 | public function setShardKey(array $keys, array $options = array()) |
|
860 | { |
||
861 | 77 | if ($this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_COLLECTION && !is_null($this->shardKey)) { |
|
862 | 2 | throw MappingException::shardKeyInSingleCollInheritanceSubclass($this->getName()); |
|
863 | } |
||
864 | |||
865 | 77 | if ($this->isEmbeddedDocument) { |
|
866 | 2 | throw MappingException::embeddedDocumentCantHaveShardKey($this->getName()); |
|
867 | } |
||
868 | |||
869 | 75 | foreach (array_keys($keys) as $field) { |
|
870 | 75 | if (! isset($this->fieldMappings[$field])) { |
|
871 | 68 | continue; |
|
872 | } |
||
873 | |||
874 | 7 | if (in_array($this->fieldMappings[$field]['type'], ['many', 'collection'])) { |
|
875 | 3 | throw MappingException::noMultiKeyShardKeys($this->getName(), $field); |
|
876 | } |
||
877 | |||
878 | 4 | if ($this->fieldMappings[$field]['strategy'] !== static::STORAGE_STRATEGY_SET) { |
|
879 | 1 | throw MappingException::onlySetStrategyAllowedInShardKey($this->getName(), $field); |
|
880 | } |
||
881 | } |
||
882 | |||
883 | 71 | $this->shardKey = array( |
|
884 | View Code Duplication | 'keys' => array_map(function($value) { |
|
885 | 71 | if ($value == 1 || $value == -1) { |
|
886 | 6 | return (int) $value; |
|
887 | } |
||
888 | 70 | if (is_string($value)) { |
|
889 | 70 | $lower = strtolower($value); |
|
890 | 70 | if ($lower === 'asc') { |
|
891 | 69 | return 1; |
|
892 | 53 | } elseif ($lower === 'desc') { |
|
893 | return -1; |
||
894 | } |
||
895 | } |
||
896 | 53 | return $value; |
|
897 | 71 | }, $keys), |
|
898 | 71 | 'options' => $options |
|
899 | ); |
||
900 | 71 | } |
|
901 | |||
902 | /** |
||
903 | * @return array |
||
904 | */ |
||
905 | 18 | public function getShardKey() |
|
906 | { |
||
907 | 18 | return $this->shardKey; |
|
908 | } |
||
909 | |||
910 | /** |
||
911 | * Checks whether this document has shard key or not. |
||
912 | * |
||
913 | * @return bool |
||
914 | */ |
||
915 | 598 | public function isSharded() |
|
916 | { |
||
917 | 598 | return $this->shardKey ? true : false; |
|
918 | } |
||
919 | |||
920 | /** |
||
921 | * Sets the write concern used by this class. |
||
922 | * |
||
923 | * @param string $writeConcern |
||
924 | */ |
||
925 | 383 | public function setWriteConcern($writeConcern) |
|
926 | { |
||
927 | 383 | $this->writeConcern = $writeConcern; |
|
928 | 383 | } |
|
929 | |||
930 | /** |
||
931 | * @return string |
||
932 | */ |
||
933 | 12 | public function getWriteConcern() |
|
934 | { |
||
935 | 12 | return $this->writeConcern; |
|
936 | } |
||
937 | |||
938 | /** |
||
939 | * Whether there is a write concern configured for this class. |
||
940 | * |
||
941 | * @return bool |
||
942 | */ |
||
943 | 604 | public function hasWriteConcern() |
|
944 | { |
||
945 | 604 | return $this->writeConcern !== null; |
|
946 | } |
||
947 | |||
948 | /** |
||
949 | * Sets the change tracking policy used by this class. |
||
950 | * |
||
951 | * @param integer $policy |
||
952 | */ |
||
953 | 374 | public function setChangeTrackingPolicy($policy) |
|
954 | { |
||
955 | 374 | $this->changeTrackingPolicy = $policy; |
|
956 | 374 | } |
|
957 | |||
958 | /** |
||
959 | * Whether the change tracking policy of this class is "deferred explicit". |
||
960 | * |
||
961 | * @return boolean |
||
962 | */ |
||
963 | 73 | public function isChangeTrackingDeferredExplicit() |
|
964 | { |
||
965 | 73 | return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT; |
|
966 | } |
||
967 | |||
968 | /** |
||
969 | * Whether the change tracking policy of this class is "deferred implicit". |
||
970 | * |
||
971 | * @return boolean |
||
972 | */ |
||
973 | 624 | public function isChangeTrackingDeferredImplicit() |
|
974 | { |
||
975 | 624 | return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT; |
|
976 | } |
||
977 | |||
978 | /** |
||
979 | * Whether the change tracking policy of this class is "notify". |
||
980 | * |
||
981 | * @return boolean |
||
982 | */ |
||
983 | 347 | public function isChangeTrackingNotify() |
|
984 | { |
||
985 | 347 | return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY; |
|
986 | } |
||
987 | |||
988 | /** |
||
989 | * Gets the ReflectionProperties of the mapped class. |
||
990 | * |
||
991 | * @return array An array of ReflectionProperty instances. |
||
992 | */ |
||
993 | 98 | public function getReflectionProperties() |
|
994 | { |
||
995 | 98 | return $this->reflFields; |
|
996 | } |
||
997 | |||
998 | /** |
||
999 | * Gets a ReflectionProperty for a specific field of the mapped class. |
||
1000 | * |
||
1001 | * @param string $name |
||
1002 | * |
||
1003 | * @return \ReflectionProperty |
||
1004 | */ |
||
1005 | public function getReflectionProperty($name) |
||
1006 | { |
||
1007 | return $this->reflFields[$name]; |
||
1008 | } |
||
1009 | |||
1010 | /** |
||
1011 | * {@inheritDoc} |
||
1012 | */ |
||
1013 | 909 | public function getName() |
|
1014 | { |
||
1015 | 909 | return $this->name; |
|
1016 | } |
||
1017 | |||
1018 | /** |
||
1019 | * The namespace this Document class belongs to. |
||
1020 | * |
||
1021 | * @return string $namespace The namespace name. |
||
1022 | */ |
||
1023 | public function getNamespace() |
||
1024 | { |
||
1025 | return $this->namespace; |
||
1026 | } |
||
1027 | |||
1028 | /** |
||
1029 | * Returns the database this Document is mapped to. |
||
1030 | * |
||
1031 | * @return string $db The database name. |
||
1032 | */ |
||
1033 | 829 | public function getDatabase() |
|
1034 | { |
||
1035 | 829 | return $this->db; |
|
1036 | } |
||
1037 | |||
1038 | /** |
||
1039 | * Set the database this Document is mapped to. |
||
1040 | * |
||
1041 | * @param string $db The database name |
||
1042 | */ |
||
1043 | 104 | public function setDatabase($db) |
|
1044 | { |
||
1045 | 104 | $this->db = $db; |
|
1046 | 104 | } |
|
1047 | |||
1048 | /** |
||
1049 | * Get the collection this Document is mapped to. |
||
1050 | * |
||
1051 | * @return string $collection The collection name. |
||
1052 | */ |
||
1053 | 834 | public function getCollection() |
|
1054 | { |
||
1055 | 834 | return $this->collection; |
|
1056 | } |
||
1057 | |||
1058 | /** |
||
1059 | * Sets the collection this Document is mapped to. |
||
1060 | * |
||
1061 | * @param array|string $name |
||
1062 | * |
||
1063 | * @throws \InvalidArgumentException |
||
1064 | */ |
||
1065 | 939 | public function setCollection($name) |
|
1066 | { |
||
1067 | 939 | if (is_array($name)) { |
|
1068 | if ( ! isset($name['name'])) { |
||
1069 | throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()'); |
||
1070 | } |
||
1071 | $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false; |
||
1072 | $this->collectionSize = isset($name['size']) ? $name['size'] : 0; |
||
1073 | $this->collectionMax = isset($name['max']) ? $name['max'] : 0; |
||
1074 | $this->collection = $name['name']; |
||
1075 | } else { |
||
1076 | 939 | $this->collection = $name; |
|
1077 | } |
||
1078 | 939 | } |
|
1079 | |||
1080 | /** |
||
1081 | * Get whether or not the documents collection is capped. |
||
1082 | * |
||
1083 | * @return boolean |
||
1084 | */ |
||
1085 | 4 | public function getCollectionCapped() |
|
1086 | { |
||
1087 | 4 | return $this->collectionCapped; |
|
1088 | } |
||
1089 | |||
1090 | /** |
||
1091 | * Set whether or not the documents collection is capped. |
||
1092 | * |
||
1093 | * @param boolean $bool |
||
1094 | */ |
||
1095 | 1 | public function setCollectionCapped($bool) |
|
1096 | { |
||
1097 | 1 | $this->collectionCapped = $bool; |
|
1098 | 1 | } |
|
1099 | |||
1100 | /** |
||
1101 | * Get the collection size |
||
1102 | * |
||
1103 | * @return integer |
||
1104 | */ |
||
1105 | 4 | public function getCollectionSize() |
|
1106 | { |
||
1107 | 4 | return $this->collectionSize; |
|
1108 | } |
||
1109 | |||
1110 | /** |
||
1111 | * Set the collection size. |
||
1112 | * |
||
1113 | * @param integer $size |
||
1114 | */ |
||
1115 | 1 | public function setCollectionSize($size) |
|
1116 | { |
||
1117 | 1 | $this->collectionSize = $size; |
|
1118 | 1 | } |
|
1119 | |||
1120 | /** |
||
1121 | * Get the collection max. |
||
1122 | * |
||
1123 | * @return integer |
||
1124 | */ |
||
1125 | 4 | public function getCollectionMax() |
|
1126 | { |
||
1127 | 4 | return $this->collectionMax; |
|
1128 | } |
||
1129 | |||
1130 | /** |
||
1131 | * Set the collection max. |
||
1132 | * |
||
1133 | * @param integer $max |
||
1134 | */ |
||
1135 | 1 | public function setCollectionMax($max) |
|
1136 | { |
||
1137 | 1 | $this->collectionMax = $max; |
|
1138 | 1 | } |
|
1139 | |||
1140 | /** |
||
1141 | * Returns TRUE if this Document is mapped to a collection FALSE otherwise. |
||
1142 | * |
||
1143 | * @return boolean |
||
1144 | */ |
||
1145 | public function isMappedToCollection() |
||
1146 | { |
||
1147 | return $this->collection ? true : false; |
||
1148 | } |
||
1149 | |||
1150 | /** |
||
1151 | * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise. |
||
1152 | * |
||
1153 | * @return boolean |
||
1154 | */ |
||
1155 | 775 | public function isFile() |
|
1156 | { |
||
1157 | 775 | return $this->file ? true : false; |
|
1158 | } |
||
1159 | |||
1160 | /** |
||
1161 | * Returns the file field name. |
||
1162 | * |
||
1163 | * @return string $file The file field name. |
||
1164 | */ |
||
1165 | 369 | public function getFile() |
|
1166 | { |
||
1167 | 369 | return $this->file; |
|
1168 | } |
||
1169 | |||
1170 | /** |
||
1171 | * Set the field name that stores the grid file. |
||
1172 | * |
||
1173 | * @param string $file |
||
1174 | */ |
||
1175 | 370 | public function setFile($file) |
|
1176 | { |
||
1177 | 370 | $this->file = $file; |
|
1178 | 370 | } |
|
1179 | |||
1180 | /** |
||
1181 | * Returns the distance field name. |
||
1182 | * |
||
1183 | * @return string $distance The distance field name. |
||
1184 | */ |
||
1185 | public function getDistance() |
||
1186 | { |
||
1187 | return $this->distance; |
||
1188 | } |
||
1189 | |||
1190 | /** |
||
1191 | * Set the field name that stores the distance. |
||
1192 | * |
||
1193 | * @param string $distance |
||
1194 | */ |
||
1195 | 1 | public function setDistance($distance) |
|
1196 | { |
||
1197 | 1 | $this->distance = $distance; |
|
1198 | 1 | } |
|
1199 | |||
1200 | /** |
||
1201 | * Map a field. |
||
1202 | * |
||
1203 | * @param array $mapping The mapping information. |
||
1204 | * |
||
1205 | * @return array |
||
1206 | * |
||
1207 | * @throws MappingException |
||
1208 | */ |
||
1209 | 953 | public function mapField(array $mapping) |
|
1210 | { |
||
1211 | 953 | if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) { |
|
1212 | 10 | $mapping['fieldName'] = $mapping['name']; |
|
1213 | } |
||
1214 | 953 | if ( ! isset($mapping['fieldName'])) { |
|
1215 | throw MappingException::missingFieldName($this->name); |
||
1216 | } |
||
1217 | 953 | if ( ! isset($mapping['name'])) { |
|
1218 | 943 | $mapping['name'] = $mapping['fieldName']; |
|
1219 | } |
||
1220 | 953 | if ($this->identifier === $mapping['name'] && empty($mapping['id'])) { |
|
1221 | 1 | throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']); |
|
1222 | } |
||
1223 | 952 | if (isset($this->fieldMappings[$mapping['fieldName']])) { |
|
1224 | //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']); |
||
1225 | } |
||
1226 | 952 | if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) { |
|
1227 | 1 | throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField); |
|
1228 | } |
||
1229 | 951 | View Code Duplication | if (isset($mapping['targetDocument']) && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) { |
1230 | 616 | $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument']; |
|
1231 | } |
||
1232 | 951 | if (isset($mapping['collectionClass'])) { |
|
1233 | 65 | View Code Duplication | if (strpos($mapping['collectionClass'], '\\') === false && strlen($this->namespace)) { |
1234 | 63 | $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass']; |
|
1235 | } |
||
1236 | 65 | $mapping['collectionClass'] = ltrim($mapping['collectionClass'], '\\'); |
|
1237 | } |
||
1238 | 951 | if ( ! empty($mapping['collectionClass'])) { |
|
1239 | 65 | $rColl = new \ReflectionClass($mapping['collectionClass']); |
|
1240 | 65 | if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) { |
|
1241 | 1 | throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']); |
|
1242 | } |
||
1243 | } |
||
1244 | |||
1245 | 950 | if (isset($mapping['discriminatorMap'])) { |
|
1246 | 123 | foreach ($mapping['discriminatorMap'] as $key => $class) { |
|
1247 | 123 | View Code Duplication | if (strpos($class, '\\') === false && strlen($this->namespace)) { |
1248 | 75 | $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class; |
|
1249 | } |
||
1250 | } |
||
1251 | } |
||
1252 | |||
1253 | 950 | if (isset($mapping['cascade']) && isset($mapping['embedded'])) { |
|
1254 | 1 | throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']); |
|
1255 | } |
||
1256 | |||
1257 | 949 | $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array(); |
|
1258 | |||
1259 | 949 | if (in_array('all', $cascades) || isset($mapping['embedded'])) { |
|
1260 | 644 | $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach'); |
|
1261 | } |
||
1262 | |||
1263 | 949 | if (isset($mapping['embedded'])) { |
|
1264 | 601 | unset($mapping['cascade']); |
|
1265 | 944 | } elseif (isset($mapping['cascade'])) { |
|
1266 | 408 | $mapping['cascade'] = $cascades; |
|
1267 | } |
||
1268 | |||
1269 | 949 | $mapping['isCascadeRemove'] = in_array('remove', $cascades); |
|
1270 | 949 | $mapping['isCascadePersist'] = in_array('persist', $cascades); |
|
1271 | 949 | $mapping['isCascadeRefresh'] = in_array('refresh', $cascades); |
|
1272 | 949 | $mapping['isCascadeMerge'] = in_array('merge', $cascades); |
|
1273 | 949 | $mapping['isCascadeDetach'] = in_array('detach', $cascades); |
|
1274 | |||
1275 | 949 | if (isset($mapping['type']) && $mapping['type'] === 'file') { |
|
1276 | 63 | $mapping['file'] = true; |
|
1277 | } |
||
1278 | 949 | if (isset($mapping['type']) && $mapping['type'] === 'increment') { |
|
1279 | 1 | $mapping['strategy'] = self::STORAGE_STRATEGY_INCREMENT; |
|
1280 | } |
||
1281 | 949 | View Code Duplication | if (isset($mapping['file']) && $mapping['file'] === true) { |
1282 | 63 | $this->file = $mapping['fieldName']; |
|
1283 | 63 | $mapping['name'] = 'file'; |
|
1284 | } |
||
1285 | 949 | View Code Duplication | if (isset($mapping['distance']) && $mapping['distance'] === true) { |
1286 | 7 | $this->distance = $mapping['fieldName']; |
|
1287 | } |
||
1288 | 949 | if (isset($mapping['id']) && $mapping['id'] === true) { |
|
1289 | 921 | $mapping['name'] = '_id'; |
|
1290 | 921 | $this->identifier = $mapping['fieldName']; |
|
1291 | 921 | View Code Duplication | if (isset($mapping['strategy'])) { |
1292 | 902 | $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy'])); |
|
1293 | } |
||
1294 | 921 | $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array(); |
|
1295 | 921 | switch ($this->generatorType) { |
|
1296 | 921 | case self::GENERATOR_TYPE_AUTO: |
|
1297 | 847 | $mapping['type'] = 'id'; |
|
1298 | 847 | break; |
|
1299 | default: |
||
1300 | 153 | if ( ! empty($this->generatorOptions['type'])) { |
|
1301 | 52 | $mapping['type'] = $this->generatorOptions['type']; |
|
1302 | 101 | } elseif (empty($mapping['type'])) { |
|
1303 | 86 | $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id'; |
|
1304 | } |
||
1305 | } |
||
1306 | 921 | unset($this->generatorOptions['type']); |
|
1307 | } |
||
1308 | |||
1309 | 949 | if ( ! isset($mapping['nullable'])) { |
|
1310 | 53 | $mapping['nullable'] = false; |
|
1311 | } |
||
1312 | |||
1313 | // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility |
||
1314 | 949 | if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) { |
|
1315 | 293 | $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID; |
|
1316 | 293 | @trigger_error('"simple" attribute of a reference is deprecated - use storeAs="id" instead.', E_USER_DEPRECATED); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
1317 | } |
||
1318 | // Provide the correct value for the "simple" field for backwards compatibility |
||
1319 | 949 | if (isset($mapping['storeAs'])) { |
|
1320 | 583 | $mapping['simple'] = $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID; |
|
1321 | } |
||
1322 | |||
1323 | 949 | if (isset($mapping['reference']) |
|
1324 | 596 | && isset($mapping['storeAs']) |
|
1325 | 583 | && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID |
|
1326 | 348 | && ! isset($mapping['targetDocument']) |
|
1327 | ) { |
||
1328 | 3 | throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']); |
|
1329 | } |
||
1330 | |||
1331 | 946 | if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) && |
|
1332 | 112 | (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) { |
|
1333 | 4 | throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']); |
|
1334 | } |
||
1335 | |||
1336 | 942 | if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) { |
|
1337 | 1 | throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']); |
|
1338 | } |
||
1339 | |||
1340 | 941 | View Code Duplication | if (isset($mapping['reference']) && $mapping['type'] === 'one') { |
1341 | 516 | $mapping['association'] = self::REFERENCE_ONE; |
|
1342 | } |
||
1343 | 941 | View Code Duplication | if (isset($mapping['reference']) && $mapping['type'] === 'many') { |
1344 | 460 | $mapping['association'] = self::REFERENCE_MANY; |
|
1345 | } |
||
1346 | 941 | View Code Duplication | if (isset($mapping['embedded']) && $mapping['type'] === 'one') { |
1347 | 462 | $mapping['association'] = self::EMBED_ONE; |
|
1348 | } |
||
1349 | 941 | View Code Duplication | if (isset($mapping['embedded']) && $mapping['type'] === 'many') { |
1350 | 505 | $mapping['association'] = self::EMBED_MANY; |
|
1351 | } |
||
1352 | |||
1353 | 941 | if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) { |
|
1354 | 133 | $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD; |
|
1355 | } |
||
1356 | |||
1357 | /* |
||
1358 | if (isset($mapping['type']) && ($mapping['type'] === 'one' || $mapping['type'] === 'many')) { |
||
1359 | $mapping['type'] = $mapping['type'] === 'one' ? self::ONE : self::MANY; |
||
1360 | } |
||
1361 | */ |
||
1362 | 941 | if (isset($mapping['version'])) { |
|
1363 | 100 | $mapping['notSaved'] = true; |
|
1364 | 100 | $this->setVersionMapping($mapping); |
|
1365 | } |
||
1366 | 941 | if (isset($mapping['lock'])) { |
|
1367 | 27 | $mapping['notSaved'] = true; |
|
1368 | 27 | $this->setLockMapping($mapping); |
|
1369 | } |
||
1370 | 941 | $mapping['isOwningSide'] = true; |
|
1371 | 941 | $mapping['isInverseSide'] = false; |
|
1372 | 941 | if (isset($mapping['reference'])) { |
|
1373 | 588 | View Code Duplication | if (isset($mapping['inversedBy']) && $mapping['inversedBy']) { |
1374 | 92 | $mapping['isOwningSide'] = true; |
|
1375 | 92 | $mapping['isInverseSide'] = false; |
|
1376 | } |
||
1377 | 588 | View Code Duplication | if (isset($mapping['mappedBy']) && $mapping['mappedBy']) { |
1378 | 295 | $mapping['isInverseSide'] = true; |
|
1379 | 295 | $mapping['isOwningSide'] = false; |
|
1380 | } |
||
1381 | 588 | View Code Duplication | if (isset($mapping['repositoryMethod'])) { |
1382 | 67 | $mapping['isInverseSide'] = true; |
|
1383 | 67 | $mapping['isOwningSide'] = false; |
|
1384 | } |
||
1385 | 588 | if (!isset($mapping['orphanRemoval'])) { |
|
1386 | 563 | $mapping['orphanRemoval'] = false; |
|
1387 | } |
||
1388 | } |
||
1389 | |||
1390 | 941 | if (!empty($mapping['prime']) && ($mapping['association'] !== self::REFERENCE_MANY || !$mapping['isInverseSide'])) { |
|
1391 | throw MappingException::referencePrimersOnlySupportedForInverseReferenceMany($this->name, $mapping['fieldName']); |
||
1392 | } |
||
1393 | |||
1394 | 941 | $this->applyStorageStrategy($mapping); |
|
1395 | |||
1396 | 940 | $this->fieldMappings[$mapping['fieldName']] = $mapping; |
|
1397 | 940 | if (isset($mapping['association'])) { |
|
1398 | 741 | $this->associationMappings[$mapping['fieldName']] = $mapping; |
|
1399 | } |
||
1400 | |||
1401 | 940 | return $mapping; |
|
1402 | } |
||
1403 | |||
1404 | /** |
||
1405 | * Validates the storage strategy of a mapping for consistency |
||
1406 | * @param array $mapping |
||
1407 | * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException |
||
1408 | */ |
||
1409 | 941 | private function applyStorageStrategy(array &$mapping) |
|
1410 | { |
||
1411 | 941 | if (! isset($mapping['type']) || isset($mapping['id'])) { |
|
1412 | 923 | return; |
|
1413 | } |
||
1414 | |||
1415 | switch (true) { |
||
1416 | 903 | case $mapping['type'] == 'int': |
|
1417 | 902 | case $mapping['type'] == 'float': |
|
1418 | 902 | case $mapping['type'] == 'increment': |
|
1419 | 334 | $defaultStrategy = self::STORAGE_STRATEGY_SET; |
|
1420 | 334 | $allowedStrategies = [self::STORAGE_STRATEGY_SET, self::STORAGE_STRATEGY_INCREMENT]; |
|
1421 | 334 | break; |
|
1422 | |||
1423 | 901 | case $mapping['type'] == 'many': |
|
1424 | 618 | $defaultStrategy = CollectionHelper::DEFAULT_STRATEGY; |
|
1425 | $allowedStrategies = [ |
||
1426 | 618 | self::STORAGE_STRATEGY_PUSH_ALL, |
|
1427 | 618 | self::STORAGE_STRATEGY_ADD_TO_SET, |
|
1428 | 618 | self::STORAGE_STRATEGY_SET, |
|
1429 | 618 | self::STORAGE_STRATEGY_SET_ARRAY, |
|
1430 | 618 | self::STORAGE_STRATEGY_ATOMIC_SET, |
|
1431 | 618 | self::STORAGE_STRATEGY_ATOMIC_SET_ARRAY, |
|
1432 | ]; |
||
1433 | 618 | break; |
|
1434 | |||
1435 | default: |
||
1436 | 889 | $defaultStrategy = self::STORAGE_STRATEGY_SET; |
|
1437 | 889 | $allowedStrategies = [self::STORAGE_STRATEGY_SET]; |
|
1438 | } |
||
1439 | |||
1440 | 903 | if (! isset($mapping['strategy'])) { |
|
1441 | 892 | $mapping['strategy'] = $defaultStrategy; |
|
1442 | } |
||
1443 | |||
1444 | 903 | if (! in_array($mapping['strategy'], $allowedStrategies)) { |
|
1445 | throw MappingException::invalidStorageStrategy($this->name, $mapping['fieldName'], $mapping['type'], $mapping['strategy']); |
||
1446 | } |
||
1447 | |||
1448 | 903 | if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide'] |
|
1449 | 453 | && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) { |
|
1450 | 1 | throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']); |
|
1451 | } |
||
1452 | 902 | } |
|
1453 | |||
1454 | /** |
||
1455 | * Map a MongoGridFSFile. |
||
1456 | * |
||
1457 | * @param array $mapping The mapping information. |
||
1458 | */ |
||
1459 | public function mapFile(array $mapping) |
||
1460 | { |
||
1461 | $mapping['file'] = true; |
||
1462 | $mapping['type'] = 'file'; |
||
1463 | $this->mapField($mapping); |
||
1464 | } |
||
1465 | |||
1466 | /** |
||
1467 | * Map a single embedded document. |
||
1468 | * |
||
1469 | * @param array $mapping The mapping information. |
||
1470 | */ |
||
1471 | 6 | public function mapOneEmbedded(array $mapping) |
|
1472 | { |
||
1473 | 6 | $mapping['embedded'] = true; |
|
1474 | 6 | $mapping['type'] = 'one'; |
|
1475 | 6 | $this->mapField($mapping); |
|
1476 | 5 | } |
|
1477 | |||
1478 | /** |
||
1479 | * Map a collection of embedded documents. |
||
1480 | * |
||
1481 | * @param array $mapping The mapping information. |
||
1482 | */ |
||
1483 | 5 | public function mapManyEmbedded(array $mapping) |
|
1484 | { |
||
1485 | 5 | $mapping['embedded'] = true; |
|
1486 | 5 | $mapping['type'] = 'many'; |
|
1487 | 5 | $this->mapField($mapping); |
|
1488 | 5 | } |
|
1489 | |||
1490 | /** |
||
1491 | * Map a single document reference. |
||
1492 | * |
||
1493 | * @param array $mapping The mapping information. |
||
1494 | */ |
||
1495 | 8 | public function mapOneReference(array $mapping) |
|
1496 | { |
||
1497 | 8 | $mapping['reference'] = true; |
|
1498 | 8 | $mapping['type'] = 'one'; |
|
1499 | 8 | $this->mapField($mapping); |
|
1500 | 8 | } |
|
1501 | |||
1502 | /** |
||
1503 | * Map a collection of document references. |
||
1504 | * |
||
1505 | * @param array $mapping The mapping information. |
||
1506 | */ |
||
1507 | 8 | public function mapManyReference(array $mapping) |
|
1508 | { |
||
1509 | 8 | $mapping['reference'] = true; |
|
1510 | 8 | $mapping['type'] = 'many'; |
|
1511 | 8 | $this->mapField($mapping); |
|
1512 | 8 | } |
|
1513 | |||
1514 | /** |
||
1515 | * INTERNAL: |
||
1516 | * Adds a field mapping without completing/validating it. |
||
1517 | * This is mainly used to add inherited field mappings to derived classes. |
||
1518 | * |
||
1519 | * @param array $fieldMapping |
||
1520 | */ |
||
1521 | 129 | public function addInheritedFieldMapping(array $fieldMapping) |
|
1522 | { |
||
1523 | 129 | $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping; |
|
1524 | |||
1525 | 129 | if (isset($fieldMapping['association'])) { |
|
1526 | 77 | $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping; |
|
1527 | } |
||
1528 | 129 | } |
|
1529 | |||
1530 | /** |
||
1531 | * INTERNAL: |
||
1532 | * Adds an association mapping without completing/validating it. |
||
1533 | * This is mainly used to add inherited association mappings to derived classes. |
||
1534 | * |
||
1535 | * @param array $mapping |
||
1536 | * |
||
1537 | * @return void |
||
1538 | * |
||
1539 | * @throws MappingException |
||
1540 | */ |
||
1541 | 78 | public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/) |
|
1542 | { |
||
1543 | 78 | $this->associationMappings[$mapping['fieldName']] = $mapping; |
|
1544 | 78 | } |
|
1545 | |||
1546 | /** |
||
1547 | * Checks whether the class has a mapped association with the given field name. |
||
1548 | * |
||
1549 | * @param string $fieldName |
||
1550 | * @return boolean |
||
1551 | */ |
||
1552 | 14 | public function hasReference($fieldName) |
|
1553 | { |
||
1554 | 14 | return isset($this->fieldMappings[$fieldName]['reference']); |
|
1555 | } |
||
1556 | |||
1557 | /** |
||
1558 | * Checks whether the class has a mapped embed with the given field name. |
||
1559 | * |
||
1560 | * @param string $fieldName |
||
1561 | * @return boolean |
||
1562 | */ |
||
1563 | 5 | public function hasEmbed($fieldName) |
|
1564 | { |
||
1565 | 5 | return isset($this->fieldMappings[$fieldName]['embedded']); |
|
1566 | } |
||
1567 | |||
1568 | /** |
||
1569 | * {@inheritDoc} |
||
1570 | * |
||
1571 | * Checks whether the class has a mapped association (embed or reference) with the given field name. |
||
1572 | */ |
||
1573 | 7 | public function hasAssociation($fieldName) |
|
1574 | { |
||
1575 | 7 | return $this->hasReference($fieldName) || $this->hasEmbed($fieldName); |
|
1576 | } |
||
1577 | |||
1578 | /** |
||
1579 | * {@inheritDoc} |
||
1580 | * |
||
1581 | * Checks whether the class has a mapped reference or embed for the specified field and |
||
1582 | * is a single valued association. |
||
1583 | */ |
||
1584 | public function isSingleValuedAssociation($fieldName) |
||
1585 | { |
||
1586 | return $this->isSingleValuedReference($fieldName) || $this->isSingleValuedEmbed($fieldName); |
||
1587 | } |
||
1588 | |||
1589 | /** |
||
1590 | * {@inheritDoc} |
||
1591 | * |
||
1592 | * Checks whether the class has a mapped reference or embed for the specified field and |
||
1593 | * is a collection valued association. |
||
1594 | */ |
||
1595 | public function isCollectionValuedAssociation($fieldName) |
||
1596 | { |
||
1597 | return $this->isCollectionValuedReference($fieldName) || $this->isCollectionValuedEmbed($fieldName); |
||
1598 | } |
||
1599 | |||
1600 | /** |
||
1601 | * Checks whether the class has a mapped association for the specified field |
||
1602 | * and if yes, checks whether it is a single-valued association (to-one). |
||
1603 | * |
||
1604 | * @param string $fieldName |
||
1605 | * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise. |
||
1606 | */ |
||
1607 | public function isSingleValuedReference($fieldName) |
||
1608 | { |
||
1609 | return isset($this->fieldMappings[$fieldName]['association']) && |
||
1610 | $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_ONE; |
||
1611 | } |
||
1612 | |||
1613 | /** |
||
1614 | * Checks whether the class has a mapped association for the specified field |
||
1615 | * and if yes, checks whether it is a collection-valued association (to-many). |
||
1616 | * |
||
1617 | * @param string $fieldName |
||
1618 | * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise. |
||
1619 | */ |
||
1620 | public function isCollectionValuedReference($fieldName) |
||
1621 | { |
||
1622 | return isset($this->fieldMappings[$fieldName]['association']) && |
||
1623 | $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_MANY; |
||
1624 | } |
||
1625 | |||
1626 | /** |
||
1627 | * Checks whether the class has a mapped embedded document for the specified field |
||
1628 | * and if yes, checks whether it is a single-valued association (to-one). |
||
1629 | * |
||
1630 | * @param string $fieldName |
||
1631 | * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise. |
||
1632 | */ |
||
1633 | public function isSingleValuedEmbed($fieldName) |
||
1634 | { |
||
1635 | return isset($this->fieldMappings[$fieldName]['association']) && |
||
1636 | $this->fieldMappings[$fieldName]['association'] === self::EMBED_ONE; |
||
1637 | } |
||
1638 | |||
1639 | /** |
||
1640 | * Checks whether the class has a mapped embedded document for the specified field |
||
1641 | * and if yes, checks whether it is a collection-valued association (to-many). |
||
1642 | * |
||
1643 | * @param string $fieldName |
||
1644 | * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise. |
||
1645 | */ |
||
1646 | public function isCollectionValuedEmbed($fieldName) |
||
1647 | { |
||
1648 | return isset($this->fieldMappings[$fieldName]['association']) && |
||
1649 | $this->fieldMappings[$fieldName]['association'] === self::EMBED_MANY; |
||
1650 | } |
||
1651 | |||
1652 | /** |
||
1653 | * Sets the ID generator used to generate IDs for instances of this class. |
||
1654 | * |
||
1655 | * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator |
||
1656 | */ |
||
1657 | 842 | public function setIdGenerator($generator) |
|
1658 | { |
||
1659 | 842 | $this->idGenerator = $generator; |
|
1660 | 842 | } |
|
1661 | |||
1662 | /** |
||
1663 | * Casts the identifier to its portable PHP type. |
||
1664 | * |
||
1665 | * @param mixed $id |
||
1666 | * @return mixed $id |
||
1667 | */ |
||
1668 | 647 | public function getPHPIdentifierValue($id) |
|
1669 | { |
||
1670 | 647 | $idType = $this->fieldMappings[$this->identifier]['type']; |
|
1671 | 647 | return Type::getType($idType)->convertToPHPValue($id); |
|
1672 | } |
||
1673 | |||
1674 | /** |
||
1675 | * Casts the identifier to its database type. |
||
1676 | * |
||
1677 | * @param mixed $id |
||
1678 | * @return mixed $id |
||
1679 | */ |
||
1680 | 714 | public function getDatabaseIdentifierValue($id) |
|
1681 | { |
||
1682 | 714 | $idType = $this->fieldMappings[$this->identifier]['type']; |
|
1683 | 714 | return Type::getType($idType)->convertToDatabaseValue($id); |
|
1684 | } |
||
1685 | |||
1686 | /** |
||
1687 | * Sets the document identifier of a document. |
||
1688 | * |
||
1689 | * The value will be converted to a PHP type before being set. |
||
1690 | * |
||
1691 | * @param object $document |
||
1692 | * @param mixed $id |
||
1693 | */ |
||
1694 | 576 | public function setIdentifierValue($document, $id) |
|
1695 | { |
||
1696 | 576 | $id = $this->getPHPIdentifierValue($id); |
|
1697 | 576 | $this->reflFields[$this->identifier]->setValue($document, $id); |
|
1698 | 576 | } |
|
1699 | |||
1700 | /** |
||
1701 | * Gets the document identifier as a PHP type. |
||
1702 | * |
||
1703 | * @param object $document |
||
1704 | * @return mixed $id |
||
1705 | */ |
||
1706 | 665 | public function getIdentifierValue($document) |
|
1707 | { |
||
1708 | 665 | return $this->reflFields[$this->identifier]->getValue($document); |
|
1709 | } |
||
1710 | |||
1711 | /** |
||
1712 | * {@inheritDoc} |
||
1713 | * |
||
1714 | * Since MongoDB only allows exactly one identifier field this is a proxy |
||
1715 | * to {@see getIdentifierValue()} and returns an array with the identifier |
||
1716 | * field as a key. |
||
1717 | */ |
||
1718 | public function getIdentifierValues($object) |
||
1719 | { |
||
1720 | return array($this->identifier => $this->getIdentifierValue($object)); |
||
1721 | } |
||
1722 | |||
1723 | /** |
||
1724 | * Get the document identifier object as a database type. |
||
1725 | * |
||
1726 | * @param object $document |
||
1727 | * |
||
1728 | * @return \MongoId $id The MongoID object. |
||
1729 | */ |
||
1730 | 36 | public function getIdentifierObject($document) |
|
1731 | { |
||
1732 | 36 | return $this->getDatabaseIdentifierValue($this->getIdentifierValue($document)); |
|
1733 | } |
||
1734 | |||
1735 | /** |
||
1736 | * Sets the specified field to the specified value on the given document. |
||
1737 | * |
||
1738 | * @param object $document |
||
1739 | * @param string $field |
||
1740 | * @param mixed $value |
||
1741 | */ |
||
1742 | 11 | public function setFieldValue($document, $field, $value) |
|
1743 | { |
||
1744 | 11 | if ($document instanceof Proxy && ! $document->__isInitialized()) { |
|
1745 | //property changes to an uninitialized proxy will not be tracked or persisted, |
||
1746 | //so the proxy needs to be loaded first. |
||
1747 | 1 | $document->__load(); |
|
1748 | } |
||
1749 | |||
1750 | 11 | $this->reflFields[$field]->setValue($document, $value); |
|
1751 | 11 | } |
|
1752 | |||
1753 | /** |
||
1754 | * Gets the specified field's value off the given document. |
||
1755 | * |
||
1756 | * @param object $document |
||
1757 | * @param string $field |
||
1758 | * |
||
1759 | * @return mixed |
||
1760 | */ |
||
1761 | 31 | public function getFieldValue($document, $field) |
|
1762 | { |
||
1763 | 31 | if ($document instanceof Proxy && $field !== $this->identifier && ! $document->__isInitialized()) { |
|
1764 | 1 | $document->__load(); |
|
1765 | } |
||
1766 | |||
1767 | 31 | return $this->reflFields[$field]->getValue($document); |
|
1768 | } |
||
1769 | |||
1770 | /** |
||
1771 | * Gets the mapping of a field. |
||
1772 | * |
||
1773 | * @param string $fieldName The field name. |
||
1774 | * |
||
1775 | * @return array The field mapping. |
||
1776 | * |
||
1777 | * @throws MappingException if the $fieldName is not found in the fieldMappings array |
||
1778 | */ |
||
1779 | 102 | public function getFieldMapping($fieldName) |
|
1780 | { |
||
1781 | 102 | if ( ! isset($this->fieldMappings[$fieldName])) { |
|
1782 | 6 | throw MappingException::mappingNotFound($this->name, $fieldName); |
|
1783 | } |
||
1784 | 100 | return $this->fieldMappings[$fieldName]; |
|
1785 | } |
||
1786 | |||
1787 | /** |
||
1788 | * Gets mappings of fields holding embedded document(s). |
||
1789 | * |
||
1790 | * @return array of field mappings |
||
1791 | */ |
||
1792 | 616 | public function getEmbeddedFieldsMappings() |
|
1793 | { |
||
1794 | 616 | return array_filter( |
|
1795 | 616 | $this->associationMappings, |
|
1796 | function($assoc) { return ! empty($assoc['embedded']); } |
||
1797 | ); |
||
1798 | } |
||
1799 | |||
1800 | /** |
||
1801 | * Gets the field mapping by its DB name. |
||
1802 | * E.g. it returns identifier's mapping when called with _id. |
||
1803 | * |
||
1804 | * @param string $dbFieldName |
||
1805 | * |
||
1806 | * @return array |
||
1807 | * @throws MappingException |
||
1808 | */ |
||
1809 | 3 | public function getFieldMappingByDbFieldName($dbFieldName) |
|
1810 | { |
||
1811 | 3 | foreach ($this->fieldMappings as $mapping) { |
|
1812 | 3 | if ($mapping['name'] == $dbFieldName) { |
|
1813 | 3 | return $mapping; |
|
1814 | } |
||
1815 | } |
||
1816 | |||
1817 | throw MappingException::mappingNotFoundByDbName($this->name, $dbFieldName); |
||
1818 | } |
||
1819 | |||
1820 | /** |
||
1821 | * Check if the field is not null. |
||
1822 | * |
||
1823 | * @param string $fieldName The field name |
||
1824 | * |
||
1825 | * @return boolean TRUE if the field is not null, FALSE otherwise. |
||
1826 | */ |
||
1827 | 1 | public function isNullable($fieldName) |
|
1828 | { |
||
1829 | 1 | $mapping = $this->getFieldMapping($fieldName); |
|
1830 | 1 | if ($mapping !== false) { |
|
1831 | 1 | return isset($mapping['nullable']) && $mapping['nullable'] == true; |
|
1832 | } |
||
1833 | return false; |
||
1834 | } |
||
1835 | |||
1836 | /** |
||
1837 | * Checks whether the document has a discriminator field and value configured. |
||
1838 | * |
||
1839 | * @return boolean |
||
1840 | */ |
||
1841 | 531 | public function hasDiscriminator() |
|
1842 | { |
||
1843 | 531 | return isset($this->discriminatorField, $this->discriminatorValue); |
|
1844 | } |
||
1845 | |||
1846 | /** |
||
1847 | * Sets the type of Id generator to use for the mapped class. |
||
1848 | * |
||
1849 | * @param string $generatorType Generator type. |
||
1850 | */ |
||
1851 | 375 | public function setIdGeneratorType($generatorType) |
|
1852 | { |
||
1853 | 375 | $this->generatorType = $generatorType; |
|
1854 | 375 | } |
|
1855 | |||
1856 | /** |
||
1857 | * Sets the Id generator options. |
||
1858 | * |
||
1859 | * @param array $generatorOptions Generator options. |
||
1860 | */ |
||
1861 | public function setIdGeneratorOptions($generatorOptions) |
||
1862 | { |
||
1863 | $this->generatorOptions = $generatorOptions; |
||
1864 | } |
||
1865 | |||
1866 | /** |
||
1867 | * @return boolean |
||
1868 | */ |
||
1869 | 622 | public function isInheritanceTypeNone() |
|
1870 | { |
||
1871 | 622 | return $this->inheritanceType == self::INHERITANCE_TYPE_NONE; |
|
1872 | } |
||
1873 | |||
1874 | /** |
||
1875 | * Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy. |
||
1876 | * |
||
1877 | * @return boolean |
||
1878 | */ |
||
1879 | 368 | public function isInheritanceTypeSingleCollection() |
|
1880 | { |
||
1881 | 368 | return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_COLLECTION; |
|
1882 | } |
||
1883 | |||
1884 | /** |
||
1885 | * Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy. |
||
1886 | * |
||
1887 | * @return boolean |
||
1888 | */ |
||
1889 | public function isInheritanceTypeCollectionPerClass() |
||
1890 | { |
||
1891 | return $this->inheritanceType == self::INHERITANCE_TYPE_COLLECTION_PER_CLASS; |
||
1892 | } |
||
1893 | |||
1894 | /** |
||
1895 | * Sets the mapped subclasses of this class. |
||
1896 | * |
||
1897 | * @param string[] $subclasses The names of all mapped subclasses. |
||
1898 | */ |
||
1899 | 2 | public function setSubclasses(array $subclasses) |
|
1900 | { |
||
1901 | 2 | foreach ($subclasses as $subclass) { |
|
1902 | 2 | if (strpos($subclass, '\\') === false && strlen($this->namespace)) { |
|
1903 | 1 | $this->subClasses[] = $this->namespace . '\\' . $subclass; |
|
1904 | } else { |
||
1905 | 1 | $this->subClasses[] = $subclass; |
|
1906 | } |
||
1907 | } |
||
1908 | 2 | } |
|
1909 | |||
1910 | /** |
||
1911 | * Sets the parent class names. |
||
1912 | * Assumes that the class names in the passed array are in the order: |
||
1913 | * directParent -> directParentParent -> directParentParentParent ... -> root. |
||
1914 | * |
||
1915 | * @param string[] $classNames |
||
1916 | */ |
||
1917 | 900 | public function setParentClasses(array $classNames) |
|
1918 | { |
||
1919 | 900 | $this->parentClasses = $classNames; |
|
1920 | |||
1921 | 900 | if (count($classNames) > 0) { |
|
1922 | 113 | $this->rootDocumentName = array_pop($classNames); |
|
1923 | } |
||
1924 | 900 | } |
|
1925 | |||
1926 | /** |
||
1927 | * Checks whether the class will generate a new \MongoId instance for us. |
||
1928 | * |
||
1929 | * @return boolean TRUE if the class uses the AUTO generator, FALSE otherwise. |
||
1930 | */ |
||
1931 | public function isIdGeneratorAuto() |
||
1932 | { |
||
1933 | return $this->generatorType == self::GENERATOR_TYPE_AUTO; |
||
1934 | } |
||
1935 | |||
1936 | /** |
||
1937 | * Checks whether the class will use a collection to generate incremented identifiers. |
||
1938 | * |
||
1939 | * @return boolean TRUE if the class uses the INCREMENT generator, FALSE otherwise. |
||
1940 | */ |
||
1941 | public function isIdGeneratorIncrement() |
||
1942 | { |
||
1943 | return $this->generatorType == self::GENERATOR_TYPE_INCREMENT; |
||
1944 | } |
||
1945 | |||
1946 | /** |
||
1947 | * Checks whether the class will generate a uuid id. |
||
1948 | * |
||
1949 | * @return boolean TRUE if the class uses the UUID generator, FALSE otherwise. |
||
1950 | */ |
||
1951 | public function isIdGeneratorUuid() |
||
1952 | { |
||
1953 | return $this->generatorType == self::GENERATOR_TYPE_UUID; |
||
1954 | } |
||
1955 | |||
1956 | /** |
||
1957 | * Checks whether the class uses no id generator. |
||
1958 | * |
||
1959 | * @return boolean TRUE if the class does not use any id generator, FALSE otherwise. |
||
1960 | */ |
||
1961 | public function isIdGeneratorNone() |
||
1962 | { |
||
1963 | return $this->generatorType == self::GENERATOR_TYPE_NONE; |
||
1964 | } |
||
1965 | |||
1966 | /** |
||
1967 | * Sets the version field mapping used for versioning. Sets the default |
||
1968 | * value to use depending on the column type. |
||
1969 | * |
||
1970 | * @param array $mapping The version field mapping array |
||
1971 | * |
||
1972 | * @throws LockException |
||
1973 | */ |
||
1974 | 100 | public function setVersionMapping(array &$mapping) |
|
1975 | { |
||
1976 | 100 | if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') { |
|
1977 | 1 | throw LockException::invalidVersionFieldType($mapping['type']); |
|
1978 | } |
||
1979 | |||
1980 | 99 | $this->isVersioned = true; |
|
1981 | 99 | $this->versionField = $mapping['fieldName']; |
|
1982 | 99 | } |
|
1983 | |||
1984 | /** |
||
1985 | * Sets whether this class is to be versioned for optimistic locking. |
||
1986 | * |
||
1987 | * @param boolean $bool |
||
1988 | */ |
||
1989 | 369 | public function setVersioned($bool) |
|
1990 | { |
||
1991 | 369 | $this->isVersioned = $bool; |
|
1992 | 369 | } |
|
1993 | |||
1994 | /** |
||
1995 | * Sets the name of the field that is to be used for versioning if this class is |
||
1996 | * versioned for optimistic locking. |
||
1997 | * |
||
1998 | * @param string $versionField |
||
1999 | */ |
||
2000 | 369 | public function setVersionField($versionField) |
|
2001 | { |
||
2002 | 369 | $this->versionField = $versionField; |
|
2003 | 369 | } |
|
2004 | |||
2005 | /** |
||
2006 | * Sets the version field mapping used for versioning. Sets the default |
||
2007 | * value to use depending on the column type. |
||
2008 | * |
||
2009 | * @param array $mapping The version field mapping array |
||
2010 | * |
||
2011 | * @throws \Doctrine\ODM\MongoDB\LockException |
||
2012 | */ |
||
2013 | 27 | public function setLockMapping(array &$mapping) |
|
2014 | { |
||
2015 | 27 | if ($mapping['type'] !== 'int') { |
|
2016 | 1 | throw LockException::invalidLockFieldType($mapping['type']); |
|
2017 | } |
||
2018 | |||
2019 | 26 | $this->isLockable = true; |
|
2020 | 26 | $this->lockField = $mapping['fieldName']; |
|
2021 | 26 | } |
|
2022 | |||
2023 | /** |
||
2024 | * Sets whether this class is to allow pessimistic locking. |
||
2025 | * |
||
2026 | * @param boolean $bool |
||
2027 | */ |
||
2028 | public function setLockable($bool) |
||
2029 | { |
||
2030 | $this->isLockable = $bool; |
||
2031 | } |
||
2032 | |||
2033 | /** |
||
2034 | * Sets the name of the field that is to be used for storing whether a document |
||
2035 | * is currently locked or not. |
||
2036 | * |
||
2037 | * @param string $lockField |
||
2038 | */ |
||
2039 | public function setLockField($lockField) |
||
2040 | { |
||
2041 | $this->lockField = $lockField; |
||
2042 | } |
||
2043 | |||
2044 | /** |
||
2045 | * {@inheritDoc} |
||
2046 | */ |
||
2047 | public function getFieldNames() |
||
2048 | { |
||
2049 | return array_keys($this->fieldMappings); |
||
2050 | } |
||
2051 | |||
2052 | /** |
||
2053 | * {@inheritDoc} |
||
2054 | */ |
||
2055 | public function getAssociationNames() |
||
2056 | { |
||
2057 | return array_keys($this->associationMappings); |
||
2058 | } |
||
2059 | |||
2060 | /** |
||
2061 | * {@inheritDoc} |
||
2062 | */ |
||
2063 | 22 | public function getTypeOfField($fieldName) |
|
2064 | { |
||
2065 | 22 | return isset($this->fieldMappings[$fieldName]) ? |
|
2066 | 22 | $this->fieldMappings[$fieldName]['type'] : null; |
|
2067 | } |
||
2068 | |||
2069 | /** |
||
2070 | * {@inheritDoc} |
||
2071 | */ |
||
2072 | 6 | public function getAssociationTargetClass($assocName) |
|
2073 | { |
||
2074 | 6 | if ( ! isset($this->associationMappings[$assocName])) { |
|
2075 | 3 | throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association."); |
|
2076 | } |
||
2077 | |||
2078 | 3 | return $this->associationMappings[$assocName]['targetDocument']; |
|
2079 | } |
||
2080 | |||
2081 | /** |
||
2082 | * Retrieve the collectionClass associated with an association |
||
2083 | * |
||
2084 | * @param string $assocName |
||
2085 | */ |
||
2086 | 2 | public function getAssociationCollectionClass($assocName) |
|
2087 | { |
||
2088 | 2 | if ( ! isset($this->associationMappings[$assocName])) { |
|
2089 | throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association."); |
||
2090 | } |
||
2091 | |||
2092 | 2 | if ( ! array_key_exists('collectionClass', $this->associationMappings[$assocName])) { |
|
2093 | throw new InvalidArgumentException("collectionClass can only be applied to 'embedMany' and 'referenceMany' associations."); |
||
2094 | } |
||
2095 | |||
2096 | 2 | return $this->associationMappings[$assocName]['collectionClass']; |
|
2097 | } |
||
2098 | |||
2099 | /** |
||
2100 | * {@inheritDoc} |
||
2101 | */ |
||
2102 | public function isAssociationInverseSide($fieldName) |
||
2103 | { |
||
2104 | throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.'); |
||
2105 | } |
||
2106 | |||
2107 | /** |
||
2108 | * {@inheritDoc} |
||
2109 | */ |
||
2110 | public function getAssociationMappedByTargetField($fieldName) |
||
2111 | { |
||
2112 | throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.'); |
||
2113 | } |
||
2114 | } |
||
2115 |
If you suppress an error, we recommend checking for the error condition explicitly: