|
31 | 31 | use Doctrine\Common\ClassLoader; |
32 | 32 | use Doctrine\Instantiator\Instantiator; |
33 | 33 | use Doctrine\Instantiator\InstantiatorInterface; |
| 34 | +use Doctrine\ODM\PHPCR\Exception\OutOfBoundsException; |
34 | 35 |
|
35 | 36 | /** |
36 | 37 | * Metadata class |
@@ -328,6 +329,23 @@ class ClassMetadata implements ClassMetadataInterface |
328 | 329 | */ |
329 | 330 | public $parentClasses = array(); |
330 | 331 |
|
| 332 | + /** |
| 333 | + * READ-ONLY: Child class restrictions. |
| 334 | + * |
| 335 | + * If empty then any classes are permitted. |
| 336 | + * |
| 337 | + * @var array |
| 338 | + */ |
| 339 | + public $childClasses = array(); |
| 340 | + |
| 341 | + /** |
| 342 | + * READ-ONLY: If the document should be act as a leaf-node and therefore |
| 343 | + * not be allowed children. |
| 344 | + * |
| 345 | + * @var boolean |
| 346 | + */ |
| 347 | + public $isLeaf = false; |
| 348 | + |
331 | 349 | /** |
332 | 350 | * The inherited fields of this class |
333 | 351 | * |
@@ -453,6 +471,57 @@ public function validateIdentifier() |
453 | 471 | } |
454 | 472 | } |
455 | 473 |
|
| 474 | + /** |
| 475 | + * Validate that childClasses is empty if isLeaf is true. |
| 476 | + * |
| 477 | + * @throws MappingException if there is a conflict between isLeaf and childClasses. |
| 478 | + */ |
| 479 | + public function validateChildClasses() |
| 480 | + { |
| 481 | + if (count($this->childClasses) > 0 && $this->isLeaf) { |
| 482 | + throw new MappingException(sprintf( |
| 483 | + 'Cannot map a document as a leaf and define child classes for "%s"', |
| 484 | + $this->name |
| 485 | + )); |
| 486 | + } |
| 487 | + } |
| 488 | + |
| 489 | + /** |
| 490 | + * Assert that the given class FQN can be a child of the document this |
| 491 | + * metadata represents. |
| 492 | + * |
| 493 | + * @param string $classFqn |
| 494 | + * @throws OutOfBoundsException |
| 495 | + */ |
| 496 | + public function assertValidChildClass(ClassMetadata $class) |
| 497 | + { |
| 498 | + if ($this->isLeaf()) { |
| 499 | + throw new OutOfBoundsException(sprintf( |
| 500 | + 'Document "%s" has been mapped as a leaf. It cannot have children', |
| 501 | + $this->name |
| 502 | + )); |
| 503 | + } |
| 504 | + |
| 505 | + $childClasses = $this->getChildClasses(); |
| 506 | + |
| 507 | + if (array() === $childClasses) { |
| 508 | + return; |
| 509 | + } |
| 510 | + |
| 511 | + foreach ($childClasses as $childClass) { |
| 512 | + if ($class->name === $childClass || $class->reflClass->isSubclassOf($childClass)) { |
| 513 | + return true; |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + throw new OutOfBoundsException(sprintf( |
| 518 | + 'Document "%s" does not allow children of type "%s". Allowed child classes "%s"', |
| 519 | + $this->name, |
| 520 | + $class->name, |
| 521 | + implode('", "', $childClasses) |
| 522 | + )); |
| 523 | + } |
| 524 | + |
456 | 525 | /** |
457 | 526 | * Validate whether this class needs to be referenceable. |
458 | 527 | * |
@@ -1123,6 +1192,49 @@ public function getParentClasses() |
1123 | 1192 | return $this->parentClasses; |
1124 | 1193 | } |
1125 | 1194 |
|
| 1195 | + /** |
| 1196 | + * Return the class names or interfaces that children of this document must |
| 1197 | + * be an instance of. |
| 1198 | + * |
| 1199 | + * @return string[] |
| 1200 | + */ |
| 1201 | + public function getChildClasses() |
| 1202 | + { |
| 1203 | + return $this->childClasses; |
| 1204 | + } |
| 1205 | + |
| 1206 | + /** |
| 1207 | + * Set the class names or interfaces that children of this document must be |
| 1208 | + * instance of. |
| 1209 | + * |
| 1210 | + * @param string[] $childClasses |
| 1211 | + */ |
| 1212 | + public function setChildClasses(array $childClasses) |
| 1213 | + { |
| 1214 | + $this->childClasses = $childClasses; |
| 1215 | + } |
| 1216 | + |
| 1217 | + /** |
| 1218 | + * Return true if this is designated as a leaf node. |
| 1219 | + * |
| 1220 | + * @return bool |
| 1221 | + */ |
| 1222 | + public function isLeaf() |
| 1223 | + { |
| 1224 | + return $this->isLeaf; |
| 1225 | + } |
| 1226 | + |
| 1227 | + /** |
| 1228 | + * Set if this document should act as a leaf node. |
| 1229 | + * |
| 1230 | + * @param bool $isLeaf |
| 1231 | + */ |
| 1232 | + public function setIsLeaf($isLeaf) |
| 1233 | + { |
| 1234 | + $this->isLeaf = $isLeaf; |
| 1235 | + } |
| 1236 | + |
| 1237 | + |
1126 | 1238 | /** |
1127 | 1239 | * Checks whether the class will generate an id via the repository. |
1128 | 1240 | * |
|
0 commit comments