Completed
Push — master ( 09b86b...ba0798 )
by Andreas
20:05 queued 12s
created

LifecycleEventManager::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 2.0116

Importance

Changes 0
Metric Value
dl 9
loc 9
ccs 6
cts 7
cp 0.8571
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2.0116
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Utility;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\ODM\MongoDB\DocumentManager;
9
use Doctrine\ODM\MongoDB\Event\DocumentNotFoundEventArgs;
10
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
11
use Doctrine\ODM\MongoDB\Event\PostCollectionLoadEventArgs;
12
use Doctrine\ODM\MongoDB\Event\PreUpdateEventArgs;
13
use Doctrine\ODM\MongoDB\Events;
14
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
15
use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface;
16
use Doctrine\ODM\MongoDB\UnitOfWork;
17
use const E_USER_DEPRECATED;
18
use function get_class;
19
use function sprintf;
20
use function trigger_error;
21
22
/**
23
 * @internal
24
 *
25
 * @final
26
 */
27
class LifecycleEventManager
28
{
29
    /** @var DocumentManager */
30
    private $dm;
31
32
    /** @var EventManager */
33
    private $evm;
34
35
    /** @var UnitOfWork */
36
    private $uow;
37
38 1656 View Code Duplication
    public function __construct(DocumentManager $dm, UnitOfWork $uow, EventManager $evm)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
39
    {
40 1656
        if (self::class !== static::class) {
41
            @trigger_error(sprintf('The class "%s" extends "%s" which will be final in MongoDB ODM 2.0.', static::class, self::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
42
        }
43 1656
        $this->dm  = $dm;
44 1656
        $this->evm = $evm;
45 1656
        $this->uow = $uow;
46 1656
    }
47
48
    /**
49
     * @param mixed $id
50
     *
51
     * @return bool Returns whether the exceptionDisabled flag was set
52
     */
53 9
    public function documentNotFound(object $proxy, $id) : bool
54
    {
55 9
        $eventArgs = new DocumentNotFoundEventArgs($proxy, $this->dm, $id);
56 9
        $this->evm->dispatchEvent(Events::documentNotFound, $eventArgs);
57
58 9
        return $eventArgs->isExceptionDisabled();
59
    }
60
61
    /**
62
     * Dispatches postCollectionLoad event.
63
     */
64 178
    public function postCollectionLoad(PersistentCollectionInterface $coll) : void
65
    {
66 178
        $eventArgs = new PostCollectionLoadEventArgs($coll, $this->dm);
67 178
        $this->evm->dispatchEvent(Events::postCollectionLoad, $eventArgs);
68 178
    }
69
70
    /**
71
     * Invokes postPersist callbacks and events for given document cascading them to embedded documents as well.
72
     */
73 596
    public function postPersist(ClassMetadata $class, object $document) : void
74
    {
75 596
        $class->invokeLifecycleCallbacks(Events::postPersist, $document, [new LifecycleEventArgs($document, $this->dm)]);
76 596
        $this->evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($document, $this->dm));
77 596
        $this->cascadePostPersist($class, $document);
78 596
    }
79
80
    /**
81
     * Invokes postRemove callbacks and events for given document.
82
     */
83 77
    public function postRemove(ClassMetadata $class, object $document) : void
84
    {
85 77
        $class->invokeLifecycleCallbacks(Events::postRemove, $document, [new LifecycleEventArgs($document, $this->dm)]);
86 77
        $this->evm->dispatchEvent(Events::postRemove, new LifecycleEventArgs($document, $this->dm));
87 77
    }
88
89
    /**
90
     * Invokes postUpdate callbacks and events for given document. The same will be done for embedded documents owned
91
     * by given document unless they were new in which case postPersist callbacks and events will be dispatched.
92
     */
93 229
    public function postUpdate(ClassMetadata $class, object $document) : void
94
    {
95 229
        $class->invokeLifecycleCallbacks(Events::postUpdate, $document, [new LifecycleEventArgs($document, $this->dm)]);
96 229
        $this->evm->dispatchEvent(Events::postUpdate, new LifecycleEventArgs($document, $this->dm));
97 229
        $this->cascadePostUpdate($class, $document);
98 229
    }
99
100
    /**
101
     * Invokes prePersist callbacks and events for given document.
102
     */
103 644
    public function prePersist(ClassMetadata $class, object $document) : void
104
    {
105 644
        $class->invokeLifecycleCallbacks(Events::prePersist, $document, [new LifecycleEventArgs($document, $this->dm)]);
106 644
        $this->evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($document, $this->dm));
107 644
    }
108
109
    /**
110
     * Invokes prePersist callbacks and events for given document.
111
     */
112 83
    public function preRemove(ClassMetadata $class, object $document) : void
113
    {
114 83
        $class->invokeLifecycleCallbacks(Events::preRemove, $document, [new LifecycleEventArgs($document, $this->dm)]);
115 83
        $this->evm->dispatchEvent(Events::preRemove, new LifecycleEventArgs($document, $this->dm));
116 83
    }
117
118
    /**
119
     * Invokes preUpdate callbacks and events for given document cascading them to embedded documents as well.
120
     */
121 236
    public function preUpdate(ClassMetadata $class, object $document) : void
122
    {
123 236
        if (! empty($class->lifecycleCallbacks[Events::preUpdate])) {
124 12
            $class->invokeLifecycleCallbacks(Events::preUpdate, $document, [new PreUpdateEventArgs($document, $this->dm, $this->uow->getDocumentChangeSet($document))]);
125 12
            $this->uow->recomputeSingleDocumentChangeSet($class, $document);
126
        }
127 236
        $this->evm->dispatchEvent(Events::preUpdate, new PreUpdateEventArgs($document, $this->dm, $this->uow->getDocumentChangeSet($document)));
128 236
        $this->cascadePreUpdate($class, $document);
129 236
    }
130
131
    /**
132
     * Cascades the preUpdate event to embedded documents.
133
     */
134 236
    private function cascadePreUpdate(ClassMetadata $class, object $document) : void
135
    {
136 236
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
137 150
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
138 150
            if ($value === null) {
139 55
                continue;
140
            }
141 142
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
142
143 142
            foreach ($values as $entry) {
144 96
                if ($this->uow->isScheduledForInsert($entry) || empty($this->uow->getDocumentChangeSet($entry))) {
145 80
                    continue;
146
                }
147 52
                $this->preUpdate($this->dm->getClassMetadata(get_class($entry)), $entry);
148
            }
149
        }
150 236
    }
151
152
    /**
153
     * Cascades the postUpdate and postPersist events to embedded documents.
154
     */
155 229
    private function cascadePostUpdate(ClassMetadata $class, object $document) : void
156
    {
157 229
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
158 146
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
159 146
            if ($value === null) {
160 58
                continue;
161
            }
162 138
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
163
164 138
            foreach ($values as $entry) {
165 96
                if (empty($this->uow->getDocumentChangeSet($entry)) && ! $this->uow->hasScheduledCollections($entry)) {
166 55
                    continue;
167
                }
168 82
                $entryClass = $this->dm->getClassMetadata(get_class($entry));
169 82
                $event      = $this->uow->isScheduledForInsert($entry) ? Events::postPersist : Events::postUpdate;
170 82
                $entryClass->invokeLifecycleCallbacks($event, $entry, [new LifecycleEventArgs($entry, $this->dm)]);
171 82
                $this->evm->dispatchEvent($event, new LifecycleEventArgs($entry, $this->dm));
172
173 82
                $this->cascadePostUpdate($entryClass, $entry);
174
            }
175
        }
176 229
    }
177
178
    /**
179
     * Cascades the postPersist events to embedded documents.
180
     */
181 596
    private function cascadePostPersist(ClassMetadata $class, object $document) : void
182
    {
183 596
        foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
184 365
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
185 365
            if ($value === null) {
186 231
                continue;
187
            }
188 333
            $values = $mapping['type'] === ClassMetadata::ONE ? [$value] : $value;
189 333
            foreach ($values as $embeddedDocument) {
190 168
                $this->postPersist($this->dm->getClassMetadata(get_class($embeddedDocument)), $embeddedDocument);
191
            }
192
        }
193 596
    }
194
}
195