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

php-casbin / laravel-authz / 16272017293

14 Jul 2025 04:11PM UTC coverage: 99.248%. Remained the same
16272017293

push

github

leeqvip
fix: add some Throwable tag in comments

264 of 266 relevant lines covered (99.25%)

120.52 hits per line

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

97.89
/src/Adapters/DatabaseAdapter.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Lauthz\Adapters;
6

7
use Lauthz\Models\Rule;
8
use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract;
9
use Lauthz\Contracts\BatchDatabaseAdapter as BatchDatabaseAdapterContract;
10
use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract;
11
use Lauthz\Contracts\FilteredDatabaseAdapter as FilteredDatabaseAdapterContract;
12
use Casbin\Persist\Adapters\Filter;
13
use Casbin\Model\Model;
14
use Casbin\Persist\AdapterHelper;
15
use DateTime;
16
use Casbin\Exceptions\InvalidFilterTypeException;
17
use Throwable;
18

19
/**
20
 * DatabaseAdapter.
21
 *
22
 * @author techlee@qq.com
23
 */
24
class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract, FilteredDatabaseAdapterContract
25
{
26
    use AdapterHelper;
27

28
    /**
29
     * @var bool
30
     */
31
    private bool $filtered = false;
32

33
    /**
34
     * Rules eloquent model.
35
     *
36
     * @var Rule
37
     */
38
    protected Rule $eloquent;
39

40
    /**
41
     * the DatabaseAdapter constructor.
42
     *
43
     * @param Rule $eloquent
44
     */
45
    public function __construct(Rule $eloquent)
46
    {
47
        $this->eloquent = $eloquent;
270✔
48
    }
49

50
    /**
51
     * Filter the rule.
52
     *
53
     * @param array $rule
54
     * @return array
55
     */
56
    public function filterRule(array $rule): array
57
    {
58
        $rule = array_values($rule);
270✔
59

60
        $i = count($rule) - 1;
270✔
61
        for (; $i >= 0; $i--) {
270✔
62
            if ($rule[$i] != '' && !is_null($rule[$i])) {
270✔
63
                break;
270✔
64
            }
65
        }
66

67
        return array_slice($rule, 0, $i + 1);
270✔
68
    }
69

70
    /**
71
     * savePolicyLine function.
72
     *
73
     * @param string $ptype
74
     * @param array  $rule
75
     */
76
    public function savePolicyLine(string $ptype, array $rule): void
77
    {
78
        $col['ptype'] = $ptype;
117✔
79
        foreach ($rule as $key => $value) {
117✔
80
            $col['v'.strval($key)] = $value;
117✔
81
        }
82

83
        $this->eloquent->create($col);
117✔
84
    }
85

86
    /**
87
     * loads all policy rules from the storage.
88
     *
89
     * @param Model $model
90
     */
91
    public function loadPolicy(Model $model): void
92
    {
93
        $rows = $this->eloquent->getAllFromCache();
270✔
94

95
        foreach ($rows as $row) {
270✔
96
            $this->loadPolicyArray($this->filterRule($row), $model);
270✔
97
        }
98
    }
99

100
    /**
101
     * saves all policy rules to the storage.
102
     *
103
     * @param Model $model
104
     */
105
    public function savePolicy(Model $model): void
106
    {
107
        foreach ($model['p'] as $ptype => $ast) {
18✔
108
            foreach ($ast->policy as $rule) {
18✔
109
                $this->savePolicyLine($ptype, $rule);
18✔
110
            }
111
        }
112

113
        foreach ($model['g'] as $ptype => $ast) {
18✔
114
            foreach ($ast->policy as $rule) {
18✔
115
                $this->savePolicyLine($ptype, $rule);
×
116
            }
117
        }
118
    }
119

120
    /**
121
     * adds a policy rule to the storage.
122
     * This is part of the Auto-Save feature.
123
     *
124
     * @param string $sec
125
     * @param string $ptype
126
     * @param array  $rule
127
     */
128
    public function addPolicy(string $sec, string $ptype, array $rule): void
129
    {
130
        $this->savePolicyLine($ptype, $rule);
99✔
131
    }
132

133
     /**
134
     * Adds a policy rules to the storage.
135
     * This is part of the Auto-Save feature.
136
     *
137
     * @param string $sec
138
     * @param string $ptype
139
     * @param string[][] $rules
140
     */
141
    public function addPolicies(string $sec, string $ptype, array $rules): void
142
    {
143
        $cols = [];
27✔
144
        $i = 0;
27✔
145

146
        foreach($rules as $rule) {
27✔
147
            $temp['ptype'] = $ptype;
27✔
148
            $temp['created_at'] = new DateTime();
27✔
149
            $temp['updated_at'] = $temp['created_at'];
27✔
150
            foreach ($rule as $key => $value) {
27✔
151
                $temp['v'.strval($key)] = $value;
27✔
152
            }
153
            $cols[$i++] = $temp ?? [];
27✔
154
            $temp = [];
27✔
155
        }
156
        $this->eloquent->insert($cols);
27✔
157
        Rule::fireModelEvent('saved');
27✔
158
    }
159

160
    /**
161
     * This is part of the Auto-Save feature.
162
     *
163
     * @param string $sec
164
     * @param string $ptype
165
     * @param array  $rule
166
     */
167
    public function removePolicy(string $sec, string $ptype, array $rule): void
168
    {
169
        $instance = $this->eloquent->where('ptype', $ptype);
36✔
170

171
        foreach ($rule as $key => $value) {
36✔
172
            $instance->where('v'.strval($key), $value);
36✔
173
        }
174

175
        $instance->delete();
36✔
176
        Rule::fireModelEvent('deleted');
36✔
177
    }
178

179
    /**
180
     * Removes policy rules from the storage.
181
     * This is part of the Auto-Save feature.
182
     *
183
     * @param string $sec
184
     * @param string $ptype
185
     * @param string[][] $rules
186
     * @throws Throwable
187
     */
188
    public function removePolicies(string $sec, string $ptype, array $rules): void
189
    {
190
        $this->eloquent->getConnection()->transaction(function () use ($sec, $rules, $ptype) {
18✔
191
            foreach ($rules as $rule) {
18✔
192
                $this->removePolicy($sec, $ptype, $rule);
18✔
193
            }
194
        });
18✔
195
    }
196

197
    /**
198
     * @param string      $sec
199
     * @param string      $ptype
200
     * @param int         $fieldIndex
201
     * @param string|null ...$fieldValues
202
     * @return array
203
     * @throws Throwable
204
     */
205
    public function _removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, ?string ...$fieldValues): array
