Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
89.55% |
60 / 67 |
|
77.78% |
7 / 9 |
CRAP | |
0.00% |
0 / 1 |
CampaignStore | |
89.55% |
60 / 67 |
|
77.78% |
7 / 9 |
18.37 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSelectFields | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
getSelectTables | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getJoinConds | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
newRecordFromRow | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
4 | |||
newSelectQueryBuilder | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
upsertCampaign | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
3 | |||
deleteCampaignByPageId | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getCampaignByDBKey | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\MediaUploader\Campaign; |
4 | |
5 | use DBAccessObjectUtils; |
6 | use FormatJson; |
7 | use IDBAccessObject; |
8 | use stdClass; |
9 | use Title; |
10 | use Wikimedia\Rdbms\ILoadBalancer; |
11 | |
12 | /** |
13 | * Provides access to the mu_campaign database table. |
14 | */ |
15 | class CampaignStore implements IDBAccessObject { |
16 | |
17 | // Constants controlling how much information from the DB should be retrieved. |
18 | /** @var int Only the id, enabled and validity fields */ |
19 | public const SELECT_MINIMAL = 0; |
20 | /** @var int The content of the campaign */ |
21 | public const SELECT_CONTENT = 1; |
22 | /** @var int The title of the corresponding page */ |
23 | public const SELECT_TITLE = 2; |
24 | |
25 | /** @var ILoadBalancer */ |
26 | private $loadBalancer; |
27 | |
28 | /** |
29 | * @param ILoadBalancer $loadBalancer |
30 | * |
31 | * @internal only for use by ServiceWiring |
32 | */ |
33 | public function __construct( ILoadBalancer $loadBalancer ) { |
34 | $this->loadBalancer = $loadBalancer; |
35 | } |
36 | |
37 | /** |
38 | * Returns an array of all fields in the mu_campaign table. |
39 | * |
40 | * @param int $selectFlags Bitfield of self::SELECT_* constants |
41 | * |
42 | * @return string[] |
43 | */ |
44 | public function getSelectFields( |
45 | int $selectFlags = self::SELECT_MINIMAL |
46 | ): array { |
47 | $fields = [ |
48 | 'campaign_page_id', |
49 | 'campaign_enabled', |
50 | 'campaign_validity', |
51 | ]; |
52 | if ( self::SELECT_CONTENT & $selectFlags ) { |
53 | $fields[] = 'campaign_content'; |
54 | } |
55 | if ( self::SELECT_TITLE & $selectFlags ) { |
56 | $fields[] = 'page_title'; |
57 | $fields[] = 'page_namespace'; |
58 | } |
59 | |
60 | return $fields; |
61 | } |
62 | |
63 | /** |
64 | * Returns an array of tables for SELECT queries. |
65 | * |
66 | * @param int $selectFlags Bitfield of self::SELECT_* constants |
67 | * |
68 | * @return string[] |
69 | */ |
70 | public function getSelectTables( |
71 | int $selectFlags = self::SELECT_MINIMAL |
72 | ): array { |
73 | $tables = [ 'mu_campaign' ]; |
74 | if ( self::SELECT_TITLE & $selectFlags ) { |
75 | $tables[] = 'page'; |
76 | } |
77 | |
78 | return $tables; |
79 | } |
80 | |
81 | /** |
82 | * Returns an array of join conditions for SELECT queries. |
83 | * |
84 | * @param int $selectFlags Bitfield of self::SELECT_* constants |
85 | * |
86 | * @return array |
87 | */ |
88 | public function getJoinConds( |
89 | int $selectFlags = self::SELECT_MINIMAL |
90 | ): array { |
91 | if ( self::SELECT_TITLE & $selectFlags ) { |
92 | return [ 'page' => [ 'JOIN', 'campaign_page_id = page_id' ] ]; |
93 | } |
94 | return []; |
95 | } |
96 | |
97 | /** |
98 | * Constructs a new CampaignRecord from a DB row. |
99 | * |
100 | * @param stdClass $row |
101 | * @param int $selectFlags Bitfield of self::SELECT_* constants used to |
102 | * retrieve the row from the DB. |
103 | * |
104 | * @return CampaignRecord |
105 | */ |
106 | public function newRecordFromRow( |
107 | stdClass $row, |
108 | int $selectFlags |
109 | ): CampaignRecord { |
110 | $content = null; |
111 | if ( self::SELECT_CONTENT & $selectFlags && $row->campaign_content ) { |
112 | $content = FormatJson::parse( |
113 | $row->campaign_content, |
114 | FormatJson::FORCE_ASSOC |
115 | )->getValue(); |
116 | } |
117 | |
118 | $title = null; |
119 | if ( self::SELECT_TITLE & $selectFlags ) { |
120 | // Performance hack: in case any code down the line decides to obtain |
121 | // the page ID from the Title object, we set that info artificially on |
122 | // the DB row, as we know it from the mu_campaign table. |
123 | $row->page_id = $row->campaign_page_id; |
124 | $title = Title::newFromRow( $row ); |
125 | } |
126 | |
127 | return new CampaignRecord( |
128 | $row->campaign_page_id, |
129 | (bool)$row->campaign_enabled, |
130 | $row->campaign_validity, |
131 | $content, |
132 | $title |
133 | ); |
134 | } |
135 | |
136 | /** |
137 | * Constructs a new CampaignSelectQueryBuilder. |
138 | * |
139 | * @param int $queryFlags bitfield of self::READ_* constants |
140 | * |
141 | * @return CampaignSelectQueryBuilder |
142 | */ |
143 | public function newSelectQueryBuilder( |
144 | int $queryFlags = self::READ_NORMAL |
145 | ): CampaignSelectQueryBuilder { |
146 | [ $mode, $options ] = DBAccessObjectUtils::getDBOptions( $queryFlags ); |
147 | $db = $this->loadBalancer->getConnectionRef( $mode ); |
148 | $queryBuilder = new CampaignSelectQueryBuilder( $db, $this ); |
149 | $queryBuilder->options( $options ); |
150 | |
151 | return $queryBuilder; |
152 | } |
153 | |
154 | /** |
155 | * Insert or update an existing row in the database. |
156 | * |
157 | * @param CampaignRecord $record |
158 | */ |
159 | public function upsertCampaign( CampaignRecord $record ): void { |
160 | $db = $this->loadBalancer->getConnectionRef( DB_PRIMARY ); |
161 | $content = $record->getContent(); |
162 | if ( $content !== null ) { |
163 | $content = FormatJson::encode( $content ); |
164 | } |
165 | |
166 | $set = [ |
167 | 'campaign_enabled' => $record->isEnabled() ? 1 : 0, |
168 | 'campaign_validity' => $record->getValidity(), |
169 | 'campaign_content' => $content, |
170 | ]; |
171 | $db->upsert( |
172 | 'mu_campaign', |
173 | $set + [ 'campaign_page_id' => $record->getPageId() ], |
174 | 'campaign_page_id', |
175 | $set, |
176 | __METHOD__ |
177 | ); |
178 | } |
179 | |
180 | /** |
181 | * Delete a campaign row in the DB by its page id (PK). |
182 | * |
183 | * @param int $pageId |
184 | */ |
185 | public function deleteCampaignByPageId( int $pageId ): void { |
186 | $db = $this->loadBalancer->getConnectionRef( DB_PRIMARY ); |
187 | $db->delete( |
188 | 'mu_campaign', |
189 | [ 'campaign_page_id' => $pageId ], |
190 | __METHOD__ |
191 | ); |
192 | } |
193 | |
194 | /** |
195 | * Convenience function to retrieve a record for a given DB key. |
196 | * |
197 | * @param string $dbKey |
198 | * @param int $selectFlags Bitfield of self::SELECT_* constants used to |
199 | * retrieve the row from the DB. SELECT_TITLE is always included |
200 | * regardless of this parameter. |
201 | * @param int $queryFlags bitfield of self::READ_* constants |
202 | * |
203 | * @return CampaignRecord|null |
204 | */ |
205 | public function getCampaignByDBKey( |
206 | string $dbKey, |
207 | int $selectFlags = self::SELECT_TITLE, |
208 | int $queryFlags = self::READ_NORMAL |
209 | ): ?CampaignRecord { |
210 | $selectFlags |= self::SELECT_TITLE; |
211 | return $this->newSelectQueryBuilder( $queryFlags ) |
212 | ->where( [ 'page_title' => $dbKey ] ) |
213 | ->fetchCampaignRecord( $selectFlags ); |
214 | } |
215 | } |