Map dummy language codes in sites
[lhc/web/wiklou.git] / includes / site / DBSiteStore.php
1 <?php
2
3 /**
4 * Represents the site configuration of a wiki.
5 * Holds a list of sites (ie SiteList), stored in the database.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 * @since 1.25
23 *
24 * @file
25 * @ingroup Site
26 *
27 * @license GNU GPL v2+
28 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
29 * @author Daniel Kinzler
30 */
31 class DBSiteStore implements SiteStore {
32
33 /**
34 * @var SiteList|null
35 */
36 protected $sites = null;
37
38 /**
39 * @var LoadBalancer
40 */
41 private $dbLoadBalancer;
42
43 /**
44 * @var string[]
45 */
46 private $languageCodeMapping = [];
47
48 /**
49 * @since 1.27
50 *
51 * @todo: inject some kind of connection manager that is aware of the target wiki,
52 * instead of injecting a LoadBalancer.
53 *
54 * @param LoadBalancer $dbLoadBalancer
55 */
56 public function __construct( LoadBalancer $dbLoadBalancer ) {
57 $this->dbLoadBalancer = $dbLoadBalancer;
58 }
59
60 /**
61 * @see SiteStore::getSites
62 *
63 * @since 1.25
64 *
65 * @return SiteList
66 */
67 public function getSites() {
68 $this->loadSites();
69
70 return $this->sites;
71 }
72
73 /**
74 * Fetches the site from the database and loads them into the sites field.
75 *
76 * @since 1.25
77 */
78 protected function loadSites() {
79 $this->sites = new SiteList();
80
81 $dbr = $this->dbLoadBalancer->getConnection( DB_SLAVE );
82
83 $res = $dbr->select(
84 'sites',
85 [
86 'site_id',
87 'site_global_key',
88 'site_type',
89 'site_group',
90 'site_source',
91 'site_language',
92 'site_protocol',
93 'site_domain',
94 'site_data',
95 'site_forward',
96 'site_config',
97 ],
98 '',
99 __METHOD__,
100 [ 'ORDER BY' => 'site_global_key' ]
101 );
102
103 foreach ( $res as $row ) {
104 $languageCode = $row->site_language === '' ? null : $row->site_language;
105 if ( isset( $this->languageCodeMapping[ $languageCode ] ) ) {
106 $languageCode = $this->languageCodeMapping[ $languageCode ];
107 }
108
109 $site = Site::newForType( $row->site_type );
110 $site->setGlobalId( $row->site_global_key );
111 $site->setInternalId( (int)$row->site_id );
112 $site->setForward( (bool)$row->site_forward );
113 $site->setGroup( $row->site_group );
114 $site->setLanguageCode( $languageCode );
115 $site->setSource( $row->site_source );
116 $site->setExtraData( unserialize( $row->site_data ) );
117 $site->setExtraConfig( unserialize( $row->site_config ) );
118 $this->sites[] = $site;
119 }
120
121 // Batch load the local site identifiers.
122 $ids = $dbr->select(
123 'site_identifiers',
124 [
125 'si_site',
126 'si_type',
127 'si_key',
128 ],
129 [],
130 __METHOD__
131 );
132
133 foreach ( $ids as $id ) {
134 if ( $this->sites->hasInternalId( $id->si_site ) ) {
135 $site = $this->sites->getSiteByInternalId( $id->si_site );
136 $site->addLocalId( $id->si_type, $id->si_key );
137 $this->sites->setSite( $site );
138 }
139 }
140
141 $this->dbLoadBalancer->reuseConnection( $dbr );
142 }
143
144 /**
145 * @see SiteStore::getSite
146 *
147 * @since 1.25
148 *
149 * @param string $globalId
150 *
151 * @return Site|null
152 */
153 public function getSite( $globalId ) {
154 if ( $this->sites === null ) {
155 $this->sites = $this->getSites();
156 }
157
158 return $this->sites->hasSite( $globalId ) ? $this->sites->getSite( $globalId ) : null;
159 }
160
161 /**
162 * @see SiteStore::saveSite
163 *
164 * @since 1.25
165 *
166 * @param Site $site
167 *
168 * @return bool Success indicator
169 */
170 public function saveSite( Site $site ) {
171 return $this->saveSites( [ $site ] );
172 }
173
174 /**
175 * @see SiteStore::saveSites
176 *
177 * @since 1.25
178 *
179 * @param Site[] $sites
180 *
181 * @return bool Success indicator
182 */
183 public function saveSites( array $sites ) {
184 if ( empty( $sites ) ) {
185 return true;
186 }
187
188 $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER );
189
190 $dbw->startAtomic( __METHOD__ );
191
192 $success = true;
193
194 $internalIds = [];
195 $localIds = [];
196
197 foreach ( $sites as $site ) {
198 if ( $site->getInternalId() !== null ) {
199 $internalIds[] = $site->getInternalId();
200 }
201
202 $fields = [
203 // Site data
204 'site_global_key' => $site->getGlobalId(), // TODO: check not null
205 'site_type' => $site->getType(),
206 'site_group' => $site->getGroup(),
207 'site_source' => $site->getSource(),
208 'site_language' => $site->getLanguageCode() === null ? '' : $site->getLanguageCode(),
209 'site_protocol' => $site->getProtocol(),
210 'site_domain' => strrev( $site->getDomain() ) . '.',
211 'site_data' => serialize( $site->getExtraData() ),
212
213 // Site config
214 'site_forward' => $site->shouldForward() ? 1 : 0,
215 'site_config' => serialize( $site->getExtraConfig() ),
216 ];
217
218 $rowId = $site->getInternalId();
219 if ( $rowId !== null ) {
220 $success = $dbw->update(
221 'sites', $fields, [ 'site_id' => $rowId ], __METHOD__
222 ) && $success;
223 } else {
224 $rowId = $dbw->nextSequenceValue( 'sites_site_id_seq' );
225 $fields['site_id'] = $rowId;
226 $success = $dbw->insert( 'sites', $fields, __METHOD__ ) && $success;
227 $rowId = $dbw->insertId();
228 }
229
230 foreach ( $site->getLocalIds() as $idType => $ids ) {
231 foreach ( $ids as $id ) {
232 $localIds[] = [ $rowId, $idType, $id ];
233 }
234 }
235 }
236
237 if ( $internalIds !== [] ) {
238 $dbw->delete(
239 'site_identifiers',
240 [ 'si_site' => $internalIds ],
241 __METHOD__
242 );
243 }
244
245 foreach ( $localIds as $localId ) {
246 $dbw->insert(
247 'site_identifiers',
248 [
249 'si_site' => $localId[0],
250 'si_type' => $localId[1],
251 'si_key' => $localId[2],
252 ],
253 __METHOD__
254 );
255 }
256
257 $dbw->endAtomic( __METHOD__ );
258
259 $this->dbLoadBalancer->reuseConnection( $dbw );
260
261 $this->reset();
262
263 return $success;
264 }
265
266 /**
267 * Resets the SiteList
268 *
269 * @since 1.25
270 */
271 public function reset() {
272 $this->sites = null;
273 }
274
275 /**
276 * Clears the list of sites stored in the database.
277 *
278 * @see SiteStore::clear()
279 *
280 * @return bool Success
281 */
282 public function clear() {
283 $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER );
284
285 $dbw->startAtomic( __METHOD__ );
286 $ok = $dbw->delete( 'sites', '*', __METHOD__ );
287 $ok = $dbw->delete( 'site_identifiers', '*', __METHOD__ ) && $ok;
288 $dbw->endAtomic( __METHOD__ );
289
290 $this->dbLoadBalancer->reuseConnection( $dbw );
291
292 $this->reset();
293
294 return $ok;
295 }
296
297 /**
298 * Provide an array that maps language codes
299 *
300 * @param string[] $newMapping
301 */
302 public function setLanguageCodeMapping( array $newMapping ) {
303 $this->languageCodeMapping = $newMapping;
304 }
305
306 }