Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
41.96% |
47 / 112 |
|
37.50% |
3 / 8 |
CRAP | |
0.00% |
0 / 1 |
DBSiteStore | |
42.34% |
47 / 111 |
|
37.50% |
3 / 8 |
124.40 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSites | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
loadSites | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
30 | |||
getSite | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
saveSite | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
saveSites | |
65.31% |
32 / 49 |
|
0.00% |
0 / 1 |
14.18 | |||
reset | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
clear | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Site; |
22 | |
23 | use Wikimedia\Rdbms\IConnectionProvider; |
24 | use Wikimedia\Rdbms\IDatabase; |
25 | |
26 | /** |
27 | * Holds a list of sites stored in the database. |
28 | * |
29 | * @since 1.25 |
30 | * @ingroup Site |
31 | * @author Jeroen De Dauw < jeroendedauw@gmail.com > |
32 | * @author Daniel Kinzler |
33 | */ |
34 | class DBSiteStore implements SiteStore { |
35 | /** @var SiteList|null */ |
36 | protected $sites = null; |
37 | /** @var IConnectionProvider */ |
38 | private $dbProvider; |
39 | |
40 | /** |
41 | * @since 1.27 |
42 | * @param IConnectionProvider $dbProvider |
43 | */ |
44 | public function __construct( IConnectionProvider $dbProvider ) { |
45 | $this->dbProvider = $dbProvider; |
46 | } |
47 | |
48 | /** |
49 | * @see SiteStore::getSites |
50 | * |
51 | * @since 1.25 |
52 | * @return SiteList |
53 | */ |
54 | public function getSites() { |
55 | $this->loadSites(); |
56 | |
57 | return $this->sites; |
58 | } |
59 | |
60 | /** |
61 | * Fetches the site from the database and loads them into the sites field. |
62 | * |
63 | * @since 1.25 |
64 | */ |
65 | protected function loadSites() { |
66 | $this->sites = new SiteList(); |
67 | |
68 | $dbr = $this->dbProvider->getReplicaDatabase(); |
69 | |
70 | $res = $dbr->newSelectQueryBuilder() |
71 | ->select( [ |
72 | 'site_id', |
73 | 'site_global_key', |
74 | 'site_type', |
75 | 'site_group', |
76 | 'site_source', |
77 | 'site_language', |
78 | 'site_protocol', |
79 | 'site_domain', |
80 | 'site_data', |
81 | 'site_forward', |
82 | 'site_config', |
83 | ] ) |
84 | ->from( 'sites' ) |
85 | ->orderBy( 'site_global_key' ) |
86 | ->caller( __METHOD__ )->fetchResultSet(); |
87 | |
88 | foreach ( $res as $row ) { |
89 | $site = Site::newForType( $row->site_type ); |
90 | $site->setGlobalId( $row->site_global_key ); |
91 | $site->setInternalId( (int)$row->site_id ); |
92 | $site->setForward( (bool)$row->site_forward ); |
93 | $site->setGroup( $row->site_group ); |
94 | $site->setLanguageCode( $row->site_language === '' |
95 | ? null |
96 | : $row->site_language |
97 | ); |
98 | $site->setSource( $row->site_source ); |
99 | $site->setExtraData( unserialize( $row->site_data ) ); |
100 | $site->setExtraConfig( unserialize( $row->site_config ) ); |
101 | $this->sites[] = $site; |
102 | } |
103 | |
104 | // Batch load the local site identifiers. |
105 | $ids = $dbr->newSelectQueryBuilder() |
106 | ->select( [ 'si_site', 'si_type', 'si_key', ] ) |
107 | ->from( 'site_identifiers' ) |
108 | ->caller( __METHOD__ )->fetchResultSet(); |
109 | |
110 | foreach ( $ids as $id ) { |
111 | if ( $this->sites->hasInternalId( $id->si_site ) ) { |
112 | $site = $this->sites->getSiteByInternalId( $id->si_site ); |
113 | $site->addLocalId( $id->si_type, $id->si_key ); |
114 | $this->sites->setSite( $site ); |
115 | } |
116 | } |
117 | } |
118 | |
119 | /** |
120 | * @see SiteStore::getSite |
121 | * |
122 | * @since 1.25 |
123 | * @param string $globalId |
124 | * @return Site|null |
125 | */ |
126 | public function getSite( $globalId ) { |
127 | if ( $this->sites === null ) { |
128 | $this->sites = $this->getSites(); |
129 | } |
130 | |
131 | return $this->sites->hasSite( $globalId ) ? $this->sites->getSite( $globalId ) : null; |
132 | } |
133 | |
134 | /** |
135 | * @see SiteStore::saveSite |
136 | * |
137 | * @since 1.25 |
138 | * @param Site $site |
139 | * @return bool Success indicator |
140 | */ |
141 | public function saveSite( Site $site ) { |
142 | return $this->saveSites( [ $site ] ); |
143 | } |
144 | |
145 | /** |
146 | * @see SiteStore::saveSites |
147 | * |
148 | * @since 1.25 |
149 | * @param Site[] $sites |
150 | * @return bool Success indicator |
151 | */ |
152 | public function saveSites( array $sites ) { |
153 | if ( !$sites ) { |
154 | return true; |
155 | } |
156 | |
157 | $dbw = $this->dbProvider->getPrimaryDatabase(); |
158 | |
159 | $dbw->startAtomic( __METHOD__ ); |
160 | |
161 | $internalIds = []; |
162 | $localIds = []; |
163 | |
164 | foreach ( $sites as $site ) { |
165 | if ( $site->getInternalId() !== null ) { |
166 | $internalIds[] = $site->getInternalId(); |
167 | } |
168 | |
169 | $fields = [ |
170 | // Site data |
171 | 'site_global_key' => $site->getGlobalId(), // TODO: check not null |
172 | 'site_type' => $site->getType(), |
173 | 'site_group' => $site->getGroup(), |
174 | 'site_source' => $site->getSource(), |
175 | 'site_language' => $site->getLanguageCode() ?? '', |
176 | 'site_protocol' => $site->getProtocol(), |
177 | 'site_domain' => strrev( $site->getDomain() ?? '' ) . '.', |
178 | 'site_data' => serialize( $site->getExtraData() ), |
179 | |
180 | // Site config |
181 | 'site_forward' => $site->shouldForward() ? 1 : 0, |
182 | 'site_config' => serialize( $site->getExtraConfig() ), |
183 | ]; |
184 | |
185 | $rowId = $site->getInternalId(); |
186 | if ( $rowId !== null ) { |
187 | $dbw->newUpdateQueryBuilder() |
188 | ->update( 'sites' ) |
189 | ->set( $fields ) |
190 | ->where( [ 'site_id' => $rowId ] ) |
191 | ->caller( __METHOD__ )->execute(); |
192 | } else { |
193 | $dbw->newInsertQueryBuilder() |
194 | ->insertInto( 'sites' ) |
195 | ->row( $fields ) |
196 | ->caller( __METHOD__ )->execute(); |
197 | $rowId = $dbw->insertId(); |
198 | } |
199 | |
200 | foreach ( $site->getLocalIds() as $idType => $ids ) { |
201 | foreach ( $ids as $id ) { |
202 | $localIds[] = [ $rowId, $idType, $id ]; |
203 | } |
204 | } |
205 | } |
206 | |
207 | if ( $internalIds !== [] ) { |
208 | $dbw->newDeleteQueryBuilder() |
209 | ->deleteFrom( 'site_identifiers' ) |
210 | ->where( [ 'si_site' => $internalIds ] ) |
211 | ->caller( __METHOD__ )->execute(); |
212 | } |
213 | |
214 | foreach ( $localIds as $localId ) { |
215 | $dbw->newInsertQueryBuilder() |
216 | ->insertInto( 'site_identifiers' ) |
217 | ->row( [ 'si_site' => $localId[0], 'si_type' => $localId[1], 'si_key' => $localId[2] ] ) |
218 | ->caller( __METHOD__ )->execute(); |
219 | } |
220 | |
221 | $dbw->endAtomic( __METHOD__ ); |
222 | |
223 | $this->reset(); |
224 | |
225 | return true; |
226 | } |
227 | |
228 | /** |
229 | * Resets the SiteList |
230 | * |
231 | * @since 1.25 |
232 | */ |
233 | public function reset() { |
234 | $this->sites = null; |
235 | } |
236 | |
237 | /** |
238 | * Clears the list of sites stored in the database. |
239 | * |
240 | * @see SiteStore::clear() |
241 | */ |
242 | public function clear() { |
243 | $dbw = $this->dbProvider->getPrimaryDatabase(); |
244 | |
245 | $dbw->startAtomic( __METHOD__ ); |
246 | $dbw->newDeleteQueryBuilder() |
247 | ->deleteFrom( 'sites' ) |
248 | ->where( IDatabase::ALL_ROWS ) |
249 | ->caller( __METHOD__ )->execute(); |
250 | $dbw->newDeleteQueryBuilder() |
251 | ->deleteFrom( 'site_identifiers' ) |
252 | ->where( IDatabase::ALL_ROWS ) |
253 | ->caller( __METHOD__ )->execute(); |
254 | $dbw->endAtomic( __METHOD__ ); |
255 | |
256 | $this->reset(); |
257 | } |
258 | |
259 | } |
260 | |
261 | /** @deprecated class alias since 1.42 */ |
262 | class_alias( DBSiteStore::class, 'DBSiteStore' ); |