Passed
Push — master ( bfc2c7...da6314 )
by Lee
02:23 queued 12s
created

Enforcer::enforce()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 1
c 3
b 1
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
declare(strict_types=1);
4
5
namespace Casbin;
6
7
use Casbin\Effect\DefaultEffector;
8
use Casbin\Effect\Effector;
9
use Casbin\Exceptions\CasbinException;
10
use Casbin\Exceptions\InvalidFilePathException;
11
use Casbin\Model\FunctionMap;
12
use Casbin\Model\Model;
13
use Casbin\Persist\Adapter;
14
use Casbin\Persist\Adapters\FileAdapter;
15
use Casbin\Persist\FilteredAdapter;
16
use Casbin\Persist\Watcher;
17
use Casbin\Rbac\DefaultRoleManager\RoleManager as DefaultRoleManager;
18
use Casbin\Rbac\RoleManager;
19
use Casbin\Util\BuiltinOperations;
20
use Casbin\Log\Log;
21
use Casbin\Util\Util;
22
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
23
24
/**
25
 * Class Enforcer
26
 * the main interface for authorization enforcement and policy management.
27
 *
28
 * @author [email protected]
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
29
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
30
class Enforcer
31
{
32
    use InternalApi;
33
    use ManagementApi;
34
    use RbacApi;
0 ignored issues
show
Bug introduced by
The trait Casbin\RbacApi requires the property $rM which is not provided by Casbin\Enforcer.
Loading history...
35
36
    /**
37
     * model path.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
38
     *
39
     * @var string
40
     */
41
    protected $modelPath;
42
43
    /**
44
     * Model.
45
     *
46
     * @var Model
47
     */
48
    protected $model;
49
50
    /**
51
     * FunctionMap.
52
     *
53
     * @var FunctionMap
54
     */
55
    protected $fm;
56
57
    /**
58
     * Effector.
59
     *
60
     * @var Effector
61
     */
62
    protected $eft;
63
64
    /**
65
     * Adapter.
66
     *
67
     * @var Adapter|null
68
     */
69
    protected $adapter;
70
71
    /**
72
     * Watcher.
73
     *
74
     * @var Watcher|null
75
     */
76
    protected $watcher;
77
78
    /**
79
     * RoleManager.
80
     *
81
     * @var RoleManager
82
     */
83
    protected $rm;
84
85
    /**
86
     * $enabled.
87
     *
88
     * @var bool
89
     */
90
    protected $enabled;
91
92
    /**
93
     * $autoSave.
94
     *
95
     * @var bool
96
     */
97
    protected $autoSave;
98
99
    /**
100
     * $autoBuildRoleLinks.
101
     *
102
     * @var bool
103
     */
104
    protected $autoBuildRoleLinks;
105
106
    /**
107
     * Enforcer constructor.
108
     * Creates an enforcer via file or DB.
109
     * File:
110
     * $e = new Enforcer("path/to/basic_model.conf", "path/to/basic_policy.csv")
111
     * MySQL DB:
112
     * $a = DatabaseAdapter::newAdapter([
113
     *      'type'     => 'mysql', // mysql,pgsql,sqlite,sqlsrv
114
     *      'hostname' => '127.0.0.1',
115
     *      'database' => 'test',
116
     *      'username' => 'root',
117
     *      'password' => '123456',
118
     *      'hostport' => '3306',
119
     *  ]);
120
     * $e = new Enforcer("path/to/basic_model.conf", $a).
121
     *
122
     * @param mixed ...$params
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
123
     *
124
     * @throws CasbinException
125
     */
126 168
    public function __construct(...$params)
127
    {
128 168
        $parsedParamLen = 0;
129 168
        $paramLen = \count($params);
130 168
        if ($paramLen >= 1) {
131 168
            if (\is_bool($enableLog = $params[$paramLen - 1])) {
132 6
                $this->enableLog($enableLog);
133 6
                ++$parsedParamLen;
134
            }
135
        }
136
137 168
        if (2 == $paramLen - $parsedParamLen) {
138 147
            $p0 = $params[0];
139 147
            if (\is_string($p0)) {
140 141
                $p1 = $params[1];
141 141
                if (\is_string($p1)) {
142 138
                    $this->initWithFile($p0, $p1);
143
                } else {
144 141
                    $this->initWithAdapter($p0, $p1);
145
                }
146
            } else {
147 6
                if (\is_string($params[1])) {
148
                    throw new CasbinException('Invalid parameters for enforcer.');
149
                } else {
150 147
                    $this->initWithModelAndAdapter($p0, $params[1]);
151
                }
152
            }
153 24
        } elseif (1 == $paramLen - $parsedParamLen) {
154 21
            $p0 = $params[0];
155 21
            if (\is_string($p0)) {
156 12
                $this->initWithFile($p0, '');
157
            } else {
158 21
                $this->initWithModelAndAdapter($p0, null);
159
            }
160 3
        } elseif (0 == $paramLen - $parsedParamLen) {
161
            // pass
162
        } else {
163
            throw new CasbinException('Invalid parameters for enforcer.');
164
        }
165 168
    }
166
167
    /**
168
     * initializes an enforcer with a model file and a policy file.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
169
     *
170
     * @param string $modelPath
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
171
     * @param string $policyPath
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
172
     *
173
     * @throws CasbinException
174
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
175 150
    public function initWithFile(string $modelPath, string $policyPath): void
176
    {
177 150
        $adapter = new FileAdapter($policyPath);
178 150
        $this->initWithAdapter($modelPath, $adapter);
179 150
    }
180
181
    /**
182
     * initializes an enforcer with a database adapter.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
183
     *
184
     * @param string  $modelPath
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
185
     * @param Adapter $adapter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
186
     *
187
     * @throws CasbinException
188
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
189 153
    public function initWithAdapter(string $modelPath, Adapter $adapter): void
190
    {
191 153
        $m = Model::newModelFromFile($modelPath);
192 153
        $this->initWithModelAndAdapter($m, $adapter);
193
194 153
        $this->modelPath = $modelPath;
195 153
    }
196
197
    /**
198
     * initWithModelAndAdapter initializes an enforcer with a model and a database adapter.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
199
     *
200
     * @param Model        $m
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
201
     * @param Adapter|null $adapter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
202
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
203 165
    public function initWithModelAndAdapter(Model $m, Adapter $adapter = null): void
204
    {
205 165
        $this->adapter = $adapter;
206
207 165
        $this->model = $m;
208 165
        $this->model->printModel();
209
210 165
        $this->fm = Model::loadFunctionMap();
211
212 165
        $this->initialize();
213
214
        // Do not initialize the full policy when using a filtered adapter
215 165
        $ok = $this->adapter instanceof FilteredAdapter ? $this->adapter->isFiltered() : false;
216
217 165
        if (!\is_null($this->adapter) && !$ok) {
218 156
            $this->loadPolicy();
219
        }
220 165
    }
221
222
    /**
223
     * initializes an enforcer with a database adapter.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
224
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
225 168
    protected function initialize(): void
226
    {
227 168
        $this->rm = new DefaultRoleManager(10);
228 168
        $this->eft = new DefaultEffector();
229 168
        $this->watcher = null;
230
231 168
        $this->enabled = true;
232 168
        $this->autoSave = true;
233 168
        $this->autoBuildRoleLinks = true;
234 168
    }
235
236
    /**
237
     * reloads the model from the model CONF file.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
238
     * Because the policy is attached to a model, so the policy is invalidated and needs to be reloaded by calling LoadPolicy().
239
     *
240
     * @throws CasbinException
241
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
242 3
    public function loadModel(): void
243
    {
244 3
        $this->model = Model::newModelFromFile($this->modelPath);
245 3
        $this->model->printModel();
246 3
        $this->fm = Model::loadFunctionMap();
247
248 3
        $this->initialize();
249 3
    }
250
251
    /**
252
     * gets the current model.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
253
     *
254
     * @return Model
255
     */
256 9
    public function getModel(): Model
257
    {
258 9
        return $this->model;
259
    }
260
261
    /**
262
     * sets the current model.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
263
     *
264
     * @param Model $model
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
265
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
266 6
    public function setModel(Model $model): void
267
    {
268 6
        $this->model = $model;
269 6
        $this->fm = $this->model->loadFunctionMap();
270
271 6
        $this->initialize();
272 6
    }
273
274
    /**
275
     * gets the current adapter.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
276
     *
277
     * @return Adapter
278
     */
279 6
    public function getAdapter(): Adapter
280
    {
281 6
        return $this->adapter;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->adapter could return the type null which is incompatible with the type-hinted return Casbin\Persist\Adapter. Consider adding an additional type-check to rule them out.
Loading history...
282
    }
283
284
    /**
285
     * sets the current adapter.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
286
     *
287
     * @param Adapter $adapter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
288
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
289 9
    public function setAdapter(Adapter $adapter): void
290
    {
291 9
        $this->adapter = $adapter;
292 9
    }
293
294
    /**
295
     * sets the current watcher.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
296
     *
297
     * @param Watcher $watcher
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
298
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
299
    public function setWatcher(Watcher $watcher): void
300
    {
301
        $this->watcher = $watcher;
302
        $this->watcher->setUpdateCallback(function () {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
303
            $this->loadPolicy();
304
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
305
    }
306
307
    /**
308
     * gets the current role manager.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
309
     *
310
     * @return RoleManager
311
     */
312 3
    public function getRoleManager(): RoleManager
313
    {
314 3
        return $this->rm;
315
    }
316
317
    /**
318
     * sets the current role manager.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
319
     *
320
     * @param RoleManager $rm
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
321
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
322
    public function setRoleManager(RoleManager $rm): void
323
    {
324
        $this->rm = $rm;
325
    }
326
327
    /**
328
     * sets the current effector.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
329
     *
330
     * @param Effector $eft
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
331
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
332
    public function setEffector(Effector $eft): void
333
    {
334
        $this->eft = $eft;
335
    }
336
337
    /**
338
     * clears all policy.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
339
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
340 3
    public function clearPolicy(): void
341
    {
342 3
        $this->model->clearPolicy();
343 3
    }
344
345
    /**
346
     * reloads the policy from file/database.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
347
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
348 162
    public function loadPolicy(): void
349
    {
350 162
        $this->model->clearPolicy();
351
352
        try {
353 162
            $this->adapter->loadPolicy($this->model);
0 ignored issues
show
Bug introduced by
The method loadPolicy() 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

353
            $this->adapter->/** @scrutinizer ignore-call */ 
354
                            loadPolicy($this->model);

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...
354 12
        } catch (InvalidFilePathException $e) {
355
            //throw $e;
356
        }
357
358 162
        $this->model->printPolicy();
359 162
        if ($this->autoBuildRoleLinks) {
360 162
            $this->buildRoleLinks();
361
        }
362 162
    }
363
364
    /**
365
     * reloads a filtered policy from file/database.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
366
     *
367
     * @param mixed $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
368
     *
369
     * @throws CasbinException
370
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
371 3
    public function loadFilteredPolicy($filter): void
372
    {
373 3
        $this->model->clearPolicy();
374
375 3
        if ($this->adapter instanceof FilteredAdapter) {
376 3
            $filteredAdapter = $this->adapter;
377 3
            $filteredAdapter->loadFilteredPolicy($this->model, $filter);
378
        } else {
379
            throw new CasbinException('filtered policies are not supported by this adapter');
380
        }
381
382 3
        $this->model->printPolicy();
383 3
        if ($this->autoBuildRoleLinks) {
384 3
            $this->buildRoleLinks();
385
        }
386 3
    }
387
388
    /**
389
     * returns true if the loaded policy has been filtered.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
390
     *
391
     * @return bool
392
     */
393 6
    public function isFiltered(): bool
394
    {
395 6
        if (!$this->adapter instanceof FilteredAdapter) {
396 3
            return false;
397
        }
398
399 3
        $filteredAdapter = $this->adapter;
400
401 3
        return $filteredAdapter->isFiltered();
402
    }
403
404
    /**
405
     * saves the current policy (usually after changed with Casbin API) back to file/database.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
406
     *
407
     * @return mixed
408
     *
409
     * @throws CasbinException
410
     */
411 6
    public function savePolicy(): void
412
    {
413 6
        if ($this->isFiltered()) {
414 3
            throw new CasbinException('cannot save a filtered policy');
415
        }
416
417 3
        $this->adapter->savePolicy($this->model);
418
419 3
        if (null !== $this->watcher) {
420
            $this->watcher->update();
421
        }
422 3
    }
423
424
    /**
425
     * changes the enforcing state of Casbin, when Casbin is disabled, all access will be allowed by the Enforce() function.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
426
     *
427
     * @param bool $enabled
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
428
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
429 3
    public function enableEnforce(bool $enabled = true): void
430
    {
431 3
        $this->enabled = $enabled;
432 3
    }
433
434
    /**
435
     * changes whether Casbin will log messages to the Logger.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
436
     *
437
     * @param bool $enabled
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
438
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
439 6
    public function enableLog(bool $enabled = true): void
440
    {
441 6
        Log::getLogger()->enableLog($enabled);
442 6
    }
443
444
    /**
445
     * controls whether to save a policy rule automatically to the adapter when it is added or removed.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
446
     *
447
     * @param bool $autoSave
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
448
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
449 3
    public function enableAutoSave(bool $autoSave = true): void
450
    {
451 3
        $this->autoSave = $autoSave;
452 3
    }
453
454
    /**
455
     * controls whether to rebuild the role inheritance relations when a role is added or deleted.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
456
     *
457
     * @param bool $autoBuildRoleLinks
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
458
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
459
    public function enableAutoBuildRoleLinks(bool $autoBuildRoleLinks = true): void
460
    {
461
        $this->autoBuildRoleLinks = $autoBuildRoleLinks;
462
    }
463
464
    /**
465
     * manually rebuild the role inheritance relations.
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
466
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
467 162
    public function buildRoleLinks(): void
468
    {
469 162
        $this->rm->clear();
470 162
        $this->model->buildRoleLinks($this->rm);
471 162
    }
472
473
    /**
474
     * use a custom matcher to decides whether a "subject" can access a "object" with the operation "action",
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
475
     * input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is "".
476
     *
477
     * @param string $matcher
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
478
     * @param mixed  ...$rvals
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
479
     *
480
     * @return bool|mixed
481
     *
482
     * @throws CasbinException
483
     */
484 111
    protected function enforcing(string $matcher, ...$rvals): bool
485
    {
486 111
        if (!$this->enabled) {
487 3
            return true;
488
        }
489
490 111
        $functions = $this->fm->getFunctions();
491
492 111
        if (isset($this->model['g'])) {
493 36
            foreach ($this->model['g'] as $key => $ast) {
494 36
                $rm = $ast->rM;
495 36
                $functions[$key] = BuiltinOperations::generateGFunction($rm);
496
            }
497
        }
498
499 111
        if (!isset($this->model['m']['m'])) {
500
            throw new CasbinException('model is undefined');
501
        }
502
503 111
        $expString = '';
504 111
        if ('' === $matcher) {
505 111
            $expString = $this->getExpString($this->model['m']['m']->value);
506
        } else {
507
            $expString = Util::removeComments(Util::escapeAssertion($matcher));
508
        }
509
510 111
        $rTokens = array_values($this->model['r']['r']->tokens);
511 111
        $pTokens = array_values($this->model['p']['p']->tokens);
512
513 111
        $rParameters = array_combine($rTokens, $rvals);
514
515 111
        if (false === $rParameters) {
516
            throw new CasbinException('invalid request size');
517
        }
518
519 111
        $expressionLanguage = $this->getExpressionLanguage($functions);
520 111
        $expression = $expressionLanguage->parse($expString, array_merge($rTokens, $pTokens));
521
522 111
        $policyEffects = [];
523 111
        $matcherResults = [];
524
525 111
        $policyLen = \count($this->model['p']['p']->policy);
526
527 111
        if (0 != $policyLen) {
528 105
            foreach ($this->model['p']['p']->policy as $i => $pvals) {
529 105
                $parameters = array_combine($pTokens, $pvals);
530 105
                if (false === $parameters) {
531
                    throw new CasbinException('invalid policy size');
532
                }
533
534 105
                $parameters = array_merge($rParameters, $parameters);
535 105
                $result = $expressionLanguage->evaluate($expression, $parameters);
536
537 105
                if (\is_bool($result)) {
538 105
                    if (!$result) {
539 99
                        $policyEffects[$i] = Effector::INDETERMINATE;
540
541 105
                        continue;
542
                    }
543
                } elseif (\is_float($result)) {
544
                    if (0 == $result) {
545
                        $policyEffects[$i] = Effector::INDETERMINATE;
546
547
                        continue;
548
                    } else {
549
                        $matcherResults[$i] = $result;
550
                    }
551
                } else {
552
                    throw new CasbinException('matcher result should be bool, int or float');
553
                }
554 102
                if (isset($parameters['p_eft'])) {
555 12
                    $eft = $parameters['p_eft'];
556 12
                    if ('allow' == $eft) {
557 9
                        $policyEffects[$i] = Effector::ALLOW;
558 12
                    } elseif ('deny' == $eft) {
559 9
                        $policyEffects[$i] = Effector::DENY;
560
                    } else {
561 12
                        $policyEffects[$i] = Effector::INDETERMINATE;
562
                    }
563
                } else {
564 90
                    $policyEffects[$i] = Effector::ALLOW;
565
                }
566
567 102
                if (isset($this->model['e']['e']) && 'priority(p_eft) || deny' == $this->model['e']['e']->value) {
568 72
                    break;
569
                }
570
            }
571
        } else {
572 12
            $parameters = $rParameters;
573 12
            foreach ($this->model['p']['p']->tokens as $token) {
574 12
                $parameters[$token] = '';
575
            }
576
577 12
            $result = $expressionLanguage->evaluate($expression, $parameters);
578
579 12
            if ($result) {
580 3
                $policyEffects[0] = Effector::ALLOW;
581
            } else {
582 12
                $policyEffects[0] = Effector::INDETERMINATE;
583
            }
584
        }
585
586 111
        $result = $this->eft->mergeEffects($this->model['e']['e']->value, $policyEffects, $matcherResults);
587
588 111
        if (Log::getLogger()->isEnabled()) {
589 24
            $reqStr = 'Request: ';
590 24
            $reqStr .= implode(', ', array_values($rvals));
591
592 24
            $reqStr .= sprintf(' ---> %s', (string) $result);
593 24
            Log::logPrint($reqStr);
594
        }
595
596 111
        return $result;
597
    }
598
599
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
600
     * @param array $functions
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
601
     *
602
     * @return ExpressionLanguage
603
     */
604 111
    protected function getExpressionLanguage(array $functions): ExpressionLanguage
605
    {
606 111
        $expressionLanguage = new ExpressionLanguage();
607 111
        foreach ($functions as $key => $func) {
608
            $expressionLanguage->register($key, function (...$args) use ($key) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
609
                return sprintf($key.'(%1$s)', implode(',', $args));
610
            }, function ($arguments, ...$args) use ($func) {
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 12.
Loading history...
611 51
                return $func(...$args);
612 111
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
613
        }
614
615 111
        return $expressionLanguage;
616
    }
617
618
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
619
     * @param string $expString
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
620
     *
621
     * @return string
622
     */
623 111
    protected function getExpString(string $expString): string
624
    {
625 111
        return preg_replace_callback(
626 111
            '/([\s\S]*in\s+)\(([\s\S]+)\)([\s\S]*)/',
627
            function ($m) {
628
                return $m[1].'['.$m[2].']'.$m[3];
629 111
            },
630 74
            $expString
631
        );
632
    }
633
634
    /**
635
     * decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act).
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
636
     *
637
     * @param mixed ...$rvals
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
638
     *
639
     * @return bool
640
     *
641
     * @throws CasbinException
642
     */
643 111
    public function enforce(...$rvals): bool
644
    {
645 111
        return $this->enforcing('', ...$rvals);
646
    }
647
648
    /**
649
     * use a custom matcher to decides whether a "subject" can access a "object" with the operation "action",
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
650
     * input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is "".
651
     *
652
     * @param string $matcher
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
653
     * @param mixed  ...$rvals
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
654
     *
655
     * @return bool
656
     *
657
     * @throws CasbinException
658
     */
659
    public function enforceWithMatcher(string $matcher, ...$rvals): bool
660
    {
661
        return $this->enforcing($matcher, ...$rvals);
662
    }
663
}
664