Completed
Push — master ( ecb96f...9f19a4 )
by Andreas
21s queued 13s
created

LifecycleEventManager::dispatchEvent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Utility;
6
7
use Doctrine\Common\EventArgs;
8
use Doctrine\Common\EventManager;
9
use Doctrine\ODM\MongoDB\DocumentManager;
10
use Doctrine\ODM\MongoDB\Event\DocumentNotFoundEventArgs;
11
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
12
use Doctrine\ODM\MongoDB\Event\PostCollectionLoadEventArgs;
13
use Doctrine\ODM\MongoDB\Event\PreUpdateEventArgs;
14
use Doctrine\ODM\MongoDB\Events;
15
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
16
use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface;
17
use Doctrine\ODM\MongoDB\UnitOfWork;
18
use function get_class;
19
20
/**
21
 * @internal
22
 */
23
final class LifecycleEventManager
24
{
25
    /** @var DocumentManager */
26
    private $dm;
27
28
    /** @var EventManager */
29
    private $evm;
30
31
    /** @var UnitOfWork */
32
    private $uow;
33 1800
34
    public function __construct(DocumentManager $dm, UnitOfWork $uow, EventManager $evm)
35 1800
    {
36 1800
        $this->dm  = $dm;
37 1800
        $this->evm = $evm;
38 1800
        $this->uow = $uow;
39
    }
40
41
    /**
42
     * @param mixed $id
43
     *
44
     * @return bool Returns whether the exceptionDisabled flag was set
45 9
     */
46
    public function documentNotFound(object $proxy, $id) : bool
47 9
    {
48 9
        $eventArgs = new DocumentNotFoundEventArgs($proxy, $this->dm, $id);
49
        $this->evm->dispatchEvent(Events::documentNotFound, $eventArgs);
50 9
51
        return $eventArgs->isExceptionDisabled();
52
    }
53
54
    /**
55
     * Dispatches postCollectionLoad event.
56 178
     */
57
    public function postCollectionLoad(PersistentCollectionInterface $coll) : void
58 178
    {
59 178
        $eventArgs = new PostCollectionLoadEventArgs($coll, $this->dm);
60 178
        $this->evm->dispatchEvent(Events::postCollectionLoad, $eventArgs);
61
    }
62
63
    /**
64
     * Invokes postPersist callbacks and events for given document cascading them to embedded documents as well.
65 599
     */
66
    public function postPersist(ClassMetadata $class, object $document) : void
67 599
    {
68 599
        $class->invokeLifecycleCallbacks(Events::postPersist, $document, [new LifecycleEventArgs($document, $this->dm)]);
69 599
        $this->dispatchEvent($class, Events::postPersist, new LifecycleEventArgs($document, $this->dm));
70 599
        $this->cascadePostPersist($class, $document);
71
    }
72
73
    /**
74
     * Invokes postRemove callbacks and events for given document.
75 77
     */
76
    public function postRemove(ClassMetadata $class, object $document) : void
77 77
    {
78 77
        $class->invokeLifecycleCallbacks(Events::postRemove, $document, [new LifecycleEventArgs($document, $this->dm)]);
79 77
        $this->dispatchEvent($class, Events::postRemove, new LifecycleEventArgs($document, $this->dm));
80
    }
81
82
    /**
83
     * Invokes postUpdate callbacks and events for given document. The same will be done for embedded documents owned
84
     * by given document unless they were new in which case postPersist callbacks and events will be dispatched.
85 230
     */
86
    public function postUpdate(ClassMetadata $class, object $document) : void
87 230
    {
88 230
        $class->invokeLifecycleCallbacks(Events::postUpdate, $document, [new LifecycleEventArgs($document, $this->dm)]);
89 230
        $this->dispatchEvent($class, Events::postUpdate, new LifecycleEventArgs($document, $this->dm));
90 230
        $this->cascadePostUpdate($class, $document);
91
    }
92
93
    /**
94
     * Invokes prePersist callbacks and events for given document.
95 658
     */
96
    public function prePersist(ClassMetadata $class, object $document) : void
97 658
    {
98 658
        $class->invokeLifecycleCallbacks(Events::prePersist, $document, [new LifecycleEventArgs($document, $this->dm)]);
99 658
        $this->dispatchEvent($class, Events::prePersist, new LifecycleEventArgs($document, $this->dm));
100
    }
101
102
    /**
103
     * Invokes prePersist callbacks and events for given document.
104 83
     */
105
    public function preRemove(ClassMetadata $class, object $document) : void
106 83
    {
107 83
        $class->invokeLifecycleCallbacks(Events::preRemove, $document, [new LifecycleEventArgs($document, $this->dm)]);
108 83
        $this->dispatchEvent($class, Events::preRemove, new LifecycleEventArgs($document, $this->dm));
109
    }
110
111
    /**
112
     * Invokes preUpdate callbacks and events for given document cascading them to embedded documents as well.
113 238
     */
114
    public function preUpdate(ClassMetadata $class, object $document) : void
115 238
    {
116 12
        if (! empty($class->lifecycleCallbacks[Events::preUpdate])) {
117 12
            $class->invokeLifecycleCallbacks(Events::preUpdate, $document, [new PreUpdateEventArgs($document, $this->dm, $this->uow->getDocumentChangeSet($document))]);
118
            $this->uow->recomputeSingleDocumentChangeSet($class, $document);
119 238
        }
120 238
        $this->dispatchEvent($class, Events::preUpdate, new PreUpdateEventArgs($document, $this->dm, $this->uow->getDocumentChangeSet($document)));
121 238
        $this->cascadePreUpdate($class, $document);
122
    }
123
124
    /**
125
     * Cascades the preUpdate event to embedded documents.
126 238
     */
127
    private function cascadePreUpdate(ClassMetadata $class, object $document) : void
128 238
    {
129 153
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
130 153
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
131 55
            if ($value === null) {
132
                continue;
133 145
            }
134
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
135 145
136 96
            foreach ($values as $entry) {
137 80
                if ($this->uow->isScheduledForInsert($entry) || empty($this->uow->getDocumentChangeSet($entry))) {
138
                    continue;
139 52
                }
140
                $this->preUpdate($this->dm->getClassMetadata(get_class($entry)), $entry);
141
            }
142 238
        }
143
    }
144
145
    /**
146
     * Cascades the postUpdate and postPersist events to embedded documents.
147 230
     */
148
    private function cascadePostUpdate(ClassMetadata $class, object $document) : void
149 230
    {
150 148
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
151 148
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
152 58
            if ($value === null) {
153
                continue;
154 140
            }
155
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
156 140
157 96
            foreach ($values as $entry) {
158 55
                if (empty($this->uow->getDocumentChangeSet($entry)) && ! $this->uow->hasScheduledCollections($entry)) {
159
                    continue;
160 82
                }
161 82
                $entryClass = $this->dm->getClassMetadata(get_class($entry));
162 82
                $event      = $this->uow->isScheduledForInsert($entry) ? Events::postPersist : Events::postUpdate;
163 82
                $entryClass->invokeLifecycleCallbacks($event, $entry, [new LifecycleEventArgs($entry, $this->dm)]);
164
                $this->dispatchEvent($entryClass, $event, new LifecycleEventArgs($entry, $this->dm));
165 82
166
                $this->cascadePostUpdate($entryClass, $entry);
167
            }
168 230
        }
169
    }
170
171
    /**
172
     * Cascades the postPersist events to embedded documents.
173 599
     */
174
    private function cascadePostPersist(ClassMetadata $class, object $document) : void
175 599
    {
176 368
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
177 368
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
178 231
            if ($value === null) {
179
                continue;
180 336
            }
181 336
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
182 168
            foreach ($values as $embeddedDocument) {
183
                $this->postPersist($this->dm->getClassMetadata(get_class($embeddedDocument)), $embeddedDocument);
184
            }
185 599
        }
186
    }
187
188
    private function dispatchEvent(ClassMetadata $class, string $eventName, ?EventArgs $eventArgs = null) : void
189
    {
190
        if ($class->isView()) {
191
            return;
192
        }
193
194
        $this->evm->dispatchEvent($eventName, $eventArgs);
195
    }
196
}
197