Passed
Push — main ( 3aa672...0dc4a1 )
by Proyecto
08:04
created

SQLiteRepository::commit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace ProyectoTAU\TAU\Common;
4
5
use PDO;
6
use PDOException;
7
use ProyectoTAU\TAU\Module\Administration\User\Domain\User;
8
use ProyectoTAU\TAU\Module\Administration\Group\Domain\Group;
9
use ProyectoTAU\TAU\Module\Administration\Role\Domain\Role;
10
use ProyectoTAU\TAU\Module\Administration\Module\Domain\Module;
11
12
/*
13
 * @see https://phpenthusiast.com/blog/the-singleton-design-pattern-in-php
14
 */
15
16
// General singleton class.
17
class SQLiteRepository implements Repository
18
{
19
    // Hold the class instance.
20
    private static ?Repository $instance = null;
21
    private static ?PDO $db = null;
22
23
    // Primary Keys Cache
24
    private $userDataStore = [];
25
    private $groupDataStore = [];
26
    private $roleDataStore = [];
27
    private $moduleDataStore = [];
28
29
    // The constructor is private
30
    // to prevent initiation with outer code.
31
    private function __construct()
32
    {
33
        // The expensive process (e.g.,db connection) goes here.
34
        $dbname = __DIR__ . '/admin.sqlite3';
35
        try {
36
            self::$db = new PDO('sqlite:' . $dbname);
37
            self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
38
            //self::$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
39
        } catch (PDOException $e) {
40
            die($e->getMessage().' ('.$dbname.')');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
41
        }
42
    }
43
44
    // The object is created from within the class itself
45
    // only if the class has no instance.
46
    public static function getInstance(): Repository
47
    {
48
        if (self::$instance == null)
49
        {
50
            self::$instance = new static();
51
        }
52
53
        return self::$instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::instance could return the type null which is incompatible with the type-hinted return ProyectoTAU\TAU\Common\Repository. Consider adding an additional type-check to rule them out.
Loading history...
54
    }
55
56
    /*
57
     * Transactions
58
     */
59
    public function begin(): void
60
    {
61
        self::$db->beginTransaction();
0 ignored issues
show
Bug introduced by
The method beginTransaction() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        self::$db->/** @scrutinizer ignore-call */ 
62
                   beginTransaction();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
62
    }
63
64
    public function commit(): void
65
    {
66
        self::$db->commit();
67
    }
68
69
    public function rollBack(): void
70
    {
71
        self::$db->rollBack();
72
    }
73
74
75
    /*
76
     * @see https://www.tutorialspoint.com/sqlite/sqlite_truncate_table.htm
77
     */
78
    public function clearUser(): void
79
    {
80
        $ps = self::$db->query('DELETE FROM user_group;');
81
        $this->executeOrFail($ps);
82
        $ps = self::$db->query('DELETE FROM User;');
83
        $this->executeOrFail($ps);
84
    }
85
86
    public function clearGroup(): void
87
    {
88
        $ps = self::$db->query('DELETE FROM user_group;');
89
        $this->executeOrFail($ps);
90
        $ps = self::$db->query('DELETE FROM group_role;');
91
        $this->executeOrFail($ps);
92
        $ps = self::$db->query('DELETE FROM "Group";');
93
        $this->executeOrFail($ps);
94
    }
95
96
    public function clearRole(): void
97
    {
98
        $ps = self::$db->query('DELETE FROM group_role;');
99
        $this->executeOrFail($ps);
100
        $ps = self::$db->query('DELETE FROM role_module;');
101
        $this->executeOrFail($ps);
102
        $ps = self::$db->query('DELETE FROM Role;');
103
        $this->executeOrFail($ps);
104
    }
105
106
    public function clearModule(): void
107
    {
108
        $ps = self::$db->query('DELETE FROM role_module;');
109
        $this->executeOrFail($ps);
110
        $ps = self::$db->query('DELETE FROM Module;');
111
        $this->executeOrFail($ps);
112
    }
113
114
    /*
115
     * User
116
     */
117
118
    public function createUser(User $user): void
119
    {
120
        $ps = self::$db->prepare('INSERT INTO User (user_id, name, surname, login)'.
121
                                            ' VALUES(:user_id, :name, :surname, :login);');
122
        $this->executeOrFail($ps, [
123
            ':user_id' => $user->getId(),
124
            ':name' => $user->getName(),
125
            ':surname' => $user->getSurname(),
126
            ':login' => $user->getLogin()
127
        ]);
128
129
        $this->userDataStore[$user->getId()] = self::$db->lastInsertId();
130
    }
131
132
    public function readUser($id): User
133
    {
134
        $ps = self::$db->prepare('SELECT user_pk, user_id, name, surname, login FROM User WHERE user_id = :user_id;');
135
136
        $this->executeOrFail($ps, [':user_id' => $id]);
137
138
        $resultSet = $ps->fetch(PDO::FETCH_ASSOC);
139
        if( $resultSet === false )
140
            throw new \InvalidArgumentException("User with id = $id not found");
141
142
        $ref = new \ReflectionClass(User::class);
143
        $user = $this->castUser($ref->newInstanceWithoutConstructor());
144
145
        $user->setId($resultSet['user_id']);
146
        $user->setName($resultSet['name']);
147
        $user->setSurname($resultSet['surname']);
148
        $user->setLogin($resultSet['login']);
149
150
        $this->userDataStore[$user->getId()] = $resultSet['user_pk'];
151
152
        return $user;
153
    }
154
155
    public function updateUser($id, $name, $surname, $login): void
156
    {
157
        $ps = self::$db->prepare('UPDATE User SET '.
158
                                            'name = :name,'.
159
                                            'surname = :surname,'.
160
                                            'login = :login'.
161
                                            ' WHERE user_id = :user_id;');
162
163
        $this->executeOrFail($ps, [
164
            ':user_id' => $id,
165
            ':name' => $name,
166
            ':surname' => $surname,
167
            ':login' => $login
168
        ]);
169
    }
170
171
    public function deleteUser($id): void
172
    {
173
        $ps = self::$db->prepare('DELETE FROM User WHERE user_id = :user_id;');
174
175
        $this->executeOrFail($ps, [':user_id' => $id]);
176
177
        unset($this->userDataStore[$id]);
178
    }
179
180
    public function getGroupsFromUser(User $user): array
181
    {
182
        $ps = self::$db->prepare('SELECT group_pk, g.group_id, name, description FROM "Group" g'.
183
                                        ' INNER JOIN user_group rel ON g.group_pk = rel.group_fk'.
184
                                        ' WHERE rel.user_id = :user_id;');
185
186
        $resultSet = $this->queryOrFail($ps, [
187
            ':user_id' => $user->getid()
188
        ]);
189
190
        $groups = [];
191
        foreach ($resultSet as $entry) {
192
            $ref = new \ReflectionClass(Group::class);
193
            $group = $this->castGroup($ref->newInstanceWithoutConstructor());
194
195
            $group->setPropertiesBag(['id', 'name', 'desc']);
196
            $group->setSettersBag($group->getPropertiesBag());
197
198
            $group->setId($entry['group_id']);
199
            $group->setName($entry['name']);
200
            $group->setDesc($entry['description']);
201
202
            $groups[$entry['group_id']] = $group;
203
        }
204
205
        $available = array_diff_assoc($this->getAllGroups(), $groups);
206
        $r = [
207
            'belongsto' => $groups,
208
            'available' => $available
209
        ];
210
211
        return $r;
212
    }
213
214
    private function castUser($o): User
215
    {
216
        return $o;
217
    }
218
219
    private function castGroup($o): Group
220
    {
221
        return $o;
222
    }
223
224
    private function queryOrFail($ps, $params = [], $debug = 0): array
225
    {
226
        $this->executeOrFail($ps, $params, $debug);
227
        $resultSet =  $ps->fetchAll(PDO::FETCH_ASSOC);
228
229
        return $resultSet;
230
    }
231
232
    private function executeOrFail($ps, $params = [], $debug = 0): void
233
    {
234
        if($debug) { //TODO: toggle to enable
235
            $sql = $ps->queryString;
236
            $b = str_replace(array_keys($params), array_values($params), $sql);
237
            echo "\n$b\n";
238
        }
239
240
        try {
241
            $result = $ps->execute($params);
242
        } catch (PDOException $e){
243
            $result = false;
244
        }
245
246
        if( $result === false ) {
247
            $debug = 1;
248
            if($debug) {
249
                $sql = $ps->queryString;
250
                $b = str_replace(array_keys($params), array_values($params), $sql);
251
                echo "\n$b\n";
252
            }
253
            $errorInfo = $ps->errorInfo();
254
            $SQLSTATE_error_code = $errorInfo[0];
255
            $Driver_specific_error_code = $errorInfo[1];
256
            $Driver_specific_error_message = $errorInfo[2];
257
            throw new \Exception(
258
                '['.$SQLSTATE_error_code.'] '.$Driver_specific_error_message.
259
                ' (Driver specific error code: '.$Driver_specific_error_code.')',
260
                $SQLSTATE_error_code);
261
        }
262
    }
263
264
    private function getAllGroups(): array
265
    {
266
        $ps = self::$db->prepare('SELECT group_pk, group_id, group_id, name, description FROM "Group";');
267
268
        $resultSet = $this->queryOrFail($ps);
269
270
        $groups = [];
271
        foreach ($resultSet as $entry) {
272
            $ref = new \ReflectionClass(Group::class);
273
            $group = $this->castGroup($ref->newInstanceWithoutConstructor());
274
275
            $group->setPropertiesBag(['id', 'name', 'desc']);
276
            $group->setSettersBag($group->getPropertiesBag());
277
278
            $group->setId($entry['group_id']);
279
            $group->setName($entry['name']);
280
            $group->setDesc($entry['description']);
281
282
            $this->groupDataStore[$entry['group_id']] = $entry['group_pk'];
283
284
            $groups[$entry['group_id']] = $group;
285
        }
286
287
        return $groups;
288
    }
289
290
    public function createGroup(Group $group): void
291
    {
292
        $ps = self::$db->prepare('INSERT INTO "Group" (group_id, name, description)'.
293
                                            ' VALUES(:group_id, :name, :description);');
294
        $this->executeOrFail($ps, [
295
            ':group_id' => $group->getId(),
296
            ':name' => $group->getName(),
297
            ':description' => $group->getDesc()
298
        ]);
299
300
        $this->groupDataStore[$group->getId()] = self::$db->lastInsertId();
301
    }
302
303
    public function readGroup($id): Group
304
    {
305
        $ps = self::$db->prepare('SELECT group_pk, group_id, name, description FROM "Group" WHERE group_id = :group_id;');
306
307
        $this->executeOrFail($ps, [':group_id' => $id]);
308
309
        $resultSet = $ps->fetch(PDO::FETCH_ASSOC);
310
        if( $resultSet === false )
311
            throw new \InvalidArgumentException("Group with id = $id not found");
312
313
        $ref = new \ReflectionClass(Group::class);
314
        $group = $this->castGroup($ref->newInstanceWithoutConstructor());
315
316
        $group->setPropertiesBag(['id', 'name', 'desc']);
317
        $group->setSettersBag($group->getPropertiesBag());
318
319
        $group->setId($resultSet['group_id']);
320
        $group->setName($resultSet['name']);
321
        $group->setDesc($resultSet['description']);
322
323
        $this->groupDataStore[$group->getId()] = $resultSet['group_pk'];
324
325
        return $group;
326
    }
327
328
    public function updateGroup($id, $name, $desc): void
329
    {
330
        $ps = self::$db->prepare('UPDATE "Group" SET '.
331
                                            'name = :name,'.
332
                                            'description = :description'.
333
                                            ' WHERE group_id = :group_id;');
334
335
        $this->executeOrFail($ps, [
336
            ':group_id' => $id,
337
            ':name' => $name,
338
            ':description' => $desc
339
        ]);
340
    }
341
342
    public function deleteGroup($id): void
343
    {
344
        $ps = self::$db->prepare('DELETE FROM "Group" WHERE group_id = :group_id;');
345
346
        $this->executeOrFail($ps, [':group_id' => $id]);
347
348
        unset($this->groupDataStore[$id]);
349
    }
350
351
    public function getUsersFromGroup(Group $group): array
352
    {
353
        $ps = self::$db->prepare('SELECT user_pk, u.user_id, name, surname, login FROM User u'.
354
                                        ' INNER JOIN user_group rel ON u.user_pk = rel.user_fk'.
355
                                        ' WHERE rel.group_id = :group_id;');
356
357
        $resultSet = $this->queryOrFail($ps, [
358
            ':group_id' => $group->getId()
359
        ]);
360
361
        $users = [];
362
        foreach ($resultSet as $entry) {
363
            $ref = new \ReflectionClass(User::class);
364
            $user = $this->castUser($ref->newInstanceWithoutConstructor());
365
366
            $user->setId($entry['user_id']);
367
            $user->setName($entry['name']);
368
            $user->setSurname($entry['surname']);
369
            $user->setLogin($entry['login']);
370
371
            $users[$entry['user_id']] = $user;
372
        }
373
374
        $available = array_diff_assoc($this->getAllUsers(), $users);
375
        $r = [
376
            'members' => $users,
377
            'available' => $available
378
        ];
379
380
        return $r;
381
    }
382
383
    private function getAllUsers(): array
384
    {
385
        $ps = self::$db->prepare('SELECT user_pk, user_id, name, surname, login FROM User;');
386
387
        $resultSet = $this->queryOrFail($ps);
388
389
        $users = [];
390
        foreach ($resultSet as $entry) {
391
            $ref = new \ReflectionClass(User::class);
392
            $user = $this->castUser($ref->newInstanceWithoutConstructor());
393
394
            $user->setId($entry['user_id']);
395
            $user->setName($entry['name']);
396
            $user->setSurname($entry['surname']);
397
            $user->setLogin($entry['login']);
398
399
            $this->userDataStore[$entry['user_id']] = $entry['user_pk'];
400
401
            $users[$entry['user_id']] = $user;
402
        }
403
404
        return $users;
405
    }
406
407
    public function addUserToGroup(User $user, Group $group)
408
    {
409
        $ps = self::$db->prepare('INSERT INTO user_group (user_fk, group_fk, user_id, group_id)'.
410
                                        ' VALUES (:user_fk, :group_fk, :user_id, :group_id);');
411
412
        $this->executeOrFail($ps, [
413
            ':user_fk' => $this->userDataStore[$user->getId()],
414
            ':group_fk' => $this->groupDataStore[$group->getId()],
415
            ':user_id' => $user->getId(),
416
            ':group_id' => $group->getId()
417
        ]);
418
    }
419
420
    public function removeUserFromGroup(User $user, Group $group)
421
    {
422
        $ps = self::$db->prepare('DELETE FROM user_group'.
423
                                        ' WHERE user_id = :user_id'.
424
                                        ' AND group_id = :group_id;');
425
426
        $this->executeOrFail($ps, [
427
            ':user_id' => $user->getId(),
428
            ':group_id' => $group->getId()
429
        ]);
430
    }
431
432
    public function createRole(Role $role): void
433
    {
434
        $ps = self::$db->prepare('INSERT INTO Role (role_id, name, description)'.
435
                                        ' VALUES(:role_id, :name, :description);');
436
437
        $this->executeOrFail($ps, [
438
            ':role_id' => $role->getId(),
439
            ':name' => $role->getName(),
440
            ':description' => $role->getDesc()
441
        ]);
442
443
        $this->roleDataStore[$role->getId()] = self::$db->lastInsertId();
444
    }
445
446
    public function readRole($id): Role
447
    {
448
        $ps = self::$db->prepare('SELECT role_pk, role_id, name, description FROM Role WHERE role_id = :role_id;');
449
450
        $this->executeOrFail($ps, [':role_id' => $id]);
451
452
        $resultSet = $ps->fetch(PDO::FETCH_ASSOC);
453
        if( $resultSet === false )
454
            throw new \InvalidArgumentException("Role with id = $id not found");
455
456
        $ref = new \ReflectionClass(Role::class);
457
        $role = $this->castRole($ref->newInstanceWithoutConstructor());
458
459
        $role->setPropertiesBag(['id', 'name', 'desc']);
460
        $role->setSettersBag($role->getPropertiesBag());
461
462
        $role->setId($resultSet['role_id']);
463
        $role->setName($resultSet['name']);
464
        $role->setDesc($resultSet['description']);
465
466
        $this->roleDataStore[$role->getId()] = $resultSet['role_pk'];
467
468
        return $role;
469
    }
470
471
    private function castRole($o): Role
472
    {
473
        return $o;
474
    }
475
476
    public function addGroupToRole(Group $group, Role $role)
477
    {
478
        $ps = self::$db->prepare('INSERT INTO group_role (group_fk, role_fk, group_id, role_id)'.
479
                                        ' VALUES (:group_fk, :role_fk, :group_id, :role_id);');
480
481
        $this->executeOrFail($ps, [
482
            ':group_fk' => $this->groupDataStore[$group->getId()],
483
            ':role_fk' => $this->roleDataStore[$role->getId()],
484
            ':group_id' => $group->getId(),
485
            ':role_id' => $role->getId()
486
        ]);
487
    }
488
489
    public function getGroupsFromRole(Role $role): array
490
    {
491
        $ps = self::$db->prepare('SELECT group_pk, g.group_id, name, description FROM "Group" g'.
492
                                        ' INNER JOIN group_role rel ON g.group_pk = rel.group_fk'.
493
                                        ' WHERE rel.role_id = :role_id;');
494
495
        $resultSet = $this->queryOrFail($ps, [
496
            ':role_id' => $role->getId()
497
        ]);
498
499
        $groups = [];
500
        foreach ($resultSet as $entry) {
501
            $ref = new \ReflectionClass(Group::class);
502
            $group = $this->castGroup($ref->newInstanceWithoutConstructor());
503
504
            $group->setPropertiesBag(['id', 'name', 'desc']);
505
            $group->setSettersBag($group->getPropertiesBag());
506
507
            $group->setId($entry['group_id']);
508
            $group->setName($entry['name']);
509
            $group->setDesc($entry['description']);
510
511
            $groups[$entry['group_id']] = $group;
512
        }
513
514
        $available = array_diff_assoc($this->getAllGroups(), $groups);
515
        $r = [
516
            'grantedby' => $groups,
517
            'available' => $available
518
        ];
519
520
        return $r;
521
    }
522
523
    public function removeGroupFromRole(Group $group, Role $role)
524
    {
525
        $ps = self::$db->prepare('DELETE FROM group_role'.
526
                                        ' WHERE group_id = :group_id'.
527
                                        ' AND role_id = :role_id;');
528
529
        $this->executeOrFail($ps, [
530
            ':group_id' => $group->getId(),
531
            ':role_id' => $role->getId()
532
        ]);
533
    }
534
535
    public function addGroupToUser(Group $group, User $user)
536
    {
537
        $ps = self::$db->prepare('INSERT INTO user_group (user_fk, group_fk, user_id, group_id)'.
538
                                        ' VALUES (:user_fk, :group_fk, :user_id, :group_id);');
539
540
        $this->executeOrFail($ps, [
541
            ':user_fk' => $this->userDataStore[$user->getId()],
542
            ':group_fk' => $this->groupDataStore[$group->getId()],
543
            ':user_id' => $user->getId(),
544
            ':group_id' => $group->getId()
545
        ]);
546
    }
547
548
    public function removeGroupFromUser(Group $group, User $user)
549
    {
550
        $ps = self::$db->prepare('DELETE FROM user_group'.
551
                                        ' WHERE user_id = :user_id'.
552
                                        ' AND group_id = :group_id;');
553
554
        $this->executeOrFail($ps, [
555
            ':user_id' => $user->getId(),
556
            ':group_id' => $group->getId()
557
        ]);
558
    }
559
560
    public function updateRole($id, $name, $desc): void
561
    {
562
        $ps = self::$db->prepare('UPDATE Role SET '.
563
                                        'name = :name,'.
564
                                        'description = :description'.
565
                                        ' WHERE role_id = :role_id;');
566
567
        $this->executeOrFail($ps, [
568
            ':role_id' => $id,
569
            ':name' => $name,
570
            ':description' => $desc
571
        ]);
572
    }
573
574
    public function deleteRole($id): void
575
    {
576
        $ps = self::$db->prepare('DELETE FROM Role WHERE role_id = :role_id;');
577
578
        $this->executeOrFail($ps, [
579
            ':role_id' => $id
580
        ]);
581
582
        unset($this->roleDataStore[$id]);
583
    }
584
585
    public function addRoleToGroup(Role $role, Group $group)
586
    {
587
        $ps = self::$db->prepare('INSERT INTO group_role (group_fk, role_fk, group_id, role_id)'.
588
                                        ' VALUES (:group_fk, :role_fk, :group_id, :role_id);');
589
590
        $this->executeOrFail($ps, [
591
            ':group_fk' => $this->groupDataStore[$group->getId()],
592
            ':role_fk' => $this->roleDataStore[$role->getId()],
593
            ':group_id' => $group->getId(),
594
            ':role_id' => $role->getId()
595
        ]);
596
    }
597
598
    public function getRolesFromGroup(Group $group): array
599
    {
600
        $ps = self::$db->prepare('SELECT role_pk, r.role_id, name, description FROM Role r'.
601
                                        ' INNER JOIN group_role rel ON r.role_pk = rel.role_fk'.
602
                                        ' WHERE rel.group_id = :group_id;');
603
604
        $resultSet = $this->queryOrFail($ps, [
605
            ':group_id' => $group->getId()
606
        ]);
607
608
        $roles = [];
609
        foreach ($resultSet as $entry) {
610
            $ref = new \ReflectionClass(Role::class);
611
            $role = $this->castRole($ref->newInstanceWithoutConstructor());
612
613
            $role->setPropertiesBag(['id', 'name', 'desc']);
614
            $role->setSettersBag($role->getPropertiesBag());
615
616
            $role->setId($entry['role_id']);
617
            $role->setName($entry['name']);
618
            $role->setDesc($entry['description']);
619
620
            $roles[$entry['role_id']] = $role;
621
        }
622
623
        $available = array_diff_assoc($this->getAllRoles(), $roles);
624
        $r = [
625
            'plays' => $roles,
626
            'available' => $available
627
        ];
628
629
        return $r;
630
    }
631
632
    private function getAllRoles(): array
633
    {
634
        $ps = self::$db->prepare('SELECT role_pk, role_id, role_id, name, description FROM Role;');
635
636
        $resultSet = $this->queryOrFail($ps);
637
638
        $roles = [];
639
        foreach ($resultSet as $entry) {
640
            $ref = new \ReflectionClass(Role::class);
641
            $role = $this->castRole($ref->newInstanceWithoutConstructor());
642
643
            $role->setPropertiesBag(['id', 'name', 'desc']);
644
            $role->setSettersBag($role->getPropertiesBag());
645
646
            $role->setId($entry['role_id']);
647
            $role->setName($entry['name']);
648
            $role->setDesc($entry['description']);
649
650
            $this->roleDataStore[$entry['role_id']] = $entry['role_pk'];
651
652
            $roles[$entry['role_id']] = $role;
653
        }
654
655
        return $roles;
656
    }
657
658
    public function removeRoleFromGroup(Role $role, Group $group)
659
    {
660
        $ps = self::$db->prepare('DELETE FROM group_role'.
661
                                        ' WHERE role_id = :role_id'.
662
                                        ' AND group_id = :group_id;');
663
664
        $this->executeOrFail($ps, [
665
            ':role_id' => $role->getId(),
666
            ':group_id' => $group->getId()
667
        ]);
668
    }
669
670
    public function addModuleToRole(Module $module, Role $role)
671
    {
672
        $ps = self::$db->prepare('INSERT INTO role_module (role_fk, module_fk, role_id, module_id)'.
673
                                        ' VALUES (:role_fk, :module_fk, :role_id, :module_id);');
674
675
        $this->executeOrFail($ps, [
676
            ':role_fk' => $this->roleDataStore[$role->getId()],
677
            ':module_fk' => $this->moduleDataStore[$module->getId()],
678
            ':role_id' => $role->getId(),
679
            ':module_id' => $module->getId()
680
        ]);
681
    }
682
683
    public function removeModuleFromRole(Module $module, Role $role)
684
    {
685
        $ps = self::$db->prepare('DELETE FROM role_module'.
686
                                        ' WHERE role_id = :role_id'.
687
                                        ' AND module_id = :module_id;');
688
689
        $this->executeOrFail($ps, [
690
            ':module_id' => $module->getId(),
691
            ':role_id' => $role->getId()
692
        ]);
693
    }
694
695
    public function getModulesFromRole(Role $role): array
696
    {
697
        $ps = self::$db->prepare('SELECT module_pk, m.module_id, name, description FROM Module m'.
698
                                        ' INNER JOIN role_module rel ON m.module_pk = rel.module_fk'.
699
                                        ' WHERE rel.role_id = :role_id;');
700
701
        $resultSet = $this->queryOrFail($ps, [
702
            ':role_id' => $role->getId()
703
        ]);
704
705
        $modules = [];
706
        foreach ($resultSet as $entry) {
707
            $ref = new \ReflectionClass(Module::class);
708
            $module = $this->castModule($ref->newInstanceWithoutConstructor());
709
710
            $module->setPropertiesBag(['id', 'name', 'desc']);
711
            $module->setSettersBag($module->getPropertiesBag());
712
713
            $module->setId($entry['module_id']);
714
            $module->setName($entry['name']);
715
            $module->setDesc($entry['description']);
716
717
            $modules[$entry['module_id']] = $module;
718
        }
719
720
        $available = array_diff_assoc($this->getAllModules(), $modules);
721
        $r = [
722
            'canrun' => $modules,
723
            'available' => $available
724
        ];
725
726
        return $r;
727
    }
728
729
    private function castModule($o): Module
730
    {
731
        return $o;
732
    }
733
734
    private function getAllModules()
735
    {
736
        $ps = self::$db->prepare('SELECT module_pk, module_id, module_id, name, description FROM Module;');
737
738
        $resultSet = $this->queryOrFail($ps);
739
740
        $modules = [];
741
        foreach ($resultSet as $entry) {
742
            $ref = new \ReflectionClass(Module::class);
743
            $module = $this->castModule($ref->newInstanceWithoutConstructor());
744
745
            $module->setPropertiesBag(['id', 'name', 'desc']);
746
            $module->setSettersBag($module->getPropertiesBag());
747
748
            $module->setId($entry['module_id']);
749
            $module->setName($entry['name']);
750
            $module->setDesc($entry['description']);
751
752
            $this->moduleDataStore[$entry['module_id']] = $entry['module_pk'];
753
754
            $modules[$entry['module_id']] = $module;
755
        }
756
757
        return $modules;
758
    }
759
760
    public function createModule(Module $module): void
761
    {
762
        $ps = self::$db->prepare('INSERT INTO Module (module_id, name, description)'.
763
                                        ' VALUES(:module_id, :name, :description);');
764
        $this->executeOrFail($ps, [
765
            ':module_id' => $module->getId(),
766
            ':name' => $module->getName(),
767
            ':description' => $module->getDesc()
768
        ]);
769
770
        $this->moduleDataStore[$module->getId()] = self::$db->lastInsertId();
771
    }
772
773
    public function readModule($id): Module
774
    {
775
        $ps = self::$db->prepare('SELECT module_pk, module_id, name, description FROM Module'.
776
                                        ' WHERE module_id = :module_id;');
777
778
        $this->executeOrFail($ps, [
779
            ':module_id' => $id
780
        ]);
781
782
        $resultSet = $ps->fetch(PDO::FETCH_ASSOC);
783
        if( $resultSet === false )
784
            throw new \InvalidArgumentException("Module with id = $id not found");
785
786
        $ref = new \ReflectionClass(Module::class);
787
        $module = $this->castModule($ref->newInstanceWithoutConstructor());
788
789
        $module->setPropertiesBag(['id', 'name', 'desc']);
790
        $module->setSettersBag($module->getPropertiesBag());
791
792
        $module->setId($resultSet['module_id']);
793
        $module->setName($resultSet['name']);
794
        $module->setDesc($resultSet['description']);
795
796
        $this->moduleDataStore[$module->getId()] = $resultSet['module_pk'];
797
798
        return $module;
799
    }
800
801
    public function updateModule($id, $name, $desc): void
802
    {
803
        $ps = self::$db->prepare('UPDATE Module SET '.
804
                                        'name = :name,'.
805
                                        'description = :description'.
806
                                        ' WHERE module_id = :module_id;');
807
808
        $this->executeOrFail($ps, [
809
            ':module_id' => $id,
810
            ':name' => $name,
811
            ':description' => $desc
812
        ]);
813
    }
814
815
    public function deleteModule($id): void
816
    {
817
        $ps = self::$db->prepare('DELETE FROM Module WHERE module_id = :module_id;');
818
819
        $this->executeOrFail($ps, [
820
            ':module_id' => $id
821
        ]);
822
823
        unset($this->moduleDataStore[$id]);
824
    }
825
826
    public function addRoleToModule(Role $role, Module $module)
827
    {
828
        $this->addModuleToRole($module, $role);
829
    }
830
831
    public function removeRoleFromModule(Role $role, Module $module)
832
    {
833
        $this->removeModuleFromRole($module, $role);
834
    }
835
836
    public function getRolesFromModule(Module $module): array
837
    {
838
        $ps = self::$db->prepare('SELECT role_pk, r.role_id, name, description FROM Role r'.
839
                                        ' INNER JOIN role_module rel ON r.role_pk = rel.role_fk'.
840
                                        ' WHERE rel.module_id = :module_id;');
841
842
        $resultSet = $this->queryOrFail($ps, [
843
            ':module_id' => $module->getId()
844
        ]);
845
846
        $roles = [];
847
        foreach ($resultSet as $entry) {
848
            $ref = new \ReflectionClass(Role::class);
849
            $role = $this->castRole($ref->newInstanceWithoutConstructor());
850
851
            $role->setPropertiesBag(['id', 'name', 'desc']);
852
            $role->setSettersBag($role->getPropertiesBag());
853
854
            $role->setId($entry['role_id']);
855
            $role->setName($entry['name']);
856
            $role->setDesc($entry['description']);
857
858
            $roles[$entry['role_id']] = $role;
859
        }
860
861
        $available = array_diff_assoc($this->getAllRoles(), $roles);
862
        $r = [
863
            'authorizedby' => $roles,
864
            'available' => $available
865
        ];
866
867
        return $r;
868
    }
869
}
870