• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nextras / orm / 22264745434

21 Feb 2026 09:31PM UTC coverage: 92.11%. First build
22264745434

Pull #793

github

web-flow
Merge c2ae59b3a into 96b3f3a9a
Pull Request #793: relationship: implement removeOrphan cascade relationship [closes #205]

160 of 167 new or added lines in 4 files covered. (95.81%)

4273 of 4639 relevant lines covered (92.11%)

5.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/src/Relationships/OneHasMany.php
1
<?php declare(strict_types = 1);
2

3
namespace Nextras\Orm\Relationships;
4

5

6
use Nextras\Orm\Collection\ICollection;
7
use Nextras\Orm\Entity\IEntity;
8
use function assert;
9

10

11
/**
12
 * @template E of IEntity
13
 * @extends HasMany<E>
14
 */
15
class OneHasMany extends HasMany
16
{
17
        public function getEntitiesForPersistence(): array
18
        {
19
                $toPersist = [];
6✔
20
                if ($this->metadataRelationship->property !== null) {
6✔
21
                        // When the relationship's reverse side is defined, we check if the reverse entity has a new value.
22
                        // If yes, we want to persist this reversed entity.
23
                        foreach ($this->toRemove as $entityToRemove) {
6✔
24
                                $property = $entityToRemove->getProperty($this->metadataRelationship->property);
6✔
25
                                $propertyMeta = $entityToRemove->getMetadata()->getProperty($this->metadataRelationship->property);
6✔
26
                                if ($entityToRemove->isPersisted() && ($property->getRawValue() !== null || $propertyMeta->isNullable)){
6✔
27
                                        $entityId = spl_object_id($entityToRemove);
6✔
28
                                        $toPersist[$entityId] = $entityToRemove;
6✔
29
                                }
30
                        }
31
                }
32
                return $this->tracked + $this->toAdd + $toPersist;
6✔
33
        }
34

35

36
        public function getEntitiesForRemoval(): array
37
        {
38
                if ($this->metadataRelationship->property !== null) {
6✔
39
                        // When the relationship's reverse side is defined, we check if the reverse entity has stayed unset.
40
                        // If yes, we want to remove the entity.
41
                        $toRemove = [];
6✔
42
                        foreach ($this->toRemove as $entityToRemove) {
6✔
43
                                $property = $entityToRemove->getProperty($this->metadataRelationship->property);
6✔
44
                                $propertyMeta = $entityToRemove->getMetadata()->getProperty($this->metadataRelationship->property);
6✔
45
                                if ($entityToRemove->isPersisted() && $property->getRawValue() === null && !$propertyMeta->isNullable) {
6✔
46
                                        $entityId = spl_object_id($entityToRemove);
6✔
47
                                        $toRemove[$entityId] = $entityToRemove;
6✔
48
                                }
49
                        }
50
                        return $toRemove;
6✔
51
                } else {
NEW
52
                        return array_filter($this->toRemove, fn ($e) => $e->isPersisted());
×
53
                }
54
        }
55

56

57
        public function doPersist(): void
58
        {
59
                if (!$this->isModified) {
6✔
60
                        return;
6✔
61
                }
62

63
                $this->tracked += $this->toAdd;
6✔
64
                foreach ($this->toRemove as $hash => $entity) {
6✔
65
                        unset($this->tracked[$hash]);
6✔
66
                }
67
                $this->toAdd = [];
6✔
68
                $this->toRemove = [];
6✔
69

70
                $this->isModified = false;
6✔
71
                $this->collection = null;
6✔
72

73
                $this->getRelationshipMapper()->clearCache();
6✔
74
                $this->relationshipMapper = null;
6✔
75
        }
6✔
76

77

78
        protected function modify(): void
79
        {
80
                $this->isModified = true;
6✔
81
        }
6✔
82

83
        protected function createCollection(): ICollection
84
        {
85
                /** @var ICollection<E> $collection */
86
                $collection = $this->getTargetRepository()->getMapper()->createCollectionOneHasMany($this->metadata);
6✔
87
                $collection = $collection->setRelationshipParent($this->parent);
6✔
88
                $collection->subscribeOnEntityFetch(function ($entities): void {
6✔
89
                        foreach ($entities as $entity) {
6✔
90
                                $this->trackEntity($entity);
6✔
91
                        }
92
                });
6✔
93
                return $this->applyDefaultOrder($collection);
6✔
94
        }
95

96

97
        protected function updateRelationshipAdd(IEntity $entity): void
98
        {
99
                if ($this->metadataRelationship->property === null) {
6✔
100
                        return;
×
101
                }
102

103
                $this->updatingReverseRelationship = true;
6✔
104
                $property = $entity->getProperty($this->metadataRelationship->property);
6✔
105
                assert($property instanceof ManyHasOne);
106
                $property->set($this->parent);
6✔
107
                $this->updatingReverseRelationship = false;
6✔
108
        }
6✔
109

110

111
        protected function updateRelationshipRemove(IEntity $entity): void
112
        {
113
                if ($this->metadataRelationship->property === null) {
6✔
114
                        return;
×
115
                }
116

117
                $this->updatingReverseRelationship = true;
6✔
118
                $property = $entity->getProperty($this->metadataRelationship->property);
6✔
119
                assert($property instanceof ManyHasOne);
120
                $property->set(null, allowNull: true);
6✔
121
                $this->updatingReverseRelationship = false;
6✔
122
        }
6✔
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc