• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FastyBird / simple-auth / 10065316629

23 Jul 2024 06:46PM UTC coverage: 63.636% (-5.7%) from 69.347%
10065316629

push

github

web-flow
Trying to fix memory leak (#14)

* Trying to fix memory leak

* Fixing entity mapping

36 of 118 new or added lines in 4 files covered. (30.51%)

10 existing lines in 3 files now uncovered.

539 of 847 relevant lines covered (63.64%)

5.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.31
/src/Models/Casbin/Adapter.php
1
<?php declare(strict_types = 1);
2

3
/**
4
 * Adapter.php
5
 *
6
 * @license        More in LICENSE.md
7
 * @copyright      https://www.fastybird.com
8
 * @author         Adam Kadlec <adam.kadlec@fastybird.com>
9
 * @package        FastyBird:SimpleAuth!
10
 * @subpackage     Models
11
 * @since          0.1.0
12
 *
13
 * @date           09.07.24
14
 */
15

16
namespace FastyBird\SimpleAuth\Models\Casbin;
17

18
use Casbin\Model as CasbinModel;
19
use Casbin\Persist as CasbinPersist;
20
use Closure;
21
use Doctrine\DBAL;
22
use FastyBird\SimpleAuth\Exceptions;
23
use FastyBird\SimpleAuth\Models;
24
use FastyBird\SimpleAuth\Types;
25
use Ramsey\Uuid;
26
use Throwable;
27
use TypeError;
28
use ValueError;
29
use function array_filter;
30
use function array_values;
31
use function implode;
32
use function intval;
33
use function is_string;
34
use function strval;
35
use function trim;
36

37
/**
38
 * Casbin database adapter
39
 *
40
 * @package        FastyBird:SimpleAuth!
41
 * @subpackage     Models
42
 * @author         Adam Kadlec <adam.kadlec@fastybird.com>
43
 */
44
class Adapter implements CasbinPersist\FilteredAdapter, CasbinPersist\BatchAdapter, CasbinPersist\UpdatableAdapter
45
{
46

47
        use CasbinPersist\AdapterHelper;
48

49
        private string $policyTableName = 'fb_security_policies';
50

51
        private bool $filtered = false;
52

53
        /** @var array<string> */
54
        private array $columns = ['policy_type', 'policy_v0', 'policy_v1', 'policy_v2', 'policy_v3', 'policy_v4', 'policy_v5'];
55

56
        public function __construct(private readonly DBAL\Connection $connection)
57
        {
58
        }
9✔
59

60
        /**
61
         * @param array<int, string|null> $rule
62
         *
63
         * @throws DBAL\Exception
64
         * @throws TypeError
65
         * @throws ValueError
66
         */
67
        public function savePolicyLine(string $pType, array $rule): DBAL\Result|int|string
68
        {
69
                $queryBuilder = $this->connection->createQueryBuilder();
3✔
70
                $queryBuilder
3✔
71
                        ->insert($this->policyTableName)
3✔
72
                        ->values([
3✔
73
                                'policy_id' => '?',
3✔
74
                                'policy_type' => '?',
3✔
75
                                'policy_policy_type' => '?',
3✔
76
                        ])
3✔
77
                        ->setParameter(0, Uuid\Uuid::uuid4(), Uuid\Doctrine\UuidBinaryType::NAME)
3✔
78
                        ->setParameter(1, Types\PolicyType::from($pType)->value)
3✔
79
                        ->setParameter(2, 'policy');
3✔
80

81
                foreach ($rule as $key => $value) {
3✔
82
                        $queryBuilder
3✔
83
                                ->setValue('policy_v' . strval($key), '?')
3✔
84
                                ->setParameter(intval($key) + 3, $value);
3✔
85
                }
86

87
                return $queryBuilder->executeQuery();
3✔
88
        }
89

90
        /**
91
         * @throws DBAL\Exception
92
         */
93
        public function loadPolicy(CasbinModel\Model $model): void
94
        {
95
                $queryBuilder = $this->connection->createQueryBuilder();
9✔
96

97
                $stmt = $queryBuilder
9✔
98
                        ->select('policy_type', 'policy_v0', 'policy_v1', 'policy_v2', 'policy_v3', 'policy_v4', 'policy_v5')
9✔
99
                        ->from($this->policyTableName)
9✔
100
                        ->executeQuery();
9✔
101

102
                while ($row = $stmt->fetchAssociative()) {
9✔
103
                        /** @var array<int, string|null> $row */
104
                        $this->loadPolicyArray($this->filterRule($row), $model);
9✔
105
                }
106
        }
107

108
        /**
109
         * @throws DBAL\Exception
110
         * @throws Exceptions\InvalidState
111
         */
112
        public function loadFilteredPolicy(CasbinModel\Model $model, $filter): void
113
        {
NEW
114
                $queryBuilder = $this->connection->createQueryBuilder();
×
NEW
115
                $queryBuilder->select(
×
NEW
116
                        'policy_type',
×
NEW
117
                        'policy_v0',
×
NEW
118
                        'policy_v1',
×
NEW
119
                        'policy_v2',
×
NEW
120
                        'policy_v3',
×
NEW
121
                        'policy_v4',
×
NEW
122
                        'policy_v5',
×
NEW
123
                );
×
124

NEW
125
                if (is_string($filter) || $filter instanceof DBAL\Query\Expression\CompositeExpression) {
×
NEW
126
                        $queryBuilder->where($filter);
×
NEW
127
                } elseif ($filter instanceof Filter) {
×
NEW
128
                        $queryBuilder->where($filter->getPredicates());
×
NEW
129
                        foreach ($filter->getParams() as $key => $value) {
×
NEW
130
                                $queryBuilder->setParameter($key, $value);
×
131
                        }
NEW
132
                } elseif ($filter instanceof Closure) {
×
NEW
133
                        $filter($queryBuilder);
×
134
                } else {
NEW
135
                        throw new Exceptions\InvalidState('Invalid filter type');
×
136
                }
137

NEW
138
                $stmt = $queryBuilder->from($this->policyTableName)->executeQuery();
×
139

NEW
140
                while ($row = $stmt->fetchAssociative()) {
×
141
                        /** @var array<int, string|null> $row */
NEW
142
                        $line = implode(', ', array_filter($row, static fn ($val) => $val != '' && $val !== null));
×
UNCOV
143
                        $this->loadPolicyLine(trim($line), $model);
×
144
                }
145

NEW
146
                $this->setFiltered(true);
×
147
        }
148

149
        /**
150
         * @throws DBAL\Exception
151
         * @throws TypeError
152
         * @throws ValueError
153
         */
154
        public function savePolicy(CasbinModel\Model $model): void
155
        {
NEW
156
                foreach ($model['p'] ?? [] as $pType => $ast) {
×
157
                        foreach ($ast->policy as $rule) {
×
NEW
158
                                $this->savePolicyLine($pType, $rule);
×
159
                        }
160
                }
161

NEW
162
                foreach ($model['g'] ?? [] as $pType => $ast) {
×
163
                        foreach ($ast->policy as $rule) {
×
NEW
164
                                $this->savePolicyLine($pType, $rule);
×
165
                        }
166
                }
167
        }
168

169
        /**
170
         * @param array<int, string|null> $rule
171
         *
172
         * @throws DBAL\Exception
173
         * @throws TypeError
174
         * @throws ValueError
175
         */
176
        public function addPolicy(string $sec, string $pType, array $rule): void
177
        {
178
                $this->savePolicyLine($pType, $rule);
3✔
179
        }
180

181
        /**
182
         * @param array<int, array<int, string|null>> $rules
183
         *
184
         * @throws DBAL\Exception
185
         * @throws TypeError
186
         * @throws ValueError
187
         */
188
        public function addPolicies(string $sec, string $pType, array $rules): void
189
        {
NEW
190
                $this->connection->transactional(function () use ($pType, $rules): void {
×
NEW
191
                        foreach ($rules as $rule) {
×
NEW
192
                                $this->savePolicyLine($pType, $rule);
×
193
                        }
NEW
194
                });
×
195
        }
196

197
        /**
198
         * @param array<int, string|null> $rule
199
         *
200
         * @throws DBAL\Exception
201
         */
202
        public function removePolicy(string $sec, string $pType, array $rule): void
203
        {
204
                $this->removePolicyLine($pType, $rule);
3✔
205
        }
206

207
        /**
208
         * @param array<int, array<int, string|null>> $rules
209
         *
210
         * @throws Throwable
211
         */
212
        public function removePolicies(string $sec, string $pType, array $rules): void
213
        {
NEW
214
                $this->connection->transactional(function () use ($pType, $rules): void {
×
NEW
215
                        foreach ($rules as $rule) {
×
NEW
216
                                $this->removePolicyLine($pType, $rule);
×
217
                        }
NEW
218
                });
×
219
        }
220

221
        /**
222
         * @throws Throwable
223
         */
224
        public function removeFilteredPolicy(string $sec, string $pType, int $fieldIndex, string ...$fieldValues): void
225
        {
NEW
226
                $this->removeFiltered($pType, $fieldIndex, ...$fieldValues);
×
227
        }
228

229
        /**
230
         * @param array<int, string|null> $oldRule
231
         * @param array<int, string|null> $newPolicy
232
         *
233
         * @throws DBAL\Exception
234
         */
235
        public function updatePolicy(string $sec, string $pType, array $oldRule, array $newPolicy): void
236
        {
NEW
237
                $queryBuilder = $this->connection->createQueryBuilder();
×
NEW
238
                $queryBuilder->where('policy_type = :ptype')->setParameter('ptype', $pType);
×
239

NEW
240
                foreach ($oldRule as $key => $value) {
×
NEW
241
                        $placeholder = 'w' . strval($key);
×
NEW
242
                        $queryBuilder->andWhere('policy_v' . strval($key) . ' = :' . $placeholder)->setParameter(
×
NEW
243
                                $placeholder,
×
NEW
244
                                $value,
×
NEW
245
                        );
×
246
                }
247

NEW
248
                foreach ($newPolicy as $key => $value) {
×
NEW
249
                        $placeholder = 's' . strval($key);
×
NEW
250
                        $queryBuilder->set('policy_v' . strval($key), ':' . $placeholder)->setParameter($placeholder, $value);
×
251
                }
252

NEW
253
                $queryBuilder->update($this->policyTableName);
×
254

NEW
255
                $queryBuilder->executeQuery();
×
256
        }
257

258
        /**
259
         * @param array<int, array<int, string|null>> $oldRules
260
         * @param array<int, array<int, string|null>> $newRules
261
         */
262
        public function updatePolicies(string $sec, string $pType, array $oldRules, array $newRules): void
263
        {
NEW
264
                $this->connection->transactional(function () use ($sec, $pType, $oldRules, $newRules): void {
×
NEW
265
                        foreach ($oldRules as $i => $oldRule) {
×
NEW
266
                                $this->updatePolicy($sec, $pType, $oldRule, $newRules[$i]);
×
267
                        }
NEW
268
                });
×
269
        }
270

271
        /**
272
         * @param array<int, array<int, string|null>> $newRules
273
         *
274
         * @return array<int, array<int, string|null>>
275
         *
276
         * @throws Throwable
277
         */
278
        public function updateFilteredPolicies(
279
                string $sec,
280
                string $pType,
281
                array $newRules,
282
                int $fieldIndex,
283
                string|null ...$fieldValues,
284
        ): array
285
        {
NEW
286
                $oldRules = [];
×
287

NEW
288
                $this->connection->transactional(
×
NEW
289
                        function () use ($sec, $pType, $newRules, $fieldIndex, $fieldValues, &$oldRules): void {
×
NEW
290
                                $oldRules = $this->removeFiltered($pType, $fieldIndex, ...$fieldValues);
×
291

NEW
292
                                $this->addPolicies($sec, $pType, $newRules);
×
NEW
293
                        },
×
NEW
294
                );
×
295

NEW
296
                return $oldRules;
×
297
        }
298

299
        /**
300
         * @param array<int, string|null> $rule
301
         *
302
         * @return array<int, string>
303
         */
304
        public function filterRule(array $rule): array
305
        {
306
                $rule = array_values($rule);
9✔
307

308
                return array_filter($rule, static fn ($value): bool => $value !== null && $value !== '');
9✔
309
        }
310

311
        public function isFiltered(): bool
312
        {
313
                return $this->filtered;
9✔
314
        }
315

316
        public function setFiltered(bool $filtered): void
317
        {
NEW
318
                $this->filtered = $filtered;
×
319
        }
320

321
        /**
322
         * @param array<int, string|null> $rule
323
         *
324
         * @throws DBAL\Exception
325
         */
326
        private function removePolicyLine(string $pType, array $rule): void
327
        {
328
                $queryBuilder = $this->connection->createQueryBuilder();
3✔
329
                $queryBuilder->where('policy_type = ?')->setParameter(0, $pType);
3✔
330

331
                foreach ($rule as $key => $value) {
3✔
332
                        $queryBuilder->andWhere('policy_v' . strval($key) . ' = ?')->setParameter($key + 1, $value);
3✔
333
                }
334

335
                $queryBuilder->delete($this->policyTableName)->executeQuery();
3✔
336
        }
337

338
        /**
339
         * @return array<int, array<int, string|null>>
340
         *
341
         * @throws Throwable
342
         */
343
        public function removeFiltered(string $pType, int $fieldIndex, string|null ...$fieldValues): array
344
        {
NEW
345
                $removedRules = [];
×
346

NEW
347
                $this->connection->transactional(function () use ($pType, $fieldIndex, $fieldValues, &$removedRules): void {
×
NEW
348
                        $queryBuilder = $this->connection->createQueryBuilder();
×
NEW
349
                        $queryBuilder->where('policy_type = :ptype')->setParameter('ptype', $pType);
×
350

NEW
351
                        foreach ($fieldValues as $value) {
×
NEW
352
                                if ($value !== null && $value !== '') {
×
NEW
353
                                        $key = 'policy_v' . strval($fieldIndex);
×
354

NEW
355
                                        $queryBuilder
×
NEW
356
                                                ->andWhere($key . ' = :' . $key)
×
NEW
357
                                                ->setParameter($key, $value);
×
358
                                }
359

NEW
360
                                $fieldIndex++;
×
361
                        }
362

NEW
363
                        $stmt = $queryBuilder->select(...$this->columns)->from($this->policyTableName)->executeQuery();
×
364

NEW
365
                        while ($row = $stmt->fetchAssociative()) {
×
366
                                /** @var array<int, string|null> $row */
NEW
367
                                $removedRules[] = $this->filterRule($row);
×
368
                        }
369

NEW
370
                        $queryBuilder->delete($this->policyTableName)->executeQuery();
×
NEW
371
                });
×
372

NEW
373
                return $removedRules;
×
374
        }
375

376
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc