X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/site/DBSiteStore.php diff --git a/includes/site/DBSiteStore.php b/includes/site/DBSiteStore.php new file mode 100644 index 00000000..7fcfbe59 --- /dev/null +++ b/includes/site/DBSiteStore.php @@ -0,0 +1,284 @@ + + * @author Daniel Kinzler + */ +class DBSiteStore implements SiteStore { + + /** + * @var SiteList|null + */ + protected $sites = null; + + /** + * @var LoadBalancer + */ + private $dbLoadBalancer; + + /** + * @since 1.27 + * + * @todo: inject some kind of connection manager that is aware of the target wiki, + * instead of injecting a LoadBalancer. + * + * @param LoadBalancer $dbLoadBalancer + */ + public function __construct( LoadBalancer $dbLoadBalancer ) { + $this->dbLoadBalancer = $dbLoadBalancer; + } + + /** + * @see SiteStore::getSites + * + * @since 1.25 + * + * @return SiteList + */ + public function getSites() { + $this->loadSites(); + + return $this->sites; + } + + /** + * Fetches the site from the database and loads them into the sites field. + * + * @since 1.25 + */ + protected function loadSites() { + $this->sites = new SiteList(); + + $dbr = $this->dbLoadBalancer->getConnection( DB_REPLICA ); + + $res = $dbr->select( + 'sites', + [ + 'site_id', + 'site_global_key', + 'site_type', + 'site_group', + 'site_source', + 'site_language', + 'site_protocol', + 'site_domain', + 'site_data', + 'site_forward', + 'site_config', + ], + '', + __METHOD__, + [ 'ORDER BY' => 'site_global_key' ] + ); + + foreach ( $res as $row ) { + $site = Site::newForType( $row->site_type ); + $site->setGlobalId( $row->site_global_key ); + $site->setInternalId( (int)$row->site_id ); + $site->setForward( (bool)$row->site_forward ); + $site->setGroup( $row->site_group ); + $site->setLanguageCode( $row->site_language === '' + ? null + : $row->site_language + ); + $site->setSource( $row->site_source ); + $site->setExtraData( unserialize( $row->site_data ) ); + $site->setExtraConfig( unserialize( $row->site_config ) ); + $this->sites[] = $site; + } + + // Batch load the local site identifiers. + $ids = $dbr->select( + 'site_identifiers', + [ + 'si_site', + 'si_type', + 'si_key', + ], + [], + __METHOD__ + ); + + foreach ( $ids as $id ) { + if ( $this->sites->hasInternalId( $id->si_site ) ) { + $site = $this->sites->getSiteByInternalId( $id->si_site ); + $site->addLocalId( $id->si_type, $id->si_key ); + $this->sites->setSite( $site ); + } + } + } + + /** + * @see SiteStore::getSite + * + * @since 1.25 + * + * @param string $globalId + * + * @return Site|null + */ + public function getSite( $globalId ) { + if ( $this->sites === null ) { + $this->sites = $this->getSites(); + } + + return $this->sites->hasSite( $globalId ) ? $this->sites->getSite( $globalId ) : null; + } + + /** + * @see SiteStore::saveSite + * + * @since 1.25 + * + * @param Site $site + * + * @return bool Success indicator + */ + public function saveSite( Site $site ) { + return $this->saveSites( [ $site ] ); + } + + /** + * @see SiteStore::saveSites + * + * @since 1.25 + * + * @param Site[] $sites + * + * @return bool Success indicator + */ + public function saveSites( array $sites ) { + if ( empty( $sites ) ) { + return true; + } + + $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER ); + + $dbw->startAtomic( __METHOD__ ); + + $success = true; + + $internalIds = []; + $localIds = []; + + foreach ( $sites as $site ) { + if ( $site->getInternalId() !== null ) { + $internalIds[] = $site->getInternalId(); + } + + $fields = [ + // Site data + 'site_global_key' => $site->getGlobalId(), // TODO: check not null + 'site_type' => $site->getType(), + 'site_group' => $site->getGroup(), + 'site_source' => $site->getSource(), + 'site_language' => $site->getLanguageCode() === null ? '' : $site->getLanguageCode(), + 'site_protocol' => $site->getProtocol(), + 'site_domain' => strrev( $site->getDomain() ) . '.', + 'site_data' => serialize( $site->getExtraData() ), + + // Site config + 'site_forward' => $site->shouldForward() ? 1 : 0, + 'site_config' => serialize( $site->getExtraConfig() ), + ]; + + $rowId = $site->getInternalId(); + if ( $rowId !== null ) { + $success = $dbw->update( + 'sites', $fields, [ 'site_id' => $rowId ], __METHOD__ + ) && $success; + } else { + $success = $dbw->insert( 'sites', $fields, __METHOD__ ) && $success; + $rowId = $dbw->insertId(); + } + + foreach ( $site->getLocalIds() as $idType => $ids ) { + foreach ( $ids as $id ) { + $localIds[] = [ $rowId, $idType, $id ]; + } + } + } + + if ( $internalIds !== [] ) { + $dbw->delete( + 'site_identifiers', + [ 'si_site' => $internalIds ], + __METHOD__ + ); + } + + foreach ( $localIds as $localId ) { + $dbw->insert( + 'site_identifiers', + [ + 'si_site' => $localId[0], + 'si_type' => $localId[1], + 'si_key' => $localId[2], + ], + __METHOD__ + ); + } + + $dbw->endAtomic( __METHOD__ ); + + $this->reset(); + + return $success; + } + + /** + * Resets the SiteList + * + * @since 1.25 + */ + public function reset() { + $this->sites = null; + } + + /** + * Clears the list of sites stored in the database. + * + * @see SiteStore::clear() + * + * @return bool Success + */ + public function clear() { + $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER ); + + $dbw->startAtomic( __METHOD__ ); + $ok = $dbw->delete( 'sites', '*', __METHOD__ ); + $ok = $dbw->delete( 'site_identifiers', '*', __METHOD__ ) && $ok; + $dbw->endAtomic( __METHOD__ ); + + $this->reset(); + + return $ok; + } + +}