206
    {
207
        $removedRules = [];
27✔
208
        $instance = $this->eloquent->where('ptype', $ptype);
27✔
209
        
210
        foreach (range(0, 5) as $value) {
27✔
211
            if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) {
27✔
212
                if ('' != $fieldValues[$value - $fieldIndex]) {
27✔
213
                    $instance->where('v' . strval($value), $fieldValues[$value - $fieldIndex]);
27✔
214
                }
215
            }
216
        }
217

218
        $oldP = $instance->get()->makeHidden(['created_at','updated_at', 'id', 'ptype'])->toArray();
27✔
219
        foreach ($oldP as &$item) {
27✔
220
            $item = $this->filterRule($item);
27✔
221
            $removedRules[] = $item;
27✔
222
        }
223

224
        $instance->delete();
27✔
225
        Rule::fireModelEvent('deleted');
27✔
226

227
        return $removedRules;
27✔
228
    }
229

230
    /**
231
     * RemoveFilteredPolicy removes policy rules that match the filter from the storage.
232
     * This is part of the Auto-Save feature.
233
     *
234
     * @param string $sec
235
     * @param string $ptype
236
     * @param int $fieldIndex
237
     * @param string|null ...$fieldValues
238
     * @return void
239
     * @throws Throwable
240
     */
241
    public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, ?string ...$fieldValues): void
242
    {
243
        $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
18✔
244
    }
245

246
    /**
247
     * Updates a policy rule from storage.
248
     * This is part of the Auto-Save feature.
249
     *
250
     * @param string $sec
251
     * @param string $ptype
252
     * @param string[] $oldRule
253
     * @param string[] $newPolicy
254
     */
255
    public function updatePolicy(string $sec, string $ptype, array $oldRule, array $newPolicy): void
