1111use Casbin \Persist \UpdatableAdapter ;
1212use Closure ;
1313use Doctrine \DBAL \Configuration ;
14+ use Doctrine \DBAL \DBALException ;
1415use Doctrine \DBAL \Driver \ResultStatement ;
15- use Doctrine \DBAL \Driver \Statement ;
1616use Doctrine \DBAL \DriverManager ;
1717use Doctrine \DBAL \Connection ;
1818use Doctrine \DBAL \Exception ;
1919use Doctrine \DBAL \Query \Expression \CompositeExpression ;
20+ use Doctrine \DBAL \Result ;
21+ use Doctrine \DBAL \Schema \Schema ;
2022use Throwable ;
2123
2224/**
@@ -47,6 +49,11 @@ class Adapter implements FilteredAdapter, BatchAdapter, UpdatableAdapter
4749 */
4850 private $ filtered = false ;
4951
52+ /**
53+ * @var string[]
54+ */
55+ protected $ columns = ['p_type ' , 'v0 ' , 'v1 ' , 'v2 ' , 'v3 ' , 'v4 ' , 'v5 ' ];
56+
5057 /**
5158 * Adapter constructor.
5259 *
@@ -93,7 +100,7 @@ public function initTable()
93100 {
94101 $ sm = $ this ->connection ->getSchemaManager ();
95102 if (!$ sm ->tablesExist ([$ this ->policyTableName ])) {
96- $ schema = new \ Doctrine \ DBAL \ Schema \ Schema ();
103+ $ schema = new Schema ();
97104 $ table = $ schema ->createTable ($ this ->policyTableName );
98105 $ table ->addColumn ('id ' , 'integer ' , array ('autoincrement ' => true ));
99106 $ table ->addColumn ('p_type ' , 'string ' , ['notnull ' => false ]);
@@ -144,10 +151,7 @@ public function loadPolicy(Model $model): void
144151 $ stmt = $ queryBuilder ->select ('p_type ' , 'v0 ' , 'v1 ' , 'v2 ' , 'v3 ' , 'v4 ' , 'v5 ' )->from ($ this ->policyTableName )->execute ();
145152
146153 while ($ row = $ this ->fetch ($ stmt )) {
147- $ line = implode (', ' , array_filter ($ row , function ($ val ) {
148- return '' != $ val && !is_null ($ val );
149- }));
150- $ this ->loadPolicyLine (trim ($ line ), $ model );
154+ $ this ->loadPolicyArray ($ this ->filterRule ($ row ), $ model );
151155 }
152156 }
153157
@@ -228,8 +232,7 @@ public function addPolicy(string $sec, string $ptype, array $rule): void
228232 * @param string $ptype
229233 * @param string[][] $rules
230234 *
231- * @throws Exception
232- * @throws \Doctrine\DBAL\DBALException
235+ * @throws DBALException
233236 */
234237 public function addPolicies (string $ sec , string $ ptype , array $ rules ): void
235238 {
@@ -306,6 +309,41 @@ public function removePolicies(string $sec, string $ptype, array $rules): void
306309 });
307310 }
308311
312+ /**
313+ * @param string $sec
314+ * @param string $ptype
315+ * @param int $fieldIndex
316+ * @param string|null ...$fieldValues
317+ * @return array
318+ * @throws Throwable
319+ */
320+ public function _removeFilteredPolicy (string $ sec , string $ ptype , int $ fieldIndex , ?string ...$ fieldValues ): array
321+ {
322+ $ removedRules = [];
323+ $ this ->connection ->transactional (function (Connection $ conn ) use ($ ptype , $ fieldIndex , $ fieldValues , &$ removedRules ) {
324+ $ queryBuilder = $ conn ->createQueryBuilder ();
325+ $ queryBuilder ->where ('p_type = :ptype ' )->setParameter ('ptype ' , $ ptype );
326+
327+ foreach ($ fieldValues as $ value ) {
328+ if (!is_null ($ value ) && $ value !== '' ) {
329+ $ key = 'v ' . strval ($ fieldIndex );
330+ $ queryBuilder ->andWhere ($ key . ' = : ' . $ key )->setParameter ($ key , $ value );
331+ }
332+ $ fieldIndex ++;
333+ }
334+
335+ $ stmt = $ queryBuilder ->select (...$ this ->columns )->from ($ this ->policyTableName )->execute ();
336+
337+ while ($ row = $ this ->fetch ($ stmt )) {
338+ $ removedRules [] = $ this ->filterRule ($ row );
339+ }
340+
341+ $ queryBuilder ->delete ($ this ->policyTableName )->execute ();
342+ });
343+
344+ return $ removedRules ;
345+ }
346+
309347 /**
310348 * RemoveFilteredPolicy removes policy rules that match the filter from the storage.
311349 * This is part of the Auto-Save feature.
@@ -314,23 +352,11 @@ public function removePolicies(string $sec, string $ptype, array $rules): void
314352 * @param string $ptype
315353 * @param int $fieldIndex
316354 * @param string ...$fieldValues
317- * @throws Exception
355+ * @throws Exception|Throwable
318356 */
319357 public function removeFilteredPolicy (string $ sec , string $ ptype , int $ fieldIndex , string ...$ fieldValues ): void
320358 {
321- $ queryBuilder = $ this ->connection ->createQueryBuilder ();
322- $ queryBuilder ->where ('p_type = :ptype ' )->setParameter ('ptype ' , $ ptype );
323-
324- foreach (range (0 , 5 ) as $ value ) {
325- if ($ fieldIndex <= $ value && $ value < $ fieldIndex + count ($ fieldValues )) {
326- if ('' != $ val = $ fieldValues [$ value - $ fieldIndex ]) {
327- $ key = 'v ' . strval ($ value );
328- $ queryBuilder ->andWhere ($ key . ' = : ' . $ key )->setParameter ($ key , $ val );
329- }
330- }
331- }
332-
333- $ queryBuilder ->delete ($ this ->policyTableName )->execute ();
359+ $ this ->_removeFilteredPolicy ($ sec , $ ptype , $ fieldIndex , ...$ fieldValues );
334360 }
335361
336362 /**
@@ -369,6 +395,7 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $
369395 * @param string[][] $oldRules
370396 * @param string[][] $newRules
371397 * @return void
398+ * @throws Throwable
372399 */
373400 public function updatePolicies (string $ sec , string $ ptype , array $ oldRules , array $ newRules ): void
374401 {
@@ -379,6 +406,46 @@ public function updatePolicies(string $sec, string $ptype, array $oldRules, arra
379406 });
380407 }
381408
409+ /**
410+ * @param string $sec
411+ * @param string $ptype
412+ * @param array $newRules
413+ * @param int $fieldIndex
414+ * @param string ...$fieldValues
415+ * @return array
416+ * @throws Throwable
417+ */
418+ public function updateFilteredPolicies (string $ sec , string $ ptype , array $ newRules , int $ fieldIndex , ?string ...$ fieldValues ): array
419+ {
420+ $ oldRules = [];
421+ $ this ->getConnection ()->transactional (function ($ conn ) use ($ sec , $ ptype , $ newRules , $ fieldIndex , $ fieldValues , &$ oldRules ) {
422+ $ oldRules = $ this ->_removeFilteredPolicy ($ sec , $ ptype , $ fieldIndex , ...$ fieldValues );
423+ $ this ->addPolicies ($ sec , $ ptype , $ newRules );
424+ });
425+
426+ return $ oldRules ;
427+ }
428+
429+ /**
430+ * Filter the rule.
431+ *
432+ * @param array $rule
433+ * @return array
434+ */
435+ public function filterRule (array $ rule ): array
436+ {
437+ $ rule = array_values ($ rule );
438+
439+ $ i = count ($ rule ) - 1 ;
440+ for (; $ i >= 0 ; $ i --) {
441+ if ($ rule [$ i ] != "" && !is_null ($ rule [$ i ])) {
442+ break ;
443+ }
444+ }
445+
446+ return array_slice ($ rule , 0 , $ i + 1 );
447+ }
448+
382449 /**
383450 * Returns true if the loaded policy has been filtered.
384451 *
@@ -409,17 +476,29 @@ public function getConnection(): Connection
409476 return $ this ->connection ;
410477 }
411478
479+ /**
480+ * Gets columns.
481+ *
482+ * @return string[]
483+ */
484+ public function getColumns (): array
485+ {
486+ return $ this ->columns ;
487+ }
488+
412489 /**
413490 * @param mixed $stmt
414491 *
415492 * @return mixed
493+ * @throws Exception
416494 */
417- private function fetch ($ stmt )
495+ private function fetch (Result $ stmt )
418496 {
419497 if (method_exists ($ stmt , 'fetchAssociative ' )) {
420498 return $ stmt ->fetchAssociative ();
421499 }
422500
423501 return $ stmt ->fetch ();
424502 }
503+
425504}
0 commit comments