1
+ <?php
2
+
3
+ /**
4
+ * @desc Policy Adapter
5
+ * @author Tinywan(ShaoBo Wan)
6
+ * @date 2022/01/12 10:37
7
+ */
8
+
9
+ declare (strict_types=1 );
10
+
11
+ namespace Casbin \WebmanPermission \Adapter ;
12
+
13
+ use Casbin \Model \Model ;
14
+ use Casbin \Persist \Adapter ;
15
+ use Casbin \Persist \AdapterHelper ;
16
+ use Casbin \Persist \UpdatableAdapter ;
17
+ use Casbin \Persist \BatchAdapter ;
18
+ use Casbin \Persist \FilteredAdapter ;
19
+ use Casbin \Persist \Adapters \Filter ;
20
+ use Casbin \Exceptions \InvalidFilterTypeException ;
21
+ use Casbin \WebmanPermission \Model \LaravelRuleModel ;
22
+ use Casbin \WebmanPermission \Model \RuleModel ;
23
+ use Illuminate \Support \Facades \DB ;
24
+
25
+ /**
26
+ * DatabaseAdapter.
27
+ *
28
+
29
+ */
30
+ class LaravelDatabaseAdapter implements Adapter, UpdatableAdapter, BatchAdapter, FilteredAdapter
31
+ {
32
+ use AdapterHelper;
33
+
34
+ /**
35
+ * @var bool
36
+ */
37
+ private bool $ filtered = false ;
38
+
39
+ /**
40
+ * RuleModel model.
41
+ *
42
+ * @var LaravelRuleModel
43
+ */
44
+ protected $ model ;
45
+
46
+ /**
47
+ * the DatabaseAdapter constructor.
48
+ *
49
+ * @param RuleModel $model
50
+ */
51
+ public function __construct (RuleModel $ model )
52
+ {
53
+ $ this ->model = $ model ;
54
+ }
55
+
56
+ /**
57
+ * savePolicyLine function.
58
+ *
59
+ * @param string $ptype
60
+ * @param array $rule
61
+ *
62
+ * @return void
63
+ */
64
+ public function savePolicyLine (string $ ptype , array $ rule )
65
+ {
66
+ $ col ['ptype ' ] = $ ptype ;
67
+ foreach ($ rule as $ key => $ value ) {
68
+ $ col ['v ' . strval ($ key ) . '' ] = $ value ;
69
+ }
70
+ $ this ->model ->create ($ col );
71
+ }
72
+
73
+ /**
74
+ * loads all policy rules from the storage.
75
+ *
76
+ * @param Model $model
77
+ */
78
+ public function loadPolicy (Model $ model ): void
79
+ {
80
+ $ rows = $ this ->model ->getAllFromCache ();
81
+ foreach ($ rows as $ row ) {
82
+ $ line = implode (', ' , array_filter (array_slice ($ row , 1 ), function ($ val ) {
83
+ return '' != $ val && !is_null ($ val );
84
+ }));
85
+ $ this ->loadPolicyLine (trim ($ line ), $ model );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * saves all policy rules to the storage.
91
+ *
92
+ * @param Model $model
93
+ */
94
+ public function savePolicy (Model $ model ): void
95
+ {
96
+ foreach ($ model ['p ' ] as $ ptype => $ ast ) {
97
+ foreach ($ ast ->policy as $ rule ) {
98
+ $ this ->savePolicyLine ($ ptype , $ rule );
99
+ }
100
+ }
101
+
102
+ foreach ($ model ['g ' ] as $ ptype => $ ast ) {
103
+ foreach ($ ast ->policy as $ rule ) {
104
+ $ this ->savePolicyLine ($ ptype , $ rule );
105
+ }
106
+ }
107
+ }
108
+
109
+ /**
110
+ * adds a policy rule to the storage.
111
+ * This is part of the Auto-Save feature.
112
+ *
113
+ * @param string $sec
114
+ * @param string $ptype
115
+ * @param array $rule
116
+ */
117
+ public function addPolicy (string $ sec , string $ ptype , array $ rule ): void
118
+ {
119
+ $ this ->savePolicyLine ($ ptype , $ rule );
120
+ }
121
+
122
+ /**
123
+ * Adds a policy rules to the storage.
124
+ * This is part of the Auto-Save feature.
125
+ *
126
+ * @param string $sec
127
+ * @param string $ptype
128
+ * @param string[][] $rules
129
+ */
130
+ public function addPolicies (string $ sec , string $ ptype , array $ rules ): void
131
+ {
132
+ $ cols = [];
133
+ $ i = 0 ;
134
+
135
+ foreach ($ rules as $ rule ) {
136
+ $ temp ['ptype ' ] = $ ptype ;
137
+ $ temp ['created_at ' ] = date ("Y-m-d h:m:i " );
138
+ $ temp ['updated_at ' ] = $ temp ['created_at ' ];
139
+ foreach ($ rule as $ key => $ value ) {
140
+ $ temp ['v ' . strval ($ key )] = $ value ;
141
+ }
142
+ $ cols [$ i ++] = $ temp ?? [];
143
+ $ temp = [];
144
+ }
145
+ $ this ->model ->insert ($ cols );
146
+ LaravelRuleModel::fireModelEvent ('saved ' );
147
+ }
148
+
149
+ /**
150
+ * This is part of the Auto-Save feature.
151
+ *
152
+ * @param string $sec
153
+ * @param string $ptype
154
+ * @param array $rule
155
+ */
156
+ public function removePolicy (string $ sec , string $ ptype , array $ rule ): void
157
+ {
158
+ $ instance = $ this ->model ->where ('ptype ' , $ ptype );
159
+ foreach ($ rule as $ key => $ value ) {
160
+ $ instance ->where ('v ' . strval ($ key ), $ value );
161
+ }
162
+ $ instance ->delete ();
163
+ LaravelRuleModel::fireModelEvent ('deleted ' );
164
+ }
165
+
166
+ /**
167
+ * Removes policy rules from the storage.
168
+ * This is part of the Auto-Save feature.
169
+ *
170
+ * @param string $sec
171
+ * @param string $ptype
172
+ * @param string[][] $rules
173
+ */
174
+ public function removePolicies (string $ sec , string $ ptype , array $ rules ): void
175
+ {
176
+ DB ::transaction (function () use ($ sec , $ ptype , $ rules ) {
177
+ foreach ($ rules as $ rule ) {
178
+ $ this ->removePolicy ($ sec , $ ptype , $ rule );
179
+ }
180
+ });
181
+ }
182
+
183
+ /**
184
+ * RemoveFilteredPolicy removes policy rules that match the filter from the storage.
185
+ * This is part of the Auto-Save feature.
186
+ *
187
+ * @param string $sec
188
+ * @param string $ptype
189
+ * @param int $fieldIndex
190
+ * @param string ...$fieldValues
191
+ */
192
+ public function removeFilteredPolicy (string $ sec , string $ ptype , int $ fieldIndex , string ...$ fieldValues ): void
193
+ {
194
+ $ instance = $ this ->model ->where ('ptype ' , $ ptype );
195
+ foreach (range (0 , 5 ) as $ value ) {
196
+ if ($ fieldIndex <= $ value && $ value < $ fieldIndex + count ($ fieldValues )) {
197
+ if ('' != $ fieldValues [$ value - $ fieldIndex ]) {
198
+ $ instance ->where ('v ' . strval ($ value ), $ fieldValues [$ value - $ fieldIndex ]);
199
+ }
200
+ }
201
+ }
202
+
203
+ $ oldP = $ instance ->get ()->makeHidden (['created_at ' ,'updated_at ' , 'id ' , 'ptype ' ])->toArray ();
204
+ foreach ($ oldP as &$ item ) {
205
+ $ item = $ this ->filterRule ($ item );
206
+ $ removedRules [] = $ item ;
207
+ }
208
+ $ instance ->delete ();
209
+ LaravelRuleModel::fireModelEvent ('deleted ' );
210
+ }
211
+
212
+ /**
213
+ * Updates a policy rule from storage.
214
+ * This is part of the Auto-Save feature.
215
+ *
216
+ * @param string $sec
217
+ * @param string $ptype
218
+ * @param string[] $oldRule
219
+ * @param string[] $newPolicy
220
+ */
221
+ public function updatePolicy (string $ sec , string $ ptype , array $ oldRule , array $ newPolicy ): void
222
+ {
223
+ $ instance = $ this ->model ->where ('ptype ' , $ ptype );
224
+ foreach ($ oldRule as $ key => $ value ) {
225
+ $ instance ->where ('v ' . strval ($ key ), $ value );
226
+ }
227
+ $ instance = $ instance ->first ();
228
+
229
+ $ update = [];
230
+ foreach ($ newPolicy as $ key => $ value ) {
231
+ $ update ['v ' . $ key ] = $ value ;
232
+ }
233
+
234
+ $ instance ->update ($ update );
235
+ LaravelRuleModel::fireModelEvent ('saved ' );
236
+ }
237
+
238
+ /**
239
+ * UpdatePolicies updates some policy rules to storage, like DB, redis.
240
+ *
241
+ * @param string $sec
242
+ * @param string $ptype
243
+ * @param string[][] $oldRules
244
+ * @param string[][] $newRules
245
+ * @return void
246
+ */
247
+ public function updatePolicies (string $ sec , string $ ptype , array $ oldRules , array $ newRules ): void
248
+ {
249
+ DB ::transaction (function () use ($ sec , $ ptype , $ oldRules , $ newRules ) {
250
+ foreach ($ oldRules as $ i => $ oldRule ) {
251
+ $ this ->updatePolicy ($ sec , $ ptype , $ oldRule , $ newRules [$ i ]);
252
+ }
253
+ });
254
+ }
255
+
256
+ /**
257
+ * UpdateFilteredPolicies deletes old rules and adds new rules.
258
+ *
259
+ * @param string $sec
260
+ * @param string $ptype
261
+ * @param array $newPolicies
262
+ * @param integer $fieldIndex
263
+ * @param string ...$fieldValues
264
+ * @return array
265
+ */
266
+ public function updateFilteredPolicies (string $ sec , string $ ptype , array $ newPolicies , int $ fieldIndex , string ...$ fieldValues ): array
267
+ {
268
+ $ oldRules = [];
269
+ \Illuminate \Support \Facades \DB ::transaction (function () use ($ sec , $ ptype , $ fieldIndex , $ fieldValues , $ newPolicies , &$ oldRules ) {
270
+ $ oldRules = $ this ->_removeFilteredPolicy ($ sec , $ ptype , $ fieldIndex , ...$ fieldValues );
271
+ $ this ->addPolicies ($ sec , $ ptype , $ newPolicies );
272
+ });
273
+ return $ oldRules ;
274
+ }
275
+
276
+ /**
277
+ * Returns true if the loaded policy has been filtered.
278
+ *
279
+ * @return bool
280
+ */
281
+ public function isFiltered (): bool
282
+ {
283
+ return $ this ->filtered ;
284
+ }
285
+
286
+ /**
287
+ * Sets filtered parameter.
288
+ *
289
+ * @param bool $filtered
290
+ */
291
+ public function setFiltered (bool $ filtered ): void
292
+ {
293
+ $ this ->filtered = $ filtered ;
294
+ }
295
+
296
+ /**
297
+ * Loads only policy rules that match the filter.
298
+ *
299
+ * @param Model $model
300
+ * @param mixed $filter
301
+ */
302
+ public function loadFilteredPolicy (Model $ model , $ filter ): void
303
+ {
304
+ $ instance = $ this ->model ;
305
+ if (is_string ($ filter )) {
306
+ $ instance = $ instance ->whereRaw ($ filter );
307
+ } elseif ($ filter instanceof Filter) {
308
+ foreach ($ filter ->p as $ k => $ v ) {
309
+ $ where [$ v ] = $ filter ->g [$ k ];
310
+ $ instance = $ instance ->where ($ v , $ filter ->g [$ k ]);
311
+ }
312
+ } elseif ($ filter instanceof \Closure) {
313
+ $ instance = $ instance ->where ($ filter );
314
+ } else {
315
+ throw new InvalidFilterTypeException ('invalid filter type ' );
316
+ }
317
+ $ rows = $ instance ->get ()->makeHidden (['created_at ' ,'updated_at ' , 'id ' ])->toArray ();
318
+ foreach ($ rows as $ row ) {
319
+ $ row = array_filter ($ row , function ($ value ) { return !is_null ($ value ) && $ value !== '' ; });
320
+ $ line = implode (', ' , array_filter ($ row , function ($ val ) {
321
+ return '' != $ val && !is_null ($ val );
322
+ }));
323
+ $ this ->loadPolicyLine (trim ($ line ), $ model );
324
+ }
325
+ $ this ->setFiltered (true );
326
+ }
327
+ }
0 commit comments