MongoDbEntityConfig::getCompoundIndexes()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
249
250
                    return $res;
251 2
                })
252 2
                ->toArray()
253
        );
254 2
    }
255
256 2
    private function setUpPostSaveClassListeners()
257
    {
258 2
        $this->postSaveClassListeners = array_merge(
259 2
            $this->postSaveClassListeners,
260 2
            Psi::it($this->getMarkersOnClass())
261 2
                ->filter(new Psi\IsInstanceOf(ClassPostSaveListenerMarker::class))
262 2
                ->toArray()
263
        );
264 2
    }
265
266 2
    private function setUpPostDeleteClassListeners()
267
    {
268 2
        $this->postDeleteClassListeners = array_merge(
269 2
            $this->postDeleteClassListeners,
270 2
            Psi::it($this->getMarkersOnClass())
271 2
                ->filter(new Psi\IsInstanceOf(ClassPostDeleteListenerMarker::class))
272 2
                ->toArray()
273
        );
274 2
    }
275
276 2 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...
277
    {
278
        // get indexed properties
279
        // TODO: write tests
280 2
        $this->indexedProperties = array_merge(
281 2
            $this->indexedProperties,
282 2
            Psi::it($this->getMarkedProperties())
283 2
                ->filter(new Psi\IsInstanceOf(PropertyMarkedForSlumber::class))
284 2
                ->filter(function (PropertyMarkedForSlumber $p) {
285 2
                    return $p->getFirstMarkerOf(PropertyStorageIndexMarker::class) !== null;
286 2
                })
287 2
                ->map(function (PropertyMarkedForSlumber $p) {
288
                    $res               = new PropertyMarkedForIndexing();
289
                    $res->propertyName = $p->name;
290
                    $res->markers      = $p->getMarkersOf(PropertyStorageIndexMarker::class);
0 ignored issues
show
Documentation Bug introduced by
It seems like $p->getMarkersOf(\PeekAn...rageIndexMarker::class) of type array<integer,object<Pee...tation\PropertyMarker>> is incompatible with the declared type array<integer,object<Pee...rtyStorageIndexMarker>> of property $markers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
291
292
                    return $res;
293 2
                })
294 2
                ->toArray()
295
        );
296 2
    }
297
298 2
    private function setUpCompoundIndexes()
299
    {
300
        // get compound indexes
301
        // TODO: write tests
302 2
        $this->compoundIndexes = array_merge(
303 2
            $this->compoundIndexes,
304 2
            Psi::it($this->getMarkersOnClass())
305 2
                ->filter(new Psi\IsInstanceOf(ClassMarker::class))
306 2
                ->filter(new Psi\IsInstanceOf(CompoundIndexDefinition::class))
307 2
                ->toArray()
308
        );
309 2
    }
310
}
311