256
    {
257
        $instance = $this->eloquent->where('ptype', $ptype);
27✔
258
        foreach($oldRule as $k => $v) {
27✔
259
            $instance->where('v' . $k, $v);
27✔
260
        }
261
        $instance = $instance->first();
27✔
262
        if (!$instance) {
27✔
263
            return;
×
264
        }
265

266
        $update = [];
27✔
267
        foreach($newPolicy as $k => $v) {
27✔
268
            $update['v' . $k] = $v;
27✔
269
        }
270
        $instance->update($update);
27✔
271
        Rule::fireModelEvent('saved');
27✔
272
    }
273

274
    /**
275
     * UpdatePolicies updates some policy rules to storage, like db, redis.
276
     *
277
     * @param string $sec
278
     * @param string $ptype
279
     * @param string[][] $oldRules
280
     * @param string[][] $newRules
281
     * @return void
282
     * @throws Throwable
283
     */
284
    public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void
285
    {
286
        $this->eloquent->getConnection()->transaction(function () use ($sec, $ptype, $oldRules, $newRules) {
9✔
287
            foreach ($oldRules as $i => $oldRule) {
9✔
288
                $this->updatePolicy($sec, $ptype, $oldRule, $newRules[$i]);
9✔
289
            }
290
        });
9✔
291
    }
292

293
    /**
294
     * UpdateFilteredPolicies deletes old rules and adds new rules.
295
     *
296
     * @param string $sec
297
     * @param string $ptype
298
     * @param array $newPolicies
299
     * @param integer $fieldIndex
300
     * @param string ...$fieldValues
301
     * @return array
302
     * @throws Throwable
303
     */
304
    public function updateFilteredPolicies(string $sec, string $ptype, array $newPolicies, int $fieldIndex, string ...$fieldValues): array
305
    {
306
        $oldRules = [];
9✔
307
        $this->eloquent->getConnection()->transaction(function () use ($sec, $ptype, $fieldIndex, $fieldValues, $newPolicies, &$oldRules) {
9✔
308
            $oldRules = $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
9✔
309
            $this->addPolicies($sec, $ptype, $newPolicies);
9✔
310
        });
9✔
311
        return $oldRules;
9✔
312
    }
313

314
    /**
315
     * Loads only policy rules that match the filter.
316
     *
317
     * @param Model $model
318
     * @param mixed $filter
319
     * @throws InvalidFilterTypeException
320
     */
321
    public function loadFilteredPolicy(Model $model, $filter): void
322
    {
323
        $instance = $this->eloquent;
9✔
324

325
        if (is_string($filter)) {
9✔
326
            $instance = $instance->whereRaw($filter);
9✔
327
        } else if ($filter instanceof Filter) {
9✔
328
            foreach($filter->p as $k => $v) {
9✔
329
                $where[$v] = $filter->g[$k];
9✔
330
                $instance = $instance->where($v, $filter->g[$k]);
9✔
331
            }
332
        } else if ($filter instanceof \Closure) {
9✔
333
            $instance = $instance->where($filter);
9✔
334
        } else {
335
            throw new InvalidFilterTypeException('invalid filter type');
9✔
336
        }
337
        $rows = $instance->get()->makeHidden(['created_at','updated_at', 'id'])->toArray();
9✔
338
        foreach ($rows as $row) {
9✔
339
            $row = array_filter($row, static fn($value): bool => !is_null($value) && $value !== '');
9✔
340
            $line = implode(', ', array_filter($row, static fn ($val): bool => '' != $val && !is_null($val)));
9✔
341
            $this->loadPolicyLine(trim($line), $model);
9✔
342
        }
343
        $this->setFiltered(true);
9✔
344
    }
345

346
    /**
347
     * Returns true if the loaded policy has been filtered.
348
     *
349
     * @return bool
350
     */
351
    public function isFiltered(): bool
352
    {
353
        return $this->filtered;
270✔
354
    }
355

356
    /**
357
     * Sets filtered parameter.
358
     *
359
     * @param bool $filtered
360
     */
361
    public function setFiltered(bool $filtered): void
362
    {
363
        $this->filtered = $filtered;
9✔
364
    }
365
}
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

© 2026 Coveralls, Inc