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

php-casbin / medoo-adapter / 11578042031

29 Oct 2024 04:14PM UTC coverage: 99.083% (-0.9%) from 100.0%
11578042031

push

github

web-flow
Merge pull request #9 from Dobmod/feature-upgrade-to-php8

BREAKING CHANGE: upgrade to PHP 8.0 and PHP-Casbin 4.0

108 of 109 relevant lines covered (99.08%)

13.47 hits per line

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

99.08
/src/Adapter.php
1
<?php
2

3
namespace CasbinAdapter\Medoo;
4

5
use Casbin\Persist\Adapter as AdapterContract;
6
use Casbin\Persist\BatchAdapter as BatchAdapterContract;
7
use Casbin\Persist\UpdatableAdapter as UpdatableAdapterContract;
8
use Casbin\Persist\FilteredAdapter as FilteredAdapterContract;
9
use Casbin\Persist\AdapterHelper;
10
use Casbin\Model\Model;
11
use Medoo\Medoo;
12
use Casbin\Exceptions\CasbinException;
13
use Casbin\Persist\Adapters\Filter;
14
use Casbin\Exceptions\InvalidFilterTypeException;
15

16
/**
17
 * Medoo Adapter.
18
 *
19
 * @author techlee@qq.com
20
 */
21
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract, FilteredAdapterContract
22
{
23
    use AdapterHelper;
24

25
    /**
26
     * Medoo instance.
27
     *
28
     * @var \Medoo\Medoo
29
     */
30
    protected $database;
31

32
    /**
33
     * CasbinRule table name.
34
     *
35
     * @var string
36
     */
37
    public $casbinRuleTableName = 'casbin_rule';
38

39
    /**
40
     * @var bool
41
     */
42
    private $filtered = false;
43

44
    /**
45
     * Adapter constructor.
46
     *
47
     * @param array $config
48
     */
49
    public function __construct(array $config)
50
    {
51
        $database = new Medoo($config);
44✔
52
        $this->database = $database;
44✔
53

54
        $this->initTable();
44✔
55
    }
56

57
    /**
58
     * New a Adapter.
59
     *
60
     * @param array $config
61
     *
62
     * @return Adapter
63
     */
64
    public static function newAdapter(array $config)
65
    {
66
        return new static($config);
44✔
67
    }
68

69
    /**
70
     * Returns true if the loaded policy has been filtered.
71
     *
72
     * @return bool
73
     */
74
    public function isFiltered(): bool
75
    {
76
        return $this->filtered;
44✔
77
    }
78

79
    /**
80
     * Sets filtered parameter.
81
     *
82
     * @param bool $filtered
83
     */
84
    public function setFiltered(bool $filtered): void
85
    {
86
        $this->filtered = $filtered;
4✔
87
    }
88

89
    /**
90
     * Initialize the policy rules table, create if it does not exist.
91
     *
92
     * @return void
93
     */
94
    public function initTable()
95
    {
96
        $this->database->create($this->casbinRuleTableName, [
44✔
97
            'ptype' => ['VARCHAR(255)'],
44✔
98
            'v0' => ['VARCHAR(255)'],
44✔
99
            'v1' => ['VARCHAR(255)'],
44✔
100
            'v2' => ['VARCHAR(255)'],
44✔
101
            'v3' => ['VARCHAR(255)'],
44✔
102
            'v4' => ['VARCHAR(255)'],
44✔
103
            'v5' => ['VARCHAR(255)'],
44✔
104
        ]);
44✔
105
    }
106

107
    /**
108
     * Filter the rule.
109
     *
110
     * @param array $rule
111
     * @return array
112
     */
113
    public function filterRule(array $rule): array
114
    {
115
        $rule = array_values($rule);
8✔
116

117
        $i = count($rule) - 1;
8✔
118
        for (; $i >= 0; $i--) {
8✔
119
            if ($rule[$i] != '' && !is_null($rule[$i])) {
8✔
120
                break;
8✔
121
            }
122
        }
123

124
        return array_slice($rule, 0, $i + 1);
8✔
125
    }
126

127
    /**
128
     * savePolicyLine function.
129
     *
130
     * @param string $ptype
131
     * @param array  $rule
132
     *
133
     * @return void
134
     */
135
    public function savePolicyLine(string $ptype, array $rule): void
136
    {
137
        $data = [];
12✔
138
        foreach ($rule as $key => $value) {
12✔
139
            $data['v' . strval($key)] = $value;
12✔
140
        }
141

142
        $this->database->insert($this->casbinRuleTableName, $data);
12✔
143
    }
144

145
    /**
146
     * loads all policy rules from the storage.
147
     *
148
     * @param Model $model
149
     *
150
     * @return void
151
     */
152
    public function loadPolicy(Model $model): void
153
    {
154
        $data = $this->database->select($this->casbinRuleTableName, ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5']);
44✔
155
        foreach ($data as $row) {
44✔
156
            $line = implode(', ', array_filter($row, function ($val) {
44✔
157
                return '' != $val && !is_null($val);
44✔
158
            }));
44✔
159
            $this->loadPolicyLine(trim($line), $model);
44✔
160
        }
161
    }
162

163
    /**
164
     * saves all policy rules to the storage.
165
     *
166
     * @param Model $model
167
     *
168
     * @return void
169
     */
170
    public function savePolicy(Model $model): void
171
    {
172
        foreach ($model['p'] as $ptype => $ast) {
4✔
173
            foreach ($ast->policy as $rule) {
4✔
174
                $this->savePolicyLine($ptype, $rule);
4✔
175
            }
176
        }
177
        foreach ($model['g'] as $ptype => $ast) {
4✔
178
            foreach ($ast->policy as $rule) {
4✔
179
                $this->savePolicyLine($ptype, $rule);
×
180
            }
181
        }
182
    }
183

184
    /**
185
     * adds a policy rule to the storage.
186
     * This is part of the Auto-Save feature.
187
     *
188
     * @param string $sec
189
     * @param string $ptype
190
     * @param array  $rule
191
     *
192
     * @return void
193
     */
194
    public function addPolicy(string $sec, string $ptype, array $rule): void
195
    {
196
        $this->savePolicyLine($ptype, $rule);
8✔
197
    }
198

199
    /**
200
     * Adds a policy rules to the storage.
201
     * This is part of the Auto-Save feature.
202
     *
203
     * @param string $sec
204
     * @param string $ptype
205
     * @param string[][] $rules
206
     */
207
    public function addPolicies(string $sec, string $ptype, array $rules): void
208
    {
209
        $cols = [];
8✔
210
        $i = 0;
8✔
211

212
        foreach ($rules as $rule) {
8✔
213
            $temp['ptype'] = $ptype;
8✔
214
            foreach ($rule as $key => $value) {
8✔
215
                $temp['v'. strval($key)] = $value;
8✔
216
            }
217
            $cols[$i++] = $temp ?? [];
8✔
218
            $temp = [];
8✔
219
        }
220
        $this->database->insert($this->casbinRuleTableName, $cols);
8✔
221
    }
222

223
    /**
224
     * This is part of the Auto-Save feature.
225
     *
226
     * @param string $sec
227
     * @param string $ptype
228
     * @param array  $rule
229
     *
230
     * @return void
231
     */
232
    public function removePolicy(string $sec, string $ptype, array $rule): void
233
    {
234
        $where['ptype'] = $ptype;
8✔
235

236
        foreach ($rule as $key => $value) {
8✔
237
            $where['v'.strval($key)] = $value;
8✔
238
        }
239

240
        $this->database->delete($this->casbinRuleTableName, ['AND' => $where]);
8✔
241
    }
242

243
    /**
244
     * Removes policy rules from the storage.
245
     * This is part of the Auto-Save feature.
246
     *
247
     * @param string $sec
248
     * @param string $ptype
249
     * @param string[][] $rules
250
     */
251
    public function removePolicies(string $sec, string $ptype, array $rules): void
252
    {
253
        $this->database->action(function () use ($sec, $ptype, $rules) {
4✔
254
            foreach ($rules as $rule) {
4✔
255
                $this->removePolicy($sec, $ptype, $rule);
4✔
256
            }
257
        });
4✔
258
    }
259

260
    /**
261
     * @param string $sec
262
     * @param string $ptype
263
     * @param int $fieldIndex
264
     * @param string|null ...$fieldValues
265
     * @return array
266
     * @throws Throwable
267
     */
268
    public function _removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, ?string ...$fieldValues): array
269
    {
270
        $removedRules = [];
8✔
271
        $columns = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
8✔
272
        $where['ptype'] = $ptype;
8✔
273

274
        foreach (range(0, 5) as $value) {
8✔
275
            if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) {
8✔
276
                if ('' !== $val = $fieldValues[$value - $fieldIndex]) {
8✔
277
                    $where['v' . strval($value)] = $val;
8✔
278
                }
279
            }
280
        }
281

282
        $removedRules = [];
8✔
283
        $rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
8✔
284
        foreach ($rows as $row) {
8✔
285
            unset($row['ptype']);
8✔
286
            $removedRules[] = $this->filterRule($row);
8✔
287
        }
288
        $this->database->delete($this->casbinRuleTableName, ['AND' => $where]);
8✔
289

290
        return $removedRules;
8✔
291
    }
292

293
    /**
294
     * RemoveFilteredPolicy removes policy rules that match the filter from the storage.
295
     * This is part of the Auto-Save feature.
296
     *
297
     * @param string $sec
298
     * @param string $ptype
299
     * @param int $fieldIndex
300
     * @param string ...$fieldValues
301
     * @throws Exception|Throwable
302
     *
303
     * @return void
304
     */
305
    public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, string ...$fieldValues): void
306
    {
307
        $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
4✔
308
    }
309

310
    /**
311
     * Updates a policy rule from storage.
312
     * This is part of the Auto-Save feature.
313
     *
314
     * @param string $sec
315
     * @param string $ptype
316
     * @param string[] $oldRule
317
     * @param string[] $newPolicy
318
     */
319
    public function updatePolicy(string $sec, string $ptype, array $oldRule, array $newPolicy): void
320
    {
321
        $where = ['ptype' => $ptype];
8✔
322
        
323
        foreach ($oldRule as $k => $v) {
8✔
324
            $where['v' . strval($k)] = $v;
8✔
325
        }
326
        
327
        $columns = [];
8✔
328
        foreach ($newPolicy as $k => $v) {
8✔
329
            $columns['v' . strval($k)] = $v;
8✔
330
        }
331

332
        $this->database->update($this->casbinRuleTableName, $columns, $where);
8✔
333
    }
334

335
    /**
336
     * UpdatePolicies updates some policy rules to storage, like db, redis.
337
     *
338
     * @param string $sec
339
     * @param string $ptype
340
     * @param string[][] $oldRules
341
     * @param string[][] $newRules
342
     * @return void
343
     */
344
    public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void
345
    {
346
        $this->database->action(function () use ($sec, $ptype, $oldRules, $newRules) {
4✔
347
            foreach ($oldRules as $i => $oldRule) {
4✔
348
                $this->updatePolicy($sec, $ptype, $oldRule, $newRules[$i]);
4✔
349
            }
350
        });
4✔
351
    }
352

353
    /**
354
     * @param string $sec
355
     * @param string $ptype
356
     * @param array $newRules
357
     * @param int $fieldIndex
358
     * @param string ...$fieldValues
359
     * @return array
360
     * @throws Throwable
361
     */
362
    public function updateFilteredPolicies(string $sec, string $ptype, array $newRules, int $fieldIndex, ?string ...$fieldValues): array
363
    {
364
        $oldRules = [];
4✔
365
        $this->database->action(function () use ($sec, $ptype, $newRules, $fieldIndex, $fieldValues, &$oldRules) {
4✔
366
            $oldRules = $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
4✔
367
            $this->addPolicies($sec, $ptype, $newRules);
4✔
368
        });
4✔
369
        return $oldRules;
4✔
370
    }
371

372
    /**
373
     * Loads only policy rules that match the filter.
374
     *
375
     * @param Model $model
376
     * @param mixed $filter
377
     */
378
    public function loadFilteredPolicy(Model $model, $filter): void
379
    {
380
        $columns = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
4✔
381
        if (is_string($filter)) {
4✔
382
            $where = Medoo::raw('WHERE ' . $filter);
4✔
383
            $rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
4✔
384
        } elseif ($filter instanceof Filter) {
4✔
385
            foreach ($filter->p as $k => $v) {
4✔
386
                $where[$v] = $filter->g[$k];
4✔
387
            }
388
            $rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
4✔
389
        } elseif ($filter instanceof \Closure) {
4✔
390
            $rows = [];
4✔
391
            $filter($this->database, $this->casbinRuleTableName, $columns, $rows);
4✔
392
        } else {
393
            throw new InvalidFilterTypeException('invalid filter type');
4✔
394
        }
395

396
        foreach ($rows as $row) {
4✔
397
            $row = array_filter($row, function ($value) {
4✔
398
                return !is_null($value) && $value !== '';
4✔
399
            });
4✔
400
            $line = implode(', ', array_filter($row, function ($val) {
4✔
401
                return '' != $val && !is_null($val);
4✔
402
            }));
4✔
403
            $this->loadPolicyLine(trim($line), $model);
4✔
404
        }
405
        $this->setFiltered(true);
4✔
406
    }
407

408
    /**
409
     * Gets database.
410
     *
411
     * @return \Medoo\Medoo
412
     */
413
    public function getDatabase()
414
    {
415
        return $this->database;
44✔
416
    }
417
}
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