Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 54 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
LocalUserOptionsStore | |
0.00% |
0 / 54 |
|
0.00% |
0 / 3 |
210 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fetch | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 | |||
store | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
110 |
1 | <?php |
2 | |
3 | namespace MediaWiki\User\Options; |
4 | |
5 | use MediaWiki\User\UserIdentity; |
6 | use Wikimedia\Rdbms\DBAccessObjectUtils; |
7 | use Wikimedia\Rdbms\IConnectionProvider; |
8 | use Wikimedia\Rdbms\IDBAccessObject; |
9 | |
10 | class LocalUserOptionsStore implements UserOptionsStore { |
11 | private IConnectionProvider $dbProvider; |
12 | |
13 | /** @var array[] Cached options for each user, by user ID */ |
14 | private $optionsFromDb; |
15 | |
16 | public function __construct( IConnectionProvider $dbProvider ) { |
17 | $this->dbProvider = $dbProvider; |
18 | } |
19 | |
20 | public function fetch( |
21 | UserIdentity $user, |
22 | int $recency |
23 | ): array { |
24 | // In core, only users with local accounts may have preferences |
25 | if ( !$user->getId() ) { |
26 | return []; |
27 | } |
28 | |
29 | $dbr = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $recency ); |
30 | $res = $dbr->newSelectQueryBuilder() |
31 | ->select( [ 'up_property', 'up_value' ] ) |
32 | ->from( 'user_properties' ) |
33 | ->where( [ 'up_user' => $user->getId() ] ) |
34 | ->recency( $recency ) |
35 | ->caller( __METHOD__ )->fetchResultSet(); |
36 | |
37 | $options = []; |
38 | foreach ( $res as $row ) { |
39 | $options[$row->up_property] = (string)$row->up_value; |
40 | } |
41 | |
42 | $this->optionsFromDb[$user->getId()] = $options; |
43 | return $options; |
44 | } |
45 | |
46 | public function store( UserIdentity $user, array $updates ) { |
47 | // In core, only users with local accounts may have preferences |
48 | if ( !$user->getId() ) { |
49 | return false; |
50 | } |
51 | |
52 | $oldOptions = $this->optionsFromDb[ $user->getId() ] |
53 | ?? $this->fetch( $user, IDBAccessObject::READ_LATEST ); |
54 | $newOptions = $oldOptions; |
55 | $keysToDelete = []; |
56 | $rowsToInsert = []; |
57 | foreach ( $updates as $key => $value ) { |
58 | if ( !UserOptionsManager::isValueEqual( |
59 | $value, $oldOptions[$key] ?? null ) |
60 | ) { |
61 | // Update by deleting and reinserting |
62 | if ( array_key_exists( $key, $oldOptions ) ) { |
63 | $keysToDelete[] = $key; |
64 | unset( $newOptions[$key] ); |
65 | } |
66 | if ( $value !== null ) { |
67 | $truncValue = mb_strcut( $value, 0, |
68 | UserOptionsManager::MAX_BYTES_OPTION_VALUE ); |
69 | $rowsToInsert[] = [ |
70 | 'up_user' => $user->getId(), |
71 | 'up_property' => $key, |
72 | 'up_value' => $truncValue, |
73 | ]; |
74 | $newOptions[$key] = $truncValue; |
75 | } |
76 | } |
77 | } |
78 | if ( !count( $keysToDelete ) && !count( $rowsToInsert ) ) { |
79 | // Nothing to do |
80 | return false; |
81 | } |
82 | |
83 | // Do the DELETE |
84 | $dbw = $this->dbProvider->getPrimaryDatabase(); |
85 | if ( $keysToDelete ) { |
86 | $dbw->newDeleteQueryBuilder() |
87 | ->deleteFrom( 'user_properties' ) |
88 | ->where( [ 'up_user' => $user->getId() ] ) |
89 | ->andWhere( [ 'up_property' => $keysToDelete ] ) |
90 | ->caller( __METHOD__ )->execute(); |
91 | } |
92 | if ( $rowsToInsert ) { |
93 | // Insert the new preference rows |
94 | $dbw->newInsertQueryBuilder() |
95 | ->insertInto( 'user_properties' ) |
96 | ->ignore() |
97 | ->rows( $rowsToInsert ) |
98 | ->caller( __METHOD__ )->execute(); |
99 | } |
100 | |
101 | // Update cache |
102 | $this->optionsFromDb[$user->getId()] = $newOptions; |
103 | |
104 | return true; |
105 | } |
106 | |
107 | } |