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

php-casbin / php-casbin / 15422853167

03 Jun 2025 04:34PM UTC coverage: 94.307% (-0.2%) from 94.485%
15422853167

push

github

leeqvip
refactor: Upgrade phpstan to level 8

52 of 63 new or added lines in 8 files covered. (82.54%)

2 existing lines in 1 file now uncovered.

1938 of 2055 relevant lines covered (94.31%)

231.19 hits per line

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

92.86
/src/Persist/Adapters/FileFilteredAdapter.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Casbin\Persist\Adapters;
6

7
use Casbin\Exceptions\CannotSaveFilteredPolicy;
8
use Casbin\Exceptions\CasbinException;
9
use Casbin\Exceptions\InvalidFilePathException;
10
use Casbin\Exceptions\InvalidFilterTypeException;
11
use Casbin\Persist\FilteredAdapter;
12
use Casbin\Model\Model;
13

14
/**
15
 * FilteredAdapter is the filtered file adapter for Casbin. It can load policy
16
 * from file or save policy to file and supports loading of filtered policies.
17
 *
18
 * @author techlee@qq.com
19
 */
20
class FileFilteredAdapter extends FileAdapter implements FilteredAdapter
21
{
22
    /**
23
     * filtered variable.
24
     *
25
     * @var bool
26
     */
27
    protected bool $filtered;
28

29
    /**
30
     * FileAdapter constructor.
31
     *
32
     * @param string $filePath
33
     */
34
    public function __construct(string $filePath)
35
    {
36
        $this->filtered = true;
30✔
37
        parent::__construct($filePath);
30✔
38
    }
39

40
    /**
41
     * Loads all policy rules from the storage.
42
     *
43
     * @param Model $model
44
     *
45
     * @throws CasbinException
46
     */
47
    public function loadPolicy(Model $model): void
48
    {
49
        $this->filtered = false;
30✔
50
        parent::loadPolicy($model);
30✔
51
    }
52

53
    /**
54
     * Loads only policy rules that match the filter.
55
     *
56
     * @param Model $model
57
     * @param mixed $filter
58
     *
59
     * @throws CasbinException
60
     */
61
    public function loadFilteredPolicy(Model $model, $filter): void
62
    {
63
        if (is_null($filter)) {
30✔
64
            $this->loadPolicy($model);
10✔
65

66
            return;
10✔
67
        }
68

69
        if (!file_exists($this->filePath)) {
30✔
70
            throw new InvalidFilePathException('invalid file path, file path cannot be empty');
10✔
71
        }
72

73
        if (!$filter instanceof Filter) {
30✔
74
            throw new InvalidFilterTypeException('invalid filter type');
10✔
75
        }
76

77
        $this->loadFilteredPolicyFile($model, $filter, [$this, 'loadPolicyLine']);
30✔
78
        $this->filtered = true;
30✔
79
    }
80

81
    /**
82
     * Returns true if the loaded policy has been filtered.
83
     *
84
     * @return bool
85
     */
86
    public function isFiltered(): bool
87
    {
88
        return $this->filtered;
30✔
89
    }
90

91
    /**
92
     * SavePolicy saves all policy rules to the storage.
93
     *
94
     * @param Model $model
95
     * @throws CannotSaveFilteredPolicy|CasbinException
96
     */
97
    public function savePolicy(Model $model): void
98
    {
99
        if ($this->filtered) {
20✔
100
            throw new CannotSaveFilteredPolicy('cannot save a filtered policy');
20✔
101
        }
102

103
        parent::savePolicy($model);
×
104
    }
105

106
    /**
107
     * LoadFilteredPolicyFile function.
108
     *
109
     * @param Model $model
110
     * @param Filter $filter
111
     * @param callable $handler
112
     * @throws InvalidFilePathException
113
     */
114
    protected function loadFilteredPolicyFile(Model $model, Filter $filter, callable $handler): void
115
    {
116
        $file = fopen($this->filePath, 'rb');
30✔
117

118
        if (false === $file) {
30✔
119
            throw new InvalidFilePathException(sprintf('Unable to access to the specified path "%s"', $this->filePath));
×
120
        }
121

122
        while ($line = fgets($file)) {
30✔
123
            $line = trim($line);
30✔
124
            if (self::filterLine($line, $filter)) {
30✔
125
                continue;
30✔
126
            }
127
            call_user_func($handler, $line, $model);
30✔
128
        }
129
    }
130

131
    /**
132
     * FilterLine function.
133
     *
134
     * @param string $line
135
     * @param Filter $filter
136
     *
137
     * @return bool
138
     */
139
    protected static function filterLine(string $line, Filter $filter): bool
140
    {
141
        $p = explode(',', $line);
30✔
142
        if (0 == strlen($p[0])) {
30✔
143
            return true;
30✔
144
        }
145

146
        $filterSlice = match (trim($p[0])) {
30✔
147
            'p' => $filter->p,
30✔
148
            'g' => $filter->g,
30✔
149
            default => []
30✔
150
        };
30✔
151

152
        return self::filterWords($p, $filterSlice);
30✔
153
    }
154

155
    /**
156
     * FilterWords function.
157
     *
158
     * @param array $line
159
     * @param array $filter
160
     *
161
     * @return bool
162
     */
163
    protected static function filterWords(array $line, array $filter): bool
164
    {
165
        if (count($line) < count($filter) + 1) {
30✔
166
            return true;
×
167
        }
168
        
169
        $skipLine = false;
30✔
170
        foreach ($filter as $i => $v) {
30✔
171
            if (strlen($v) > 0 && \trim($v) != trim($line[$i + 1])) {
30✔
172
                $skipLine = true;
30✔
173

174
                break;
30✔
175
            }
176
        }
177

178
        return $skipLine;
30✔
179
    }
180
}
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