Completed
Pull Request — master (#1)
by Karsten
03:23
created

MongoDbEntityConfig::getPreSaveVisits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * File was created 11.02.2016 17:38
4
 */
5
6
namespace PeekAndPoke\Component\Slumber\Data\MongoDb;
7
8
use PeekAndPoke\Component\PropertyAccess\PropertyAccess;
9
use PeekAndPoke\Component\Psi\Functions\Unary\Matcher\IsInstanceOf;
10
use PeekAndPoke\Component\Psi\Psi;
11
use PeekAndPoke\Component\Slumber\Annotation\ClassMarker;
12
use PeekAndPoke\Component\Slumber\Annotation\ClassPostDeleteListenerMarker;
13
use PeekAndPoke\Component\Slumber\Annotation\ClassPostSaveListenerMarker;
14
use PeekAndPoke\Component\Slumber\Annotation\CompoundIndexDefinition;
15
use PeekAndPoke\Component\Slumber\Annotation\PropertyPreSaveVisitorMarker;
16
use PeekAndPoke\Component\Slumber\Annotation\PropertyStorageIndexMarker;
17
use PeekAndPoke\Component\Slumber\Annotation\Slumber\AsObject;
18
use PeekAndPoke\Component\Slumber\Annotation\Slumber\Store\AsDbReference;
19
use PeekAndPoke\Component\Slumber\Annotation\Slumber\Store\AsId;
20
use PeekAndPoke\Component\Slumber\Core\Codec\Property\CollectionMapper;
21
use PeekAndPoke\Component\Slumber\Core\Codec\Property\ObjectMapper;
22
use PeekAndPoke\Component\Slumber\Core\LookUp\EntityConfig;
23
use PeekAndPoke\Component\Slumber\Core\LookUp\PropertyMarkedForIndexing;
24
use PeekAndPoke\Component\Slumber\Core\LookUp\PropertyMarkedForPreSaveVisit;
25
use PeekAndPoke\Component\Slumber\Core\LookUp\PropertyMarkedForSlumber;
26
use PeekAndPoke\Component\Slumber\Data\LazyDbReferenceCollection;
27
use PeekAndPoke\Component\Slumber\Data\MongoDb\Types\DbReferenceCollectionMapper;
28
use PeekAndPoke\Component\Slumber\Data\MongoDb\Types\DbReferenceMapper;
29
use PeekAndPoke\Component\Slumber\Data\MongoDb\Types\PrimaryIdMapper;
30
31
/**
32
 * @author Karsten J. Gerber <[email protected]>
33
 */
34
class MongoDbEntityConfig extends EntityConfig
35
{
36
    /** @var PropertyMarkedForSlumber */
37
    protected $idMarker;
38
39
    /** @var array|PropertyMarkedForPreSaveVisit[] */
40
    protected $preSaveVisits = [];
41
42
    /** @var array|ClassPostSaveListenerMarker[] */
43
    protected $postSaveClassListeners = [];
44
    /** @var array|ClassPostDeleteListenerMarker[] */
45
    protected $postDeleteClassListeners = [];
46
47
    /** @var array|PropertyMarkedForIndexing[] */
48
    protected $indexedProperties = [];
49
    /** @var array|CompoundIndexDefinition[] */
50
    protected $compoundIndexes = [];
51
52
    /**
53
     * @param EntityConfig $config
54
     *
55
     * @return MongoDbEntityConfig
56
     */
57 1
    public static function from(EntityConfig $config)
58
    {
59 1
        $result = new self(
60 1
            $config->getClassName(),
61 1
            $config->getCreator(),
62 1
            $config->getMarkersOnClass(),
63 1
            $config->getMarkedProperties()
64
        );
65
66 1
        $result->initialize();
67
68 1
        return $result;
69
    }
70
71
    /**
72
     * Get access to the primary id in order to read and write it without having to know the name of the property
73
     *
74
     * @return PropertyAccess
75
     */
76 20
    public function getIdAccess()
77
    {
78 20
        return $this->idMarker->propertyAccess;
79
    }
80
81
    /**
82
     * @return CompoundIndexDefinition[]
83
     */
84
    public function getCompoundIndexes()
85
    {
86
        return $this->compoundIndexes;
87
    }
88
89
    /**
90
     * @return PropertyMarkedForIndexing[]
91
     */
92
    public function getIndexedProperties()
93
    {
94
        return $this->indexedProperties;
95
    }
96
97
    /**
98
     * @return PropertyMarkedForPreSaveVisit[]
99
     */
100 21
    public function getPreSaveVisits()
101
    {
102 21
        return $this->preSaveVisits;
103
    }
104
105
    /**
106
     * @return bool
107
     */
108 21
    public function hasPostSaveClassListeners()
109
    {
110 21
        return count($this->postSaveClassListeners) > 0;
111
    }
112
113
    /**
114
     * @return ClassPostSaveListenerMarker[]
115
     */
116
    public function getPostSaveClassListeners()
117
    {
118
        return $this->postSaveClassListeners;
119
    }
120
121
    /**
122
     * @return bool
123
     */
124
    public function hasPostDeleteClassListeners()
125
    {
126
        return count($this->postDeleteClassListeners) > 0;
127
    }
128
129
    /**
130
     * @return ClassPostDeleteListenerMarker[]
131
     */
132
    public function getPostDeleteClassListeners()
133
    {
134
        return $this->postDeleteClassListeners;
135
    }
136
137 1
    private function initialize()
138
    {
139
        // setup and modify the id-marker
140 1
        $this->setUpIdMarker();
141
142
        // setup and modify markers with database-relations
143 1
        $this->setUpDbReferenceMarkers();
144
145
        // setup property live-cycle event listeners
146 1
        $this->setUpPreSaveVisits();
147
148
        // setup class live-cycle event listeners
149 1
        $this->setUpPostSaveClassListeners();
150 1
        $this->setUpPostDeleteClassListeners();
151
152
        // setup indexes
153 1
        $this->setUpIndexedProperties();
154 1
        $this->setUpCompoundIndexes();
155 1
    }
156
157 1
    private function setUpIdMarker()
158
    {
159
        // we modify the property markers if we find an AsId::class
160
161 1
        $this->markedProperties = Psi::it($this->getMarkedProperties())
162 1
            ->filter(new IsInstanceOf(PropertyMarkedForSlumber::class))
163
            ->map(function (PropertyMarkedForSlumber $p) {
164
165
                // search for the first AsId marker and modify it
166 1
                if ($this->idMarker === null && $p->getFirstMarkerOf(AsId::class)) {
167
                    // remember the property marked as primary id
168
                    return $this->idMarker = $p->withAlias('_id')->withMapper(new PrimaryIdMapper($p->mapper->getOptions()));
169
                }
170
171
                // return unmodified
172 1
                return $p;
173 1
            })
174 1
            ->toArray();
175 1
    }
176
177 1
    private function setUpDbReferenceMarkers()
178
    {
179 1
        $this->markedProperties = Psi::it($this->getMarkedProperties())
180 1
            ->filter(new IsInstanceOf(PropertyMarkedForSlumber::class))
181
            ->map(function (PropertyMarkedForSlumber $p) {
182
183
                /** @var AsDbReference $asDbRef */
184 1
                $asDbRef = $p->getFirstMarkerOf(AsDbReference::class);
185
186
                // do we have a AsDbReference marker ?
187 1
                if ($asDbRef) {
188
189
                    // is it accompanied by an AsObject marker ?
190
                    /** @var AsObject $asObj */
191
                    $asObj = $p->getFirstMarkerOf(AsObject::class);
192
193
                    if ($asObj) {
194
                        // we need the actual object
195
                        $asDbRef->setObjectOptions($asObj);
196
197
                        // return the modified marker
198
                        return $p->withMapper(new DbReferenceMapper($asDbRef));
199
                    }
200
201
                    // is it a collection and has an ObjectMapper as leave? Then we replace t
202
                    if ($p->mapper instanceof CollectionMapper && $p->mapper->isLeaveOfType(ObjectMapper::class)) {
203
204
                        /** @var ObjectMapper $leaf */
205
                        $leaf = $p->mapper->getLeaf();
206
                        // set the options of the referenced object
207
                        $asDbRef->setObjectOptions($leaf->getOptions());
208
                        // replace the leave mapper
209
                        $p->mapper->setLeaf(new DbReferenceMapper($asDbRef));
210
211
                        // we must also wrap the out collection so that we can un-wrap the LazyDbReferences
212
                        if ($asDbRef->lazy) {
213
                            $p->mapper->setLeafParentsCollectionType(LazyDbReferenceCollection::class);
214
                        }
215
216
                        // when the collection only has one child (Any Slumber\As...) we have to replace the mapper itself
217
                        if ($p->mapper->getNestingLevel() === 1) {
218
                            /** @noinspection PhpParamsInspection */
219
                            $p->mapper = new DbReferenceCollectionMapper($p->mapper);
220
                        }
221
                        // else {
222
                        // TODO: to be implemented . We need to replace the mapper of the leafs grand-parent, just like above
223
                        //       it works without it but has a high performance impact
224
                        // }
225
226
                        return $p;
227
                    }
228
                }
229
230
                // return un-modified
231 1
                return $p;
232 1
            })
233 1
            ->toArray();
234 1
    }
235
236 1 View Code Duplication
    private function setUpPreSaveVisits()
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...
237
    {
238
        // set up the pre save property visits
239 1
        $this->preSaveVisits = array_merge(
240 1
            $this->preSaveVisits,
241 1
            Psi::it($this->getMarkedProperties())
242 1
                ->filter(new IsInstanceOf(PropertyMarkedForSlumber::class))
243
                ->filter(function (PropertyMarkedForSlumber $p) {
244 1
                    return $p->getFirstMarkerOf(PropertyPreSaveVisitorMarker::class) !== null;
245 1
                })
246
                ->map(function (PropertyMarkedForSlumber $p) {
247
                    $res               = new PropertyMarkedForPreSaveVisit();
248
                    $res->propertyName = $p->name;
249
                    $res->markers      = $p->getMarkersOf(PropertyPreSaveVisitorMarker::class);
250
251
                    return $res;
252 1
                })
253 1
                ->toArray()
254
        );
255 1
    }
256
257 1
    private function setUpPostSaveClassListeners()
258
    {
259 1
        $this->postSaveClassListeners = array_merge(
260 1
            $this->postSaveClassListeners,
261 1
            Psi::it($this->getMarkersOnClass())
262 1
                ->filter(new IsInstanceOf(ClassPostSaveListenerMarker::class))
263 1
                ->toArray()
264
        );
265 1
    }
266
267 1
    private function setUpPostDeleteClassListeners()
268
    {
269 1
        $this->postDeleteClassListeners = array_merge(
270 1
            $this->postDeleteClassListeners,
271 1
            Psi::it($this->getMarkersOnClass())
272 1
                ->filter(new IsInstanceOf(ClassPostDeleteListenerMarker::class))
273 1
                ->toArray()
274
        );
275 1
    }
276
277 1 View Code Duplication
    private function setUpIndexedProperties()
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...
278
    {
279
        // get indexed properties
280
        // TODO: write tests
281 1
        $this->indexedProperties = array_merge(
282 1
            $this->indexedProperties,
283 1
            Psi::it($this->getMarkedProperties())
284 1
                ->filter(new IsInstanceOf(PropertyMarkedForSlumber::class))
285
                ->filter(function (PropertyMarkedForSlumber $p) {
286 1
                    return $p->getFirstMarkerOf(PropertyStorageIndexMarker::class) !== null;
287 1
                })
288 1
                ->map(function (PropertyMarkedForSlumber $p) {
289
                    $res               = new PropertyMarkedForIndexing();
290
                    $res->propertyName = $p->name;
291
                    $res->markers      = $p->getMarkersOf(PropertyStorageIndexMarker::class);
292
293
                    return $res;
294 1
                })
295 1
                ->toArray()
296
        );
297 1
    }
298
299 1
    private function setUpCompoundIndexes()
300
    {
301
        // get compound indexes
302
        // TODO: write tests
303 1
        $this->compoundIndexes = array_merge(
304 1
            $this->compoundIndexes,
305 1
            Psi::it($this->getMarkersOnClass())
306 1
                ->filter(new IsInstanceOf(ClassMarker::class))
307 1
                ->filter(new IsInstanceOf(CompoundIndexDefinition::class))
308 1
                ->toArray()
309
        );
310 1
    }
311
}
312