/** * Get the inverse relationship type of the given relationship type * * @param RelationshipType $relationship_type * @return RelationshipType */ public static function getInverseRelationship(RelationshipType $relationship_type) { switch ($relationship_type) { default: throw new InvalidEntityException("Unknown relationship type: " . $relationship_type->key()); case RelationshipType::ONETOONE(): return RelationshipType::ONETOONE(); case RelationshipType::ONETOMANY(): return RelationshipType::MANYTOONE(); case RelationshipType::MANYTOONE(): return RelationshipType::ONETOMANY(); case RelationshipType::MANYTOMANY(): return RelationshipType::MANYTOMANY(); } }
/** * When adding an entity on a one-to-many relationship, the foreign entity might have had a pre-existing entity * assigned in the inverted 'to-one' index. If it had a value, we now need to break that existing relationship as * we have inadvertently removed it by assigning it to a new local entity. * * This operation should only ever be applied to 'to-one' relationships, which should be the inverse of a 'to-many' * relationship. Other use is illogical. * * This call will remove only the inverse of the relationship provided (which would be the former forward of the * relationship that triggered this), breaking the forward relationship is assumed when overwriting the new * relationship. * * @param Relationship $relationship * @param string $source_id */ private function breakFormerRelationship(Relationship $relationship, $source_id) { $key = $this->getRelationshipKey($relationship, $source_id); $this->getDriver()->debugLog('Checking for breakable former relationship: ' . $key); $old_value = $this->getDriver()->getSingleValueIndex($key); if (!$old_value) { // No former relationship to break return; } $inverse_relationship = $this->invertRelationship($relationship); // Relationship keys $inverse_key = $this->getRelationshipKey($inverse_relationship, $old_value); $this->getDriver()->debugLog('@Breaking former relationship: ' . $inverse_key); if ($inverse_relationship->getRelationshipType() == RelationshipType::MANYTOONE() || $inverse_relationship->getRelationshipType() == RelationshipType::ONETOONE()) { $this->getDriver()->clearSingleValueIndex($inverse_key); } else { $this->getDriver()->removeMultiValueIndex($inverse_key, $source_id); } // Sorted index keys foreach ($inverse_relationship->getSortableBy() as $sortable) { $sort_key = $this->getSortIndexKey($inverse_relationship, $sortable->getName(), $old_value); $this->getDriver()->removeSortedIndex($sort_key, $source_id); } }
/** * Get all relationships in the entity * * @return Relationship[] */ public function getRelationships() { $r = []; $properties = $this->reflection_obj->getProperties(); foreach ($properties as $property) { /** @var OneToOne $oto */ $oto = $this->annotation_reader->getPropertyAnnotation($property, self::OTO_ANNOTATION); if ($oto) { $r[] = $this->createRelationship($property->getName(), RelationshipType::ONETOONE(), $oto); } /** @var OneToMany $otm */ $otm = $this->annotation_reader->getPropertyAnnotation($property, self::OTM_ANNOTATION); if ($otm) { $r[] = $this->createRelationship($property->getName(), RelationshipType::ONETOMANY(), $otm); } /** @var ManyToOne $mto */ $mto = $this->annotation_reader->getPropertyAnnotation($property, self::MTO_ANNOTATION); if ($mto) { $r[] = $this->createRelationship($property->getName(), RelationshipType::MANYTOONE(), $mto); } /** @var ManyToMany $mtm */ $mtm = $this->annotation_reader->getPropertyAnnotation($property, self::MTM_ANNOTATION); if ($mtm) { $r[] = $this->createRelationship($property->getName(), RelationshipType::MANYTOMANY(), $mtm); } } return $r; }
/** * Same as above test, except we'll delete the category * * @dataProvider entityManagerDataProvider * @param EntityManager $em */ public function testDeleteIndicesAndRelationshipsAlt(EntityManager $em) { $article1 = new RefArticle(); $article1->setId(502)->setTitle('Ref Article 502'); $category1 = new RefCategory(); $category1->setId(533)->setName('Ref Category 533'); $article1->setCanonicalCategory($category1); $em->persist($category1)->persist($article1)->flush(); $this->assertTrue($this->exists($em, 'article', '502')); $mto = $this->getRelKey($em, 'article', 'category', '502', 'canonical_category', RelationshipType::MANYTOONE()); $this->assertEquals('533', $em->getDriver()->getSingleValueIndex($mto)); // Not inversed: $otm = $this->getRelKey($em, 'category', 'article', '533', 'articles', RelationshipType::ONETOMANY()); $this->assertNotContains('502', $em->getDriver()->getMultiValueIndex($otm)); // Ref exists: $refs = $em->getDriver()->getRefs($this->getEntityRefKey($em, 'category', '533')); $ref = (string) new Ref(RefArticle::class, '502', 'canonical_category'); $this->assertCount(1, $refs); $this->assertEquals($ref, (string) $refs[0]); /** @var RefCategory $category */ $category = $em->retrieve(RefCategory::class, 533); $em->delete($category)->flush(); $this->assertFalse($this->exists($em, 'category', '533')); $this->assertNull($em->getDriver()->getSingleValueIndex($mto)); $this->assertNotContains('502', $em->getDriver()->getMultiValueIndex($otm)); // Ref no longer needed: $refs = $em->getDriver()->getRefs($this->getEntityRefKey($em, 'category', '533')); $this->assertNotContains($ref, $refs); }