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