Completed
Pull Request — feature/update-inst-conf-aggre... (#233)
by Michiel
04:34 queued 02:20
created

InstitutionConfiguration::rebuild()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 9.472
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * Copyright 2016 SURFnet B.V.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\Stepup\Configuration;
20
21
use Broadway\EventSourcing\EventSourcedAggregateRoot;
22
use Surfnet\Stepup\Configuration\Api\InstitutionConfiguration as InstitutionConfigurationInterface;
23
use Surfnet\Stepup\Configuration\Entity\RaLocation;
24
use Surfnet\Stepup\Configuration\Event\AllowedSecondFactorListUpdatedEvent;
25
use Surfnet\Stepup\Configuration\Event\InstitutionConfigurationRemovedEvent;
26
use Surfnet\Stepup\Configuration\Event\NewInstitutionConfigurationCreatedEvent;
27
use Surfnet\Stepup\Configuration\Event\NumberOfTokensPerIdentityOptionChangedEvent;
28
use Surfnet\Stepup\Configuration\Event\RaLocationAddedEvent;
29
use Surfnet\Stepup\Configuration\Event\RaLocationContactInformationChangedEvent;
30
use Surfnet\Stepup\Configuration\Event\RaLocationRelocatedEvent;
31
use Surfnet\Stepup\Configuration\Event\RaLocationRemovedEvent;
32
use Surfnet\Stepup\Configuration\Event\RaLocationRenamedEvent;
33
use Surfnet\Stepup\Configuration\Event\SelectRaaOptionChangedEvent;
34
use Surfnet\Stepup\Configuration\Event\ShowRaaContactInformationOptionChangedEvent;
35
use Surfnet\Stepup\Configuration\Event\UseRaaOptionChangedEvent;
36
use Surfnet\Stepup\Configuration\Event\UseRaLocationsOptionChangedEvent;
37
use Surfnet\Stepup\Configuration\Event\UseRaOptionChangedEvent;
38
use Surfnet\Stepup\Configuration\Event\VerifyEmailOptionChangedEvent;
39
use Surfnet\Stepup\Configuration\Value\AllowedSecondFactorList;
40
use Surfnet\Stepup\Configuration\Value\ContactInformation;
41
use Surfnet\Stepup\Configuration\Value\Institution;
42
use Surfnet\Stepup\Configuration\Value\InstitutionConfigurationId;
43
use Surfnet\Stepup\Configuration\Value\Location;
44
use Surfnet\Stepup\Configuration\Value\NumberOfTokensPerIdentityOption;
45
use Surfnet\Stepup\Configuration\Value\RaLocationId;
46
use Surfnet\Stepup\Configuration\Value\RaLocationList;
47
use Surfnet\Stepup\Configuration\Value\RaLocationName;
48
use Surfnet\Stepup\Configuration\Value\SelectRaaOption;
49
use Surfnet\Stepup\Configuration\Value\ShowRaaContactInformationOption;
50
use Surfnet\Stepup\Configuration\Value\UseRaaOption;
51
use Surfnet\Stepup\Configuration\Value\UseRaLocationsOption;
52
use Surfnet\Stepup\Configuration\Value\UseRaOption;
53
use Surfnet\Stepup\Configuration\Value\VerifyEmailOption;
54
use Surfnet\Stepup\Exception\DomainException;
55
56
/**
57
 * InstitutionConfiguration aggregate root
58
 *
59
 * Some things to know about this aggregate:
60
 *
61
 * 1. The aggregate is instantiated by InstitutionConfigurationCommandHandler by calling the
62
 *    handleReconfigureInstitutionConfigurationOptionsCommand method. It does so, not by using the projections to build
63
 *    the aggregate but by playing the events onto the aggregate.
64
 * 2. If one of the configuration options should be nullable, take a look at the applyUseRaOptionChangedEvent doc block
65
 *
66
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Events and value objects
67
 * @SuppressWarnings(PHPMD.TooManyMethods) AggregateRoot
68
 * @SuppressWarnings(PHPMD.TooManyPublicMethods) AggregateRoot
69
 */
70
class InstitutionConfiguration extends EventSourcedAggregateRoot implements InstitutionConfigurationInterface
71
{
72
    /**
73
     * @var InstitutionConfigurationId
74
     */
75
    private $institutionConfigurationId;
76
77
    /**
78
     * @var Institution
79
     */
80
    private $institution;
81
82
    /**
83
     * @var RaLocationList
84
     */
85
    private $raLocations;
86
87
    /**
88
     * @var UseRaLocationsOption
89
     */
90
    private $useRaLocationsOption;
91
92
    /**
93
     * @var ShowRaaContactInformationOption
94
     */
95
    private $showRaaContactInformationOption;
96
97
    /**
98
     * @var VerifyEmailOption
99
     */
100
    private $verifyEmailOption;
101
102
    /**
103
     * @var NumberOfTokensPerIdentityOption
104
     */
105
    private $numberOfTokensPerIdentityOption;
106
107
    /**
108
     * @var UseRaOption
109
     */
110
    private $useRaOption;
111
112
    /**
113
     * @var UseRaaOption
114
     */
115
116
    private $useRaaOption;
117
118
    /**
119
     * @var SelectRaaOption
120
     */
121
    private $selectRaaOption;
122
123
    /**
124
     * @var AllowedSecondFactorList
125
     */
126
    private $allowedSecondFactorList;
127
128
    /**
129
     * @var boolean
130
     */
131
    private $isMarkedAsDestroyed;
132
133
    /**
134
     * @param InstitutionConfigurationId $institutionConfigurationId
135
     * @param Institution $institution
136
     * @return InstitutionConfiguration
137
     */
138
    public static function create(InstitutionConfigurationId $institutionConfigurationId, Institution $institution)
139
    {
140
        $institutionConfiguration = new self;
141
        $institutionConfiguration->apply(
142
            new NewInstitutionConfigurationCreatedEvent(
143
                $institutionConfigurationId,
144
                $institution,
145
                UseRaLocationsOption::getDefault(),
146
                ShowRaaContactInformationOption::getDefault(),
147
                VerifyEmailOption::getDefault(),
148
                NumberOfTokensPerIdentityOption::getDefault(),
149
                UseRaOption::getDefault(),
150
                UseRaaOption::getDefault(),
151
                SelectRaaOption::getDefault()
152
            )
153
        );
154
        $institutionConfiguration->apply(new AllowedSecondFactorListUpdatedEvent(
155
            $institutionConfigurationId,
156
            $institution,
157
            AllowedSecondFactorList::blank()
158
        ));
159
160
        return $institutionConfiguration;
161
    }
162
163
    /**
164
     * @return InstitutionConfiguration
165
     */
166
    public function rebuild()
167
    {
168
        // We can only rebuild a destroyed InstitutionConfiguration, all other cases are not valid
169
        if ($this->isMarkedAsDestroyed !== true) {
170
            throw new DomainException('Cannot rebuild InstitutionConfiguration as it has not been destroyed');
171
        }
172
173
        $this->apply(
174
            new NewInstitutionConfigurationCreatedEvent(
175
                $this->institutionConfigurationId,
176
                $this->institution,
177
                UseRaLocationsOption::getDefault(),
178
                ShowRaaContactInformationOption::getDefault(),
179
                VerifyEmailOption::getDefault(),
180
                NumberOfTokensPerIdentityOption::getDefault(),
181
                UseRaOption::getDefault(),
182
                UseRaaOption::getDefault(),
183
                SelectRaaOption::getDefault()
184
            )
185
        );
186
        $this->apply(new AllowedSecondFactorListUpdatedEvent(
187
            $this->institutionConfigurationId,
188
            $this->institution,
189
            AllowedSecondFactorList::blank()
190
        ));
191
192
        return $this;
193
    }
194
195
    final public function __construct()
196
    {
197
    }
198
199
    public function configureUseRaLocationsOption(UseRaLocationsOption $useRaLocationsOption)
200
    {
201
        if ($this->useRaLocationsOption->equals($useRaLocationsOption)) {
202
            return;
203
        }
204
205
        $this->apply(
206
            new UseRaLocationsOptionChangedEvent(
207
                $this->institutionConfigurationId,
208
                $this->institution,
209
                $useRaLocationsOption
210
            )
211
        );
212
    }
213
214
    public function configureShowRaaContactInformationOption(ShowRaaContactInformationOption $showRaaContactInformationOption)
215
    {
216
        if ($this->showRaaContactInformationOption->equals($showRaaContactInformationOption)) {
217
            return;
218
        }
219
220
        $this->apply(
221
            new ShowRaaContactInformationOptionChangedEvent(
222
                $this->institutionConfigurationId,
223
                $this->institution,
224
                $showRaaContactInformationOption
225
            )
226
        );
227
    }
228
229
    public function configureVerifyEmailOption(VerifyEmailOption $verifyEmailOption)
230
    {
231
        if ($this->verifyEmailOption->equals($verifyEmailOption)) {
232
            return;
233
        }
234
235
        $this->apply(
236
            new VerifyEmailOptionChangedEvent(
237
                $this->institutionConfigurationId,
238
                $this->institution,
239
                $verifyEmailOption
240
            )
241
        );
242
    }
243
244
    public function configureNumberOfTokensPerIdentityOption(
245
        NumberOfTokensPerIdentityOption $numberOfTokensPerIdentityOption
246
    ) {
247
        if ($this->numberOfTokensPerIdentityOption->equals($numberOfTokensPerIdentityOption)) {
248
            return;
249
        }
250
251
        $this->apply(
252
            new NumberOfTokensPerIdentityOptionChangedEvent(
253
                $this->institutionConfigurationId,
254
                $this->institution,
255
                $numberOfTokensPerIdentityOption
256
            )
257
        );
258
    }
259
260
    public function configureUseRaOption(UseRaOption $useRaOption)
261
    {
262
        if ($this->useRaOption->equals($useRaOption)) {
263
            return;
264
        }
265
266
        $this->apply(
267
            new UseRaOptionChangedEvent(
268
                $this->institutionConfigurationId,
269
                $this->institution,
270
                $useRaOption
271
            )
272
        );
273
    }
274
275
    public function configureUseRaaOption(UseRaaOption $useRaaOption)
276
    {
277
        if ($this->useRaaOption->equals($useRaaOption)) {
278
            return;
279
        }
280
281
        $this->apply(
282
            new UseRaaOptionChangedEvent(
283
                $this->institutionConfigurationId,
284
                $this->institution,
285
                $useRaaOption
286
            )
287
        );
288
    }
289
290
    public function configureSelectRaaOption(SelectRaaOption $selectRaaOption)
291
    {
292
        if ($this->selectRaaOption->equals($selectRaaOption)) {
293
            return;
294
        }
295
296
        $this->apply(
297
            new SelectRaaOptionChangedEvent(
298
                $this->institutionConfigurationId,
299
                $this->institution,
300
                $selectRaaOption
301
            )
302
        );
303
    }
304
305
    public function updateAllowedSecondFactorList(AllowedSecondFactorList $allowedSecondFactorList)
306
    {
307
        // AllowedSecondFactorList can be null for InstitutionConfigurations for which this functionality did not exist
308
        if ($this->allowedSecondFactorList !== null
309
            && $this->allowedSecondFactorList->equals($allowedSecondFactorList)
310
        ) {
311
            return;
312
        }
313
314
        $this->apply(
315
            new AllowedSecondFactorListUpdatedEvent(
316
                $this->institutionConfigurationId,
317
                $this->institution,
318
                $allowedSecondFactorList
319
            )
320
        );
321
    }
322
323
    /**
324
     * @param RaLocationId $raLocationId
325
     * @param RaLocationName $raLocationName
326
     * @param Location $location
327
     * @param ContactInformation $contactInformation
328
     */
329
    public function addRaLocation(
330
        RaLocationId $raLocationId,
331
        RaLocationName $raLocationName,
332
        Location $location,
333
        ContactInformation $contactInformation
334
    ) {
335 View Code Duplication
        if ($this->raLocations->containsWithId($raLocationId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
336
            throw new DomainException(sprintf(
337
                'Cannot add RaLocation with RaLocationId "%s" to RaLocations of InstitutionConfiguration "%s":'
338
                . ' it is already present',
339
                $raLocationId,
340
                $this->getAggregateRootId()
341
            ));
342
        }
343
344
        $this->apply(new RaLocationAddedEvent(
345
            $this->institutionConfigurationId,
346
            $this->institution,
347
            $raLocationId,
348
            $raLocationName,
349
            $location,
350
            $contactInformation
351
        ));
352
    }
353
354
    /**
355
     * @param RaLocationId $raLocationId
356
     * @param RaLocationName $raLocationName
357
     * @param Location $location
358
     * @param ContactInformation $contactInformation
359
     */
360
    public function changeRaLocation(
361
        RaLocationId $raLocationId,
362
        RaLocationName $raLocationName,
363
        Location $location,
364
        ContactInformation $contactInformation
365
    ) {
366 View Code Duplication
        if (!$this->raLocations->containsWithId($raLocationId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
367
            throw new DomainException(sprintf(
368
                'Cannot change RaLocation with RaLocationId "%s" in RaLocations of InstitutionConfiguration "%s":'
369
                . ' it is not present',
370
                $raLocationId,
371
                $this->getAggregateRootId()
372
            ));
373
        }
374
375
        $raLocation = $this->raLocations->getById($raLocationId);
376
377
        if (!$raLocation->getName()->equals($raLocationName)) {
378
            $this->apply(
379
                new RaLocationRenamedEvent($this->institutionConfigurationId, $raLocationId, $raLocationName)
380
            );
381
        }
382
        if (!$raLocation->getLocation()->equals($location)) {
383
            $this->apply(
384
                new RaLocationRelocatedEvent($this->institutionConfigurationId, $raLocationId, $location)
385
            );
386
        }
387
        if (!$raLocation->getContactInformation()->equals($contactInformation)) {
388
            $this->apply(
389
                new RaLocationContactInformationChangedEvent(
390
                    $this->institutionConfigurationId,
391
                    $raLocationId,
392
                    $contactInformation
393
                )
394
            );
395
        }
396
    }
397
398
    /**
399
     * @param RaLocationId $raLocationId
400
     */
401
    public function removeRaLocation(RaLocationId $raLocationId)
402
    {
403 View Code Duplication
        if (!$this->raLocations->containsWithId($raLocationId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
404
            throw new DomainException(sprintf(
405
                'Cannot remove RaLocation with RaLocationId "%s" in RaLocations of InstitutionConfiguration "%s":'
406
                . ' it is not present',
407
                $raLocationId,
408
                $this->getAggregateRootId()
409
            ));
410
        }
411
412
        $this->apply(new RaLocationRemovedEvent($this->institutionConfigurationId, $raLocationId));
413
    }
414
415
    /**
416
     * @return void
417
     */
418
    public function destroy()
419
    {
420
        $this->apply(new InstitutionConfigurationRemovedEvent($this->institutionConfigurationId, $this->institution));
421
    }
422
423
    public function getAggregateRootId()
424
    {
425
        return $this->institutionConfigurationId;
426
    }
427
428
    protected function applyNewInstitutionConfigurationCreatedEvent(NewInstitutionConfigurationCreatedEvent $event)
429
    {
430
        $this->institutionConfigurationId      = $event->institutionConfigurationId;
431
        $this->institution                     = $event->institution;
432
        $this->useRaLocationsOption            = $event->useRaLocationsOption;
433
        $this->showRaaContactInformationOption = $event->showRaaContactInformationOption;
434
        $this->verifyEmailOption               = $event->verifyEmailOption;
435
        $this->numberOfTokensPerIdentityOption = $event->numberOfTokensPerIdentityOption;
436
437
        // Apply the FGA options
438
        $this->useRaOption = $event->useRaOption;
439
        $this->useRaaOption = $event->useRaaOption;
440
        $this->selectRaaOption = $event->selectRaaOption;
441
442
        $this->raLocations                     = new RaLocationList([]);
443
        $this->isMarkedAsDestroyed             = false;
444
    }
445
446
    /**
447
     * Apply the UseRaOptionChangedEvent
448
     *
449
     * To ensure the aggregate is correctly populated with the FGA options we ensure the UseRaOptionChangedEvent
450
     * can be applied on the aggregate. Refraining from doing this would result in the $this->useRaOption field only
451
     * being applied when applyNewInstitutionConfigurationCreatedEvent is called. And this might not be the case if
452
     * the fields where null'ed (removed from configuration).
453
     *
454
     * This also applies for applyUseRaaOptionChangedEvent & applySelectRaaOptionChangedEvent
455
     *
456
     * @param UseRaOptionChangedEvent $event
457
     */
458
    protected function applyUseRaOptionChangedEvent(UseRaOptionChangedEvent $event)
459
    {
460
        $this->useRaOption = $event->useRaOption;
461
    }
462
463
    protected function applyUseRaaOptionChangedEvent(UseRaaOptionChangedEvent $event)
464
    {
465
        $this->useRaaOption = $event->useRaaOption;
466
    }
467
468
    protected function applySelectRaaOptionChangedEvent(SelectRaaOptionChangedEvent $event)
469
    {
470
        $this->selectRaaOption = $event->selectRaaOption;
471
    }
472
473
    protected function applyUseRaLocationsOptionChangedEvent(UseRaLocationsOptionChangedEvent $event)
474
    {
475
        $this->useRaLocationsOption = $event->useRaLocationsOption;
476
    }
477
478
    protected function applyShowRaaContactInformationOptionChangedEvent(
479
        ShowRaaContactInformationOptionChangedEvent $event
480
    ) {
481
        $this->showRaaContactInformationOption = $event->showRaaContactInformationOption;
482
    }
483
484
    protected function applyVerifyEmailOptionChangedEvent(
485
        VerifyEmailOptionChangedEvent $event
486
    ) {
487
        $this->verifyEmailOption = $event->verifyEmailOption;
488
    }
489
490
    protected function applyNumberOfTokensPerIdentityOptionChangedEvent(
491
        NumberOfTokensPerIdentityOptionChangedEvent $event
492
    ) {
493
        $this->numberOfTokensPerIdentityOption = $event->numberOfTokensPerIdentityOption;
494
    }
495
496
    protected function applyAllowedSecondFactorListUpdatedEvent(AllowedSecondFactorListUpdatedEvent $event)
497
    {
498
        $this->allowedSecondFactorList = $event->allowedSecondFactorList;
499
    }
500
501
    protected function applyRaLocationAddedEvent(RaLocationAddedEvent $event)
502
    {
503
        $this->raLocations->add(
504
            RaLocation::create(
505
                $event->raLocationId,
506
                $event->raLocationName,
507
                $event->location,
508
                $event->contactInformation
509
            )
510
        );
511
    }
512
513
    protected function applyRaLocationRenamedEvent(RaLocationRenamedEvent $event)
514
    {
515
        $raLocation = $this->raLocations->getById($event->raLocationId);
516
        $raLocation->rename($event->raLocationName);
517
    }
518
519
    protected function applyRaLocationRelocatedEvent(RaLocationRelocatedEvent $event)
520
    {
521
        $raLocation = $this->raLocations->getById($event->raLocationId);
522
        $raLocation->relocate($event->location);
523
    }
524
525
    protected function applyRaLocationContactInformationChangedEvent(RaLocationContactInformationChangedEvent $event)
526
    {
527
        $raLocation = $this->raLocations->getById($event->raLocationId);
528
        $raLocation->changeContactInformation($event->contactInformation);
529
    }
530
531
    protected function applyRaLocationRemovedEvent(RaLocationRemovedEvent $event)
532
    {
533
        $this->raLocations->removeWithId($event->raLocationId);
534
    }
535
536
    /**
537
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
538
     * @param InstitutionConfigurationRemovedEvent $event
539
     */
540
    protected function applyInstitutionConfigurationRemovedEvent(InstitutionConfigurationRemovedEvent $event)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
541
    {
542
        // reset all configuration to defaults. This way, should it be rebuild, it seems like it is new again
543
        $this->raLocations                     = new RaLocationList([]);
544
        $this->useRaLocationsOption            = UseRaLocationsOption::getDefault();
545
        $this->showRaaContactInformationOption = ShowRaaContactInformationOption::getDefault();
546
        $this->verifyEmailOption               = VerifyEmailOption::getDefault();
547
        $this->numberOfTokensPerIdentityOption = NumberOfTokensPerIdentityOption::getDefault();
548
        $this->allowedSecondFactorList         = AllowedSecondFactorList::blank();
549
        $this->useRaOption = UseRaOption::getDefault();
550
        $this->useRaaOption = UseRaaOption::getDefault();
551
        $this->selectRaaOption = SelectRaaOption::getDefault();
552
553
        $this->isMarkedAsDestroyed             = true;
554
    }
555
}
556