This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Doctrine\ODM\CouchDB\Mapping; |
||
4 | |||
5 | use Doctrine\Common\Persistence\Mapping\ClassMetadata AS IClassMetadata, |
||
6 | Doctrine\Instantiator\Instantiator, |
||
7 | ReflectionClass, |
||
8 | ReflectionProperty; |
||
9 | |||
10 | /** |
||
11 | * Metadata class |
||
12 | * |
||
13 | * @license http://www.opensource.org/licenses/lgpl-license.php LGPL |
||
14 | * @link www.doctrine-project.com |
||
15 | * @since 1.0 |
||
16 | * @author Benjamin Eberlei <[email protected]> |
||
17 | * @author Lukas Kahwe Smith <[email protected]> |
||
18 | */ |
||
19 | class ClassMetadata implements IClassMetadata |
||
20 | { |
||
21 | const IDGENERATOR_UUID = 1; |
||
22 | const IDGENERATOR_ASSIGNED = 2; |
||
23 | |||
24 | const TO_ONE = 5; |
||
25 | const TO_MANY = 10; |
||
26 | const ONE_TO_ONE = 1; |
||
27 | const ONE_TO_MANY = 2; |
||
28 | const MANY_TO_ONE = 4; |
||
29 | const MANY_TO_MANY = 8; |
||
30 | |||
31 | const CASCADE_PERSIST = 1; |
||
32 | const CASCADE_REMOVE = 2; |
||
33 | const CASCADE_MERGE = 4; |
||
34 | const CASCADE_DETACH = 8; |
||
35 | const CASCADE_REFRESH = 16; |
||
36 | const CASCADE_ALL = 31; |
||
37 | |||
38 | public $idGenerator = self::IDGENERATOR_UUID; |
||
39 | |||
40 | /** |
||
41 | * READ-ONLY: The field name of the document identifier. |
||
42 | */ |
||
43 | public $identifier; |
||
44 | |||
45 | /** |
||
46 | * READ-ONLY: The name of the document class. |
||
47 | */ |
||
48 | public $name; |
||
49 | |||
50 | /** |
||
51 | * READ-ONLY: The root document class name. |
||
52 | */ |
||
53 | public $rootDocumentName; |
||
54 | |||
55 | /** |
||
56 | * READ-ONLY: Is this entity in an inheritance hierachy? |
||
57 | */ |
||
58 | public $inInheritanceHierachy = false; |
||
59 | |||
60 | /** |
||
61 | * READ-ONLY: a list of all parent classes. |
||
62 | */ |
||
63 | public $parentClasses = array(); |
||
64 | |||
65 | /** |
||
66 | * READ-ONLY: The namespace the document class is contained in. |
||
67 | * |
||
68 | * @var string |
||
69 | * @todo Not really needed. Usage could be localized. |
||
70 | */ |
||
71 | public $namespace; |
||
72 | |||
73 | /** |
||
74 | * The name of the custom repository class used for the document class. |
||
75 | * (Optional). |
||
76 | * |
||
77 | * @var string |
||
78 | */ |
||
79 | public $customRepositoryClassName; |
||
80 | |||
81 | /** |
||
82 | * READ-ONLY: The field mappings of the class. |
||
83 | * Keys are field names and values are mapping definitions. |
||
84 | * |
||
85 | * The mapping definition array has the following values: |
||
86 | * |
||
87 | * - <b>fieldName</b> (string) |
||
88 | * The name of the field in the Document. |
||
89 | * |
||
90 | * - <b>id</b> (boolean, optional) |
||
91 | * Marks the field as the primary key of the document. Multiple fields of an |
||
92 | * document can have the id attribute, forming a composite key. |
||
93 | * |
||
94 | * @var array |
||
95 | */ |
||
96 | public $fieldMappings = array(); |
||
97 | |||
98 | /** |
||
99 | * An array of indexed fields, accessible through a generic view shipped with Doctrine. |
||
100 | * |
||
101 | * @var array |
||
102 | */ |
||
103 | public $indexes = array(); |
||
104 | |||
105 | /** |
||
106 | * Is this class indexed? If yes, then a findAll() query can be executed for this type. |
||
107 | * |
||
108 | * @var bool |
||
109 | */ |
||
110 | public $indexed = false; |
||
111 | |||
112 | /** |
||
113 | * An array of json result-key-names to field-names |
||
114 | * |
||
115 | * @var array |
||
116 | */ |
||
117 | public $jsonNames = array(); |
||
118 | |||
119 | /** |
||
120 | * READ-ONLY: Array of fields to also load with a given method. |
||
121 | * |
||
122 | * @var array |
||
123 | */ |
||
124 | public $alsoLoadMethods = array(); |
||
125 | |||
126 | /** |
||
127 | * READ-ONLY: Whether this class describes the mapping of a mapped superclass. |
||
128 | * |
||
129 | * @var boolean |
||
130 | */ |
||
131 | public $isMappedSuperclass = false; |
||
132 | |||
133 | /** |
||
134 | * READ-ONLY: Whether this class describes the mapping of a embedded document. |
||
135 | * |
||
136 | * @var boolean |
||
137 | */ |
||
138 | public $isEmbeddedDocument = false; |
||
139 | |||
140 | /** |
||
141 | * READ-ONLY: Wheather the document or embedded document is read-only and will be skipped in change-tracking. |
||
142 | * |
||
143 | * This should be set to true for value objects, for example attachments. Replacing the reference with a new |
||
144 | * value object will trigger an update. |
||
145 | * |
||
146 | * @var bool |
||
147 | */ |
||
148 | public $isReadOnly = false; |
||
149 | |||
150 | /** |
||
151 | * READ-ONLY |
||
152 | * |
||
153 | * @var array |
||
154 | */ |
||
155 | public $associationsMappings = array(); |
||
156 | |||
157 | /** |
||
158 | * CouchDB documents are always versioned, this flag determines if this version is exposed to the userland. |
||
159 | * |
||
160 | * @var bool |
||
161 | */ |
||
162 | public $isVersioned = false; |
||
163 | |||
164 | /** |
||
165 | * Version Field stores the CouchDB Revision |
||
166 | * |
||
167 | * @var string |
||
168 | */ |
||
169 | public $versionField = null; |
||
170 | |||
171 | /** |
||
172 | * @var bool |
||
173 | */ |
||
174 | public $hasAttachments = false; |
||
175 | |||
176 | /** |
||
177 | * Field that stores the attachments as a key->value array of file-names to attachment objects. |
||
178 | * |
||
179 | * @var string |
||
180 | */ |
||
181 | public $attachmentField = null; |
||
182 | |||
183 | /** |
||
184 | * If in an inheritance scenario the attachment field is on a super class, this is its name. |
||
185 | * |
||
186 | * @var string|null |
||
187 | */ |
||
188 | public $attachmentDeclaredClass = null; |
||
189 | |||
190 | /** |
||
191 | * The ReflectionClass instance of the mapped class. |
||
192 | * |
||
193 | * @var ReflectionClass |
||
194 | */ |
||
195 | public $reflClass; |
||
196 | |||
197 | /** |
||
198 | * The ReflectionProperty instances of the mapped class. |
||
199 | * |
||
200 | * @var array |
||
201 | */ |
||
202 | public $reflFields = array(); |
||
203 | |||
204 | /** |
||
205 | * @var \Doctrine\Instantiator\InstantiatorInterface |
||
206 | */ |
||
207 | private $instantiator; |
||
208 | |||
209 | /** |
||
210 | * Initializes a new ClassMetadata instance that will hold the object-document mapping |
||
211 | * metadata of the class with the given name. |
||
212 | * |
||
213 | * @param string $documentName The name of the document class the new instance is used for. |
||
214 | */ |
||
215 | public function __construct($documentName) |
||
216 | { |
||
217 | $this->name = $documentName; |
||
218 | $this->rootDocumentName = $documentName; |
||
219 | $this->instantiator = new Instantiator(); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Used to derive a class metadata of the current instance for a mapped child class. |
||
224 | * |
||
225 | * @param ClassMetadata $child |
||
226 | * @throws \InvalidArgumentException |
||
227 | */ |
||
228 | public function deriveChildMetadata($child) |
||
229 | { |
||
230 | if (!is_subclass_of($child->name, $this->name)) { |
||
231 | throw new \InvalidArgumentException("Only child class names of '".$this->name."' are valid values."); |
||
232 | } |
||
233 | |||
234 | $child->isMappedSuperclass = false; |
||
235 | $child->isEmbeddedDocument = false; |
||
236 | |||
237 | foreach ($this->fieldMappings AS $fieldName => $fieldMapping) { |
||
238 | $child->fieldMappings[$fieldName] = $fieldMapping; |
||
239 | |||
240 | if (!isset($fieldMapping['declared'])) { |
||
241 | $child->fieldMappings[$fieldName]['declared'] = $this->name; |
||
242 | } |
||
243 | } |
||
244 | |||
245 | foreach ($this->associationsMappings AS $assocName => $assocMapping) { |
||
246 | $child->associationsMappings[$assocName] = $assocMapping; |
||
247 | |||
248 | if (!isset($assocMapping['declared'])) { |
||
249 | $child->associationsMappings[$assocName]['declared'] = $this->name; |
||
250 | } |
||
251 | } |
||
252 | |||
253 | if ($this->attachmentField) { |
||
254 | $child->attachmentField = $this->attachmentField; |
||
255 | |||
256 | if (!$child->attachmentDeclaredClass) { |
||
0 ignored issues
–
show
|
|||
257 | $child->attachmentDeclaredClass = $this->name; |
||
258 | } |
||
259 | } |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * Determines which fields get serialized. |
||
264 | * |
||
265 | * It is only serialized what is necessary for best unserialization performance. |
||
266 | * That means any metadata properties that are not set or empty or simply have |
||
267 | * their default value are NOT serialized. |
||
268 | * |
||
269 | * Parts that are also NOT serialized because they can not be properly unserialized: |
||
270 | * - reflClass (ReflectionClass) |
||
271 | * - reflFields (ReflectionProperty array) |
||
272 | * |
||
273 | * @return array The names of all the fields that should be serialized. |
||
274 | */ |
||
275 | public function __sleep() |
||
276 | { |
||
277 | // This metadata is always serialized/cached. |
||
278 | $serialized = array( |
||
279 | 'name', |
||
280 | 'associationsMappings', |
||
281 | 'fieldMappings', |
||
282 | 'jsonNames', |
||
283 | 'idGenerator', |
||
284 | 'identifier', |
||
285 | 'rootDocumentName', |
||
286 | ); |
||
287 | |||
288 | if ($this->inInheritanceHierachy) { |
||
289 | $serialized[] = 'inInheritanceHierachy'; |
||
290 | } |
||
291 | |||
292 | if ($this->parentClasses) { |
||
0 ignored issues
–
show
The expression
$this->parentClasses of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
293 | $serialized[] = 'parentClasses'; |
||
294 | } |
||
295 | |||
296 | if ($this->isVersioned) { |
||
297 | $serialized[] = 'isVersioned'; |
||
298 | $serialized[] = 'versionField'; |
||
299 | } |
||
300 | |||
301 | if ($this->customRepositoryClassName) { |
||
302 | $serialized[] = 'customRepositoryClassName'; |
||
303 | } |
||
304 | |||
305 | if ($this->hasAttachments) { |
||
306 | $serialized[] = 'hasAttachments'; |
||
307 | $serialized[] = 'attachmentField'; |
||
308 | if ($this->attachmentDeclaredClass) { |
||
0 ignored issues
–
show
The expression
$this->attachmentDeclaredClass of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
309 | $serialized[] = 'attachmentDeclaredClass'; |
||
310 | } |
||
311 | } |
||
312 | |||
313 | if ($this->isReadOnly) { |
||
314 | $serialized[] = 'isReadOnly'; |
||
315 | } |
||
316 | |||
317 | if ($this->isMappedSuperclass) { |
||
318 | $serialized[] = 'isMappedSuperclass'; |
||
319 | } |
||
320 | |||
321 | if ($this->indexed) { |
||
322 | $serialized[] = 'indexed'; |
||
323 | } |
||
324 | if ($this->indexes) { |
||
0 ignored issues
–
show
The expression
$this->indexes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
325 | $serialized[] = 'indexes'; |
||
326 | } |
||
327 | |||
328 | return $serialized; |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * Restores some state that can not be serialized/unserialized. |
||
333 | */ |
||
334 | public function wakeupReflection($reflService) |
||
335 | { |
||
336 | // Restore ReflectionClass and properties |
||
337 | $this->reflClass = $reflService->getClass($this->name); |
||
338 | $this->namespace = $reflService->getClassNamespace($this->name); |
||
339 | $this->instantiator = $this->instantiator ?: new Instantiator(); |
||
340 | |||
341 | View Code Duplication | foreach ($this->fieldMappings as $field => $mapping) { |
|
342 | if (isset($mapping['declared'])) { |
||
343 | $reflField = new \ReflectionProperty($mapping['declared'], $field); |
||
344 | } else { |
||
345 | $reflField = $this->reflClass->getProperty($field); |
||
346 | } |
||
347 | $reflField->setAccessible(true); |
||
348 | $this->reflFields[$field] = $reflField; |
||
349 | } |
||
350 | |||
351 | View Code Duplication | foreach ($this->associationsMappings as $field => $mapping) { |
|
352 | if (isset($mapping['declared'])) { |
||
353 | $reflField = new \ReflectionProperty($mapping['declared'], $field); |
||
354 | } else { |
||
355 | $reflField = $this->reflClass->getProperty($field); |
||
356 | } |
||
357 | |||
358 | $reflField->setAccessible(true); |
||
359 | $this->reflFields[$field] = $reflField; |
||
360 | } |
||
361 | |||
362 | if ($this->hasAttachments) { |
||
363 | if ($this->attachmentDeclaredClass) { |
||
0 ignored issues
–
show
The expression
$this->attachmentDeclaredClass of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
364 | $reflField = new \ReflectionProperty($this->attachmentDeclaredClass, $this->attachmentField); |
||
365 | } else { |
||
366 | $reflField = $this->reflClass->getProperty($this->attachmentField); |
||
367 | } |
||
368 | $reflField->setAccessible(true); |
||
369 | $this->reflFields[$this->attachmentField] = $reflField; |
||
370 | } |
||
371 | } |
||
372 | |||
373 | /** |
||
374 | * Creates a new instance of the mapped class, without invoking the constructor. |
||
375 | * |
||
376 | * @return object |
||
377 | */ |
||
378 | public function newInstance() |
||
379 | { |
||
380 | return $this->instantiator->instantiate($this->name); |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * Gets the ReflectionClass instance of the mapped class. |
||
385 | * |
||
386 | * @return ReflectionClass |
||
387 | */ |
||
388 | public function getReflectionClass() |
||
389 | { |
||
390 | if ( ! $this->reflClass) { |
||
391 | $this->reflClass = new ReflectionClass($this->name); |
||
392 | } |
||
393 | return $this->reflClass; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * Gets the ReflectionPropertys of the mapped class. |
||
398 | * |
||
399 | * @return array An array of ReflectionProperty instances. |
||
400 | */ |
||
401 | public function getReflectionProperties() |
||
402 | { |
||
403 | return $this->reflFields; |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * Gets a ReflectionProperty for a specific field of the mapped class. |
||
408 | * |
||
409 | * @param string $name |
||
410 | * @return ReflectionProperty |
||
411 | */ |
||
412 | public function getReflectionProperty($name) |
||
413 | { |
||
414 | return $this->reflFields[$name]; |
||
415 | } |
||
416 | |||
417 | |||
418 | /** |
||
419 | * Sets the document identifier of a document. |
||
420 | * |
||
421 | * @param object $document |
||
422 | * @param mixed $id |
||
423 | */ |
||
424 | public function setIdentifierValue($document, $id) |
||
425 | { |
||
426 | $this->reflFields[$this->identifier]->setValue($document, $id); |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Gets the document identifier. |
||
431 | * |
||
432 | * @param object $document |
||
433 | * @return string $id |
||
434 | */ |
||
435 | public function getIdentifierValue($document) |
||
436 | { |
||
437 | return (string) $this->reflFields[$this->identifier]->getValue($document); |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Get identifier values of this document. |
||
442 | * |
||
443 | * Since CouchDB only allows exactly one identifier field this is a proxy |
||
444 | * to {@see getIdentifierValue()} and returns an array with the identifier |
||
445 | * field as a key. |
||
446 | * |
||
447 | * @param object $document |
||
448 | * @return array |
||
449 | */ |
||
450 | public function getIdentifierValues($document) |
||
451 | { |
||
452 | return array($this->identifier => $this->getIdentifierValue($document)); |
||
0 ignored issues
–
show
The return type of
return array($this->iden...ifierValue($document)); (array<string,string> ) is incompatible with the return type declared by the interface Doctrine\Common\Persiste...ta::getIdentifierValues of type array .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
453 | } |
||
454 | |||
455 | /** |
||
456 | * Sets the specified field to the specified value on the given document. |
||
457 | * |
||
458 | * @param object $document |
||
459 | * @param string $field |
||
460 | * @param mixed $value |
||
461 | */ |
||
462 | public function setFieldValue($document, $field, $value) |
||
463 | { |
||
464 | $this->reflFields[$field]->setValue($document, $value); |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * Gets the specified field's value off the given document. |
||
469 | * |
||
470 | * @param object $document |
||
471 | * @param string $field |
||
472 | */ |
||
473 | public function getFieldValue($document, $field) |
||
474 | { |
||
475 | return $this->reflFields[$field]->getValue($document); |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Checks whether a field is part of the identifier/primary key field(s). |
||
480 | * |
||
481 | * @param string $fieldName The field name |
||
482 | * @return boolean TRUE if the field is part of the table identifier/primary key field(s), |
||
483 | * FALSE otherwise. |
||
484 | */ |
||
485 | public function isIdentifier($fieldName) |
||
486 | { |
||
487 | return $this->identifier === $fieldName ? true : false; |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * INTERNAL: |
||
492 | * Sets the mapped identifier field of this class. |
||
493 | * |
||
494 | * @param string $identifier |
||
495 | * @throws MappingException |
||
496 | */ |
||
497 | public function setIdentifier($identifier) |
||
498 | { |
||
499 | if ($this->isEmbeddedDocument) { |
||
500 | throw new MappingException('EmbeddedDocument should not have id field'); |
||
501 | } |
||
502 | $this->identifier = $identifier; |
||
503 | } |
||
504 | |||
505 | /** |
||
506 | * Gets the mapped identifier field of this class. |
||
507 | * |
||
508 | * @return string $identifier |
||
509 | */ |
||
510 | public function getIdentifier() |
||
511 | { |
||
512 | return $this->identifier; |
||
0 ignored issues
–
show
The return type of
return $this->identifier; (string ) is incompatible with the return type declared by the interface Doctrine\Common\Persiste...Metadata::getIdentifier of type array .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
513 | } |
||
514 | |||
515 | /** |
||
516 | * Get identifier field names of this class.; |
||
517 | * |
||
518 | * Since CouchDB only allows exactly one identifier field this is a proxy |
||
519 | * to {@see getIdentifier()} and returns an array. |
||
520 | * |
||
521 | * @return array |
||
522 | */ |
||
523 | public function getIdentifierFieldNames() |
||
524 | { |
||
525 | return array($this->identifier); |
||
526 | } |
||
527 | |||
528 | /** |
||
529 | * Checks whether the class has a (mapped) field with a certain name. |
||
530 | * |
||
531 | * @param $fieldName |
||
532 | * @return boolean |
||
533 | */ |
||
534 | public function hasField($fieldName) |
||
535 | { |
||
536 | return isset($this->fieldMappings[$fieldName]); |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * Registers a custom repository class for the document class. |
||
541 | * |
||
542 | * @param string $repositoryClassName The class name of the custom mapper. |
||
543 | */ |
||
544 | public function setCustomRepositoryClass($repositoryClassName) |
||
545 | { |
||
546 | $this->customRepositoryClassName = $repositoryClassName; |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * The name of this Document class. |
||
551 | * |
||
552 | * @return string $name The Document class name. |
||
553 | */ |
||
554 | public function getName() |
||
555 | { |
||
556 | return $this->name; |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * The namespace this Document class belongs to. |
||
561 | * |
||
562 | * @return string $namespace The namespace name. |
||
563 | */ |
||
564 | public function getNamespace() |
||
565 | { |
||
566 | return $this->namespace; |
||
567 | } |
||
568 | |||
569 | /** |
||
570 | * Set the field that will contain attachments of this document. |
||
571 | * |
||
572 | * @param string $fieldName |
||
573 | * @throws MappingException |
||
574 | */ |
||
575 | public function mapAttachments($fieldName) |
||
576 | { |
||
577 | if (isset($this->fieldMappings[$fieldName]) || isset($this->associationsMappings[$fieldName])) { |
||
578 | throw MappingException::duplicateFieldMapping($this->name, $fieldName); |
||
579 | } |
||
580 | |||
581 | $this->hasAttachments = true; |
||
582 | $this->attachmentField = $fieldName; |
||
583 | } |
||
584 | |||
585 | /** |
||
586 | * Map an embedded object |
||
587 | * |
||
588 | * - fieldName - The name of the property/field on the mapped php class |
||
589 | * - jsonName - JSON key name of this field in CouchDB. |
||
590 | * - targetDocument - Name of the target document |
||
591 | * - embedded - one or many embedded objects? |
||
592 | * |
||
593 | * @param array $mapping |
||
594 | */ |
||
595 | public function mapEmbedded(array $mapping) |
||
596 | { |
||
597 | $mapping = $this->validateAndCompleteReferenceMapping($mapping); |
||
598 | |||
599 | $this->mapField($mapping); |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Map a field. |
||
604 | * |
||
605 | * - type - The Doctrine Type of this field. |
||
606 | * - fieldName - The name of the property/field on the mapped php class |
||
607 | * - jsonName - JSON key name of this field in CouchDB. |
||
608 | * - name - The JSON key of this field in the CouchDB document |
||
609 | * - id - True for an ID field. |
||
610 | * - strategy - ID Generator strategy when the field is an id-field. |
||
611 | * - indexed - Is this field indexed for the Doctrine CouchDB repository view |
||
612 | * - isVersionField - Is this field containing the revision number of this document? |
||
613 | * |
||
614 | * @param array $mapping The mapping information. |
||
615 | */ |
||
616 | public function mapField(array $mapping) |
||
617 | { |
||
618 | $mapping = $this->validateAndCompleteFieldMapping($mapping); |
||
619 | |||
620 | if (!isset($mapping['type'])) { |
||
621 | $mapping['type'] = "mixed"; |
||
622 | } |
||
623 | |||
624 | if (isset($mapping['id']) && $mapping['id'] === true) { |
||
625 | $mapping['type'] = 'string'; |
||
626 | $mapping['jsonName'] = '_id'; |
||
627 | $this->setIdentifier($mapping['fieldName']); |
||
628 | if (isset($mapping['strategy'])) { |
||
629 | $this->idGenerator = constant('Doctrine\ODM\CouchDB\Mapping\ClassMetadata::IDGENERATOR_' . strtoupper($mapping['strategy'])); |
||
630 | unset($mapping['strategy']); |
||
631 | } |
||
632 | } else if (isset($mapping['isVersionField'])) { |
||
633 | $this->isVersioned = true; |
||
634 | $this->versionField = $mapping['fieldName']; |
||
635 | } |
||
636 | |||
637 | $mapping = $this->checkAndStoreIndexMapping($mapping); |
||
638 | |||
639 | $this->fieldMappings[$mapping['fieldName']] = $mapping; |
||
640 | $this->jsonNames[$mapping['jsonName']] = $mapping['fieldName']; |
||
641 | } |
||
642 | |||
643 | protected function validateAndCompleteFieldMapping($mapping) |
||
644 | { |
||
645 | if ( ! isset($mapping['fieldName']) || !$mapping['fieldName']) { |
||
646 | throw new MappingException("Mapping a property requires to specify the name."); |
||
647 | } |
||
648 | if ( ! isset($mapping['jsonName'])) { |
||
649 | $mapping['jsonName'] = $mapping['fieldName']; |
||
650 | } |
||
651 | if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationsMappings[$mapping['fieldName']])) { |
||
652 | throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']); |
||
653 | } |
||
654 | |||
655 | return $mapping; |
||
656 | } |
||
657 | |||
658 | protected function validateAndCompleteReferenceMapping($mapping) |
||
659 | { |
||
660 | if (isset($mapping['targetDocument']) && $mapping['targetDocument'] && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) { |
||
661 | $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument']; |
||
662 | } |
||
663 | return $mapping; |
||
664 | } |
||
665 | |||
666 | protected function validateAndCompleteAssociationMapping($mapping) |
||
667 | { |
||
668 | $mapping = $this->validateAndCompleteFieldMapping($mapping); |
||
669 | |||
670 | $mapping['sourceDocument'] = $this->name; |
||
671 | $mapping = $this->validateAndCompleteReferenceMapping($mapping); |
||
672 | return $mapping; |
||
673 | } |
||
674 | |||
675 | View Code Duplication | public function mapManyToOne($mapping) |
|
676 | { |
||
677 | $mapping = $this->validateAndCompleteAssociationMapping($mapping); |
||
678 | |||
679 | $mapping['isOwning'] = true; |
||
680 | $mapping['type'] = self::MANY_TO_ONE; |
||
681 | |||
682 | $mapping = $this->checkAndStoreIndexMapping($mapping); |
||
683 | |||
684 | $this->storeAssociationMapping($mapping); |
||
685 | } |
||
686 | |||
687 | View Code Duplication | public function mapManyToMany($mapping) |
|
688 | { |
||
689 | $mapping = $this->validateAndCompleteAssociationMapping($mapping); |
||
690 | |||
691 | $mapping['isOwning'] = empty($mapping['mappedBy']); |
||
692 | $mapping['type'] = self::MANY_TO_MANY; |
||
693 | |||
694 | $this->storeAssociationMapping($mapping); |
||
695 | } |
||
696 | |||
697 | private function checkAndStoreIndexMapping($mapping) |
||
698 | { |
||
699 | if (isset($mapping['indexed']) && $mapping['indexed']) { |
||
700 | $this->indexes[] = $mapping['fieldName']; |
||
701 | } |
||
702 | unset($mapping['indexed']); |
||
703 | |||
704 | return $mapping; |
||
705 | } |
||
706 | |||
707 | private function storeAssociationMapping($mapping) |
||
708 | { |
||
709 | $this->associationsMappings[$mapping['fieldName']] = $mapping; |
||
710 | $this->jsonNames[$mapping['jsonName']] = $mapping['fieldName']; |
||
711 | } |
||
712 | |||
713 | /** |
||
714 | * A numerically indexed list of field names of this persistent class. |
||
715 | * |
||
716 | * This array includes identifier fields if present on this class. |
||
717 | * |
||
718 | * @return array |
||
719 | */ |
||
720 | public function getFieldNames() |
||
721 | { |
||
722 | return array_keys($this->fieldMappings); |
||
723 | } |
||
724 | |||
725 | /** |
||
726 | * Gets the mapping of a field. |
||
727 | * |
||
728 | * @param string $fieldName The field name. |
||
729 | * @return array The field mapping. |
||
730 | * @throws MappingException |
||
731 | */ |
||
732 | public function getFieldMapping($fieldName) |
||
733 | { |
||
734 | if ( ! isset($this->fieldMappings[$fieldName])) { |
||
735 | throw MappingException::mappingNotFound($this->name, $fieldName); |
||
736 | } |
||
737 | return $this->fieldMappings[$fieldName]; |
||
738 | } |
||
739 | |||
740 | /** |
||
741 | * Gets the type of a field. |
||
742 | * |
||
743 | * @param string $fieldName |
||
744 | * @return Type |
||
745 | */ |
||
746 | public function getTypeOfField($fieldName) |
||
747 | { |
||
748 | return isset($this->fieldMappings[$fieldName]) ? |
||
749 | $this->fieldMappings[$fieldName]['type'] : null; |
||
750 | } |
||
751 | |||
752 | /** |
||
753 | * Checks if the given field is a mapped association for this class. |
||
754 | * |
||
755 | * @param string $fieldName |
||
756 | * @return boolean |
||
757 | */ |
||
758 | public function hasAssociation($fieldName) |
||
759 | { |
||
760 | return isset($this->associationsMappings[$fieldName]); |
||
761 | } |
||
762 | |||
763 | public function isCollectionValuedAssociation($name) |
||
764 | { |
||
765 | // TODO: included @EmbedMany here also? |
||
766 | return isset($this->associationsMappings[$name]) && ($this->associationsMappings[$name]['type'] & self::TO_MANY); |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Checks if the given field is a mapped single valued association for this class. |
||
771 | * |
||
772 | * @param string $fieldName |
||
773 | * @return boolean |
||
774 | */ |
||
775 | public function isSingleValuedAssociation($fieldName) |
||
776 | { |
||
777 | return isset($this->associationsMappings[$fieldName]) && |
||
778 | ($this->associationsMappings[$fieldName]['type'] & self::TO_ONE); |
||
779 | } |
||
780 | |||
781 | /** |
||
782 | * A numerically indexed list of association names of this persistent class. |
||
783 | * |
||
784 | * This array includes identifier associations if present on this class. |
||
785 | * |
||
786 | * @return array |
||
787 | */ |
||
788 | public function getAssociationNames() |
||
789 | { |
||
790 | return array_keys($this->associationsMappings); |
||
791 | } |
||
792 | |||
793 | /** |
||
794 | * Returns the target class name of the given association. |
||
795 | * |
||
796 | * @param string $assocName |
||
797 | * @return string |
||
798 | * @throws \InvalidArgumentException |
||
799 | */ |
||
800 | public function getAssociationTargetClass($assocName) |
||
801 | { |
||
802 | if (!isset($this->associationsMappings[$assocName])) { |
||
803 | throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association."); |
||
804 | } |
||
805 | return $this->associationsMappings[$assocName]['targetDocument']; |
||
806 | } |
||
807 | |||
808 | /** |
||
809 | * {@inheritDoc} |
||
810 | */ |
||
811 | public function getAssociationMappedByTargetField($assocName) |
||
812 | { |
||
813 | return $this->associationsMappings[$assocName]['mappedBy']; |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * {@inheritDoc} |
||
818 | */ |
||
819 | public function isAssociationInverseSide($assocName) |
||
820 | { |
||
821 | return isset($this->associationsMappings[$assocName]) && ! $this->associationsMappings[$assocName]; |
||
822 | } |
||
823 | |||
824 | public function isInheritedField($field) |
||
825 | { |
||
826 | return isset($this->fieldMappings[$field]['declared']); |
||
827 | } |
||
828 | |||
829 | public function isInheritedAssociation($field) |
||
830 | { |
||
831 | return isset($this->associationsMappings[$field]['declared']); |
||
832 | } |
||
833 | |||
834 | public function setParentClasses($classes) |
||
835 | { |
||
836 | $this->parentClasses = $classes; |
||
837 | $this->inInheritanceHierachy = true; |
||
838 | if (count($classes) > 0) { |
||
839 | $this->rootDocumentName = array_pop($classes); |
||
840 | } |
||
841 | } |
||
842 | |||
843 | public function markInheritanceRoot() |
||
844 | { |
||
845 | if ($this->parentClasses) { |
||
0 ignored issues
–
show
The expression
$this->parentClasses of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
846 | throw MappingException::invalidInheritanceRoot($this->name, $this->parentClasses); |
||
847 | } |
||
848 | $this->inInheritanceHierachy = true; |
||
849 | } |
||
850 | |||
851 | /** |
||
852 | * Initializes a new ClassMetadata instance that will hold the object-relational mapping |
||
853 | * metadata of the class with the given name. |
||
854 | * |
||
855 | * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service. |
||
856 | * |
||
857 | * @return void |
||
858 | */ |
||
859 | public function initializeReflection($reflService) |
||
860 | { |
||
861 | $this->reflClass = $reflService->getClass($this->name); |
||
862 | $this->namespace = $reflService->getClassNamespace($this->name); |
||
863 | |||
864 | if ($this->reflClass) { |
||
865 | $this->name = $this->rootDocumentName = $this->reflClass->getName(); |
||
866 | } |
||
867 | } |
||
868 | } |
||
869 | |||
870 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: