r94005 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94004‎ | r94005 | r94006 >
Date:08:21, 6 August 2011
Author:catrope
Status:deferred
Tags:
Comment:
RL2: Add backend classes for the Gadgets extension rewrite
Modified paths:
  • /branches/RL2/extensions/Gadgets/Gadgets.php (modified) (history)
  • /branches/RL2/extensions/Gadgets/backend (added) (history)
  • /branches/RL2/extensions/Gadgets/backend/ForeignDBGadgetRepo.php (added) (history)
  • /branches/RL2/extensions/Gadgets/backend/Gadget.php (added) (history)
  • /branches/RL2/extensions/Gadgets/backend/GadgetRepo.php (added) (history)
  • /branches/RL2/extensions/Gadgets/backend/GadgetResourceLoaderModule.php (added) (history)
  • /branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php (added) (history)

Diff [purge]

Index: branches/RL2/extensions/Gadgets/Gadgets.php
@@ -29,6 +29,40 @@
3030 'descriptionmsg' => 'gadgets-desc',
3131 );
3232
 33+/*** Configuration ***/
 34+
 35+/**
 36+ * Add gadget repositories here.
 37+ *
 38+ * For foreign DB-based gadget repositories, use:
 39+ * // TODO: Document better by looking at WMF ForeignFileRepo config
 40+ * $wgGadgetRepositories[] = array(
 41+ * 'class' => 'ForeignDBGadgetRepo',
 42+ * 'source' => 'mediawikiwiki', // Name of the ResourceLoader source for the foreign wiki, see $wgResourceLoaderSources
 43+ * 'dbType' => 'mysql', // Database type of the foreign wiki's database
 44+ * 'dbServer' => 'db123', // Database host for the foreign wiki's master database
 45+ * 'dbUser' => 'username', // User name for the foreign wiki's database
 46+ * 'dbPassword' => 'password', // Password for the foreign wiki's database
 47+ * 'dbName' => 'mediawikiwiki', // Name of the foreign wiki's database
 48+ * // TODO: Make this the default?
 49+ * 'dbFlags' => ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT // Use this value unless you know what you're doing
 50+ * 'tablePrefix' => 'mw_', // Table prefix for the foreign wiki's database, or '' if no prefix
 51+ //* 'hasSharedCache' => true, // Whether the foreign wiki's cache is accessible through $wgMemc // TODO: needed?
 52+ * );
 53+ *
 54+ * For foreign API-based gadget repositories, use:
 55+ * $wgGadgetRepositories[] = array(
 56+ * 'class' => 'ForeignAPIGadgetRepo',
 57+ * // TODO
 58+ * );
 59+ */
 60+$wgGadgetRepositories = array(
 61+ array(
 62+ // Default local gadget repository. Doesn't need any parameters
 63+ 'class' => 'LocalGadgetRepo',
 64+ )
 65+);
 66+
3367 define( 'NS_GADGET', 2300 );
3468 define( 'NS_GADGET_TALK', 2301 );
3569
@@ -56,7 +90,12 @@
5791
5892 $wgAutoloadClasses['ApiQueryGadgetCategories'] = $dir . 'api/ApiQueryGadgetCategories.php';
5993 $wgAutoloadClasses['ApiQueryGadgets'] = $dir . 'api/ApiQueryGadgets.php';
 94+$wgAutoloadClasses['ForeignDBGadgetRepo'] = $dir . 'backend/ForeignDBGadgetRepo.php';
 95+$wgAutoloadClasses['Gadget'] = $dir . 'backend/Gadget.php';
6096 $wgAutoloadClasses['GadgetHooks'] = $dir . 'GadgetHooks.php';
 97+$wgAutoloadClasses['GadgetRepo'] = $dir . 'backend/GadgetRepo.php';
 98+$wgAutoloadClasses['GadgetResourceLoaderModule'] = $dir . 'backend/GadgetResourceLoaderModule.php';
 99+$wgAutoloadClasses['LocalGadgetRepo'] = $dir . 'backend/LocalGadgetRepo.php';
61100 $wgAutoloadClasses['SpecialGadgets'] = $dir . 'SpecialGadgets.php';
62101
63102 $wgSpecialPages['Gadgets'] = 'SpecialGadgets';
Index: branches/RL2/extensions/Gadgets/backend/Gadget.php
@@ -0,0 +1,238 @@
 2+<?php
 3+/**
 4+ * Class for gadgets based on properties obtained from a JSON blob.
 5+ *
 6+ * The format of the JSON blob is as follows:
 7+ * {
 8+ * "settings": {
 9+ * // The rights required to be able to enable this gadget
 10+ * "rights": ["delete", "block"],
 11+ * // Whether this gadget is enabled by default
 12+ * "default": true
 13+ * // Whether this gadget is hidden
 14+ * "hidden": false,
 15+ * // Whether this gadget is shared
 16+ * "shared": true,
 17+ * // The key of the section this gadget belongs to. The section title message key is gadgetsection-$section-title
 18+ * "section": "key of gadget section",
 19+ * },
 20+ * "module": {
 21+ * // scripts and styles are pages in the Gadget: namespace
 22+ * "scripts": ["foobar.js"],
 23+ * "styles": ["foobar.css"],
 24+ * "messages": ["foobar-welcome", "recentchanges", "namespaces"],
 25+ * "dependencies": ["jquery.ui.tabs", "gadget.awesome"]
 26+ * }
 27+ * }
 28+ */
 29+class Gadget {
 30+ /** Gadget name (string) */
 31+ protected $name;
 32+
 33+ /** Gadget repository this gadget came from (GadgetRepo object) */
 34+ protected $repo;
 35+
 36+ /** Last modification timestamp of the gadget metadata (TS_MW timestamp) **/
 37+ protected $timestamp;
 38+
 39+ /** array of gadget settings, see "settings" key in the JSON blob */
 40+ protected $settings;
 41+
 42+ /** array of module settings, see "module" key in the JSON blob */
 43+ protected $moduleData;
 44+
 45+ /*** Public static methods ***/
 46+
 47+ public static function isValidPropertiesArray( $properties ) {
 48+ // TODO: Also validate existence of individual properties
 49+ return is_array( $properties ) && isset( $properties['settings'] ) && isset( $properties['module'] );
 50+ }
 51+
 52+ /*** Public methods ***/
 53+
 54+ /**
 55+ * Constructor
 56+ * @param $name string Name
 57+ * @param $repo GadgetRepo that this gadget came from
 58+ * @param $properties mixed Array or JSON blob (string) with settings and module info
 59+ * @param $timestamp string Timestamp (TS_MW) this gadget's metadata was last touched
 60+ * @throws MWException if $properties is invalid
 61+ */
 62+ public function __construct( $name, $repo, $properties, $timestamp ) {
 63+ if ( is_string( $properties ) ) {
 64+ $properties = FormatJson::decode( $properties, true );
 65+ }
 66+
 67+
 68+ if ( !self::isValidPropertiesArray( $properties ) ) {
 69+ throw new MWException( 'Invalid property array passed to ' . __METHOD__ );
 70+ }
 71+
 72+ $this->name = $name;
 73+ $this->repo = $repo;
 74+ $this->timestamp = $timestamp;
 75+ $this->settings = $properties['settings'];
 76+ $this->moduleData = $properties['module'];
 77+ }
 78+
 79+ /**
 80+ * Retrieve the JSON representation of this gadget, in the same format as $properties in __construct().
 81+ * @return string JSON
 82+ */
 83+ public function getJSON() {
 84+ return FormatJson::encode( array( 'settings' => $this->settings, 'module' => $this->moduleData ) );
 85+ }
 86+
 87+ /**
 88+ * Get the name of the gadget. This name must be unique within its repository and must never change.
 89+ * It is only used internally; the name displayed to the user is controlled by getNameMsg().
 90+ * @return string
 91+ */
 92+ public function getName() {
 93+ return $this->name;
 94+ }
 95+
 96+ /**
 97+ * Get the name of the ResourceLoader source for this gadget's module
 98+ * @return string
 99+ */
 100+ public function getRepo() {
 101+ return $this->repo;
 102+ }
 103+
 104+ /**
 105+ * Get the last modification timestamp of the gadget metadata
 106+ * @return string TS_MW timestamp
 107+ */
 108+ public function getTimestamp() {
 109+ return $this->timestamp;
 110+ }
 111+
 112+ /**
 113+ * Get the title message for this gadget. This is the interface message that controls the name of the
 114+ * gadget as shown to the user.
 115+ * @return string Message key
 116+ */
 117+ public function getTitleMsg() {
 118+ return "gadget-{$this->name}-title";
 119+ }
 120+
 121+ /**
 122+ * Get the description message for this gadget.
 123+ * @return string Message key
 124+ */
 125+ public function getDescriptionMsg() {
 126+ return "gadget-{$this->name}-desc";
 127+ }
 128+
 129+ /**
 130+ * Get the section (also called category) this gadget is in.
 131+ * @return string Section key or empty string if not in any section
 132+ */
 133+ public function getSection() {
 134+ return $this->settings['section'];
 135+ }
 136+
 137+ /**
 138+ * Check whether this gadget is enabled by default. Even these gadgets can be disabled in the user's
 139+ * preferences, the preference just defaults to being on.
 140+ * @return bool
 141+ */
 142+ public function isEnabledByDefault() {
 143+ return (bool)$this->settings['default'];
 144+ }
 145+
 146+ /**
 147+ * Get the rights a user needs to be allowed to enable this gadget.
 148+ * @return array of rights (strings), empty if no restrictions
 149+ */
 150+ public function getRequiredRights() {
 151+ return (array)$this->settings['rights'];
 152+ }
 153+
 154+ /**
 155+ * Check whether this module is public. Modules that are not public cannot be enabled by users in
 156+ * their preferences and are only visible in the gadget manager.
 157+ * @return bool
 158+ */
 159+ public function isHidden() {
 160+ return (bool)$this->settings['hidden'];
 161+ }
 162+
 163+ /**
 164+ * Check whether this module is shared. Modules that are not shared cannot be loaded through
 165+ * a foreign repository.
 166+ * @return bool
 167+ */
 168+ public function isShared() {
 169+ return (bool)$this->settings['shared'];
 170+ }
 171+
 172+ /**
 173+ * Get the ResourceLoader module for this gadget, if available.
 174+ * @return ResourceLoaderModule object
 175+ */
 176+ public function getModule() {
 177+ // Build $pages
 178+ $pages = array();
 179+ foreach ( $this->moduleData['scripts'] as $script ) {
 180+ $pages["Gadget:$script"] = array( 'type' => 'script' );
 181+ }
 182+ foreach ( $this->moduleData['styles'] as $style ) {
 183+ $pages["Gadget:$style"] = array( 'type' => 'style' );
 184+ }
 185+
 186+ return new GadgetResourceLoaderModule(
 187+ $pages,
 188+ (array)$this->moduleData['dependencies'],
 189+ (array)$this->moduleData['messages'],
 190+ $this->repo->getSource(),
 191+ $this->timestamp,
 192+ $this->repo->getDB()
 193+ );
 194+ }
 195+
 196+ /**
 197+ * Get the name of the ResourceLoader module for this gadget.
 198+ * @return string Module name
 199+ */
 200+ public function getModuleName() {
 201+ return "gadget.{$this->name}";
 202+ }
 203+
 204+ public function getScripts() {
 205+ return $this->moduleData['scripts'];
 206+ }
 207+
 208+ public function getStyles() {
 209+ return $this->moduleData['styles'];
 210+ }
 211+
 212+ /*** Public methods ***/
 213+
 214+ /**
 215+ * Check whether this gadget is enabled for a given user.
 216+ * @param $user User object
 217+ * @return bool
 218+ */
 219+ public function isEnabledForUser( $user ) {
 220+ $name = $this->getName();
 221+ return (bool)$user->getOption( "gadget-$name", $this->isEnabledByDefault() );
 222+ }
 223+
 224+ /**
 225+ * Checks whether a given user has the required rights to use this gadget
 226+ *
 227+ * @param $user User: user to check against
 228+ * @return Boolean
 229+ */
 230+ public function isAllowed( $user ) {
 231+ $required = $this->getRequiredRights();
 232+ $numRequired = count( $required );
 233+ if ( $numRequired === 0 ) {
 234+ // Short circuit to prevent calling $user->getRights()
 235+ return true;
 236+ }
 237+ return count( array_intersect( $required, $user->getRights() ) ) == $numRequired;
 238+ }
 239+}
Property changes on: branches/RL2/extensions/Gadgets/backend/Gadget.php
___________________________________________________________________
Added: svn:eol-style
1240 + native
Index: branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php
@@ -0,0 +1,200 @@
 2+<?php
 3+/**
 4+ * Gadget repository that gets its gadgets from the local database.
 5+ */
 6+class LocalGadgetRepo extends GadgetRepo {
 7+ protected $data = null;
 8+
 9+ /*** Public methods inherited from GadgetRepo ***/
 10+
 11+ /**
 12+ * Constructor.
 13+ * @param info array of options
 14+ */
 15+ public function __construct( array $options ) {
 16+ parent::__construct( $options );
 17+
 18+ // TODO: define options
 19+ }
 20+
 21+ public function getGadgetNames() {
 22+ $this->loadData();
 23+ return array_keys( $this->data );
 24+ }
 25+
 26+ public function getGadget( $name ) {
 27+ $this->loadData();
 28+ if ( !isset( $this->data[$name] ) ) {
 29+ return null;
 30+ }
 31+ return new Gadget( $name, $this, $this->data[$name]['json'], $this->data[$name]['timestamp'] );
 32+ }
 33+
 34+ public function getSource() {
 35+ return 'local';
 36+ }
 37+
 38+ public function clearInObjectCache() {
 39+ $this->data = null;
 40+ }
 41+
 42+ public function isWriteable() {
 43+ return true;
 44+ }
 45+
 46+ public function addGadget( Gadget $gadget ) {
 47+ if ( !$this->isWriteable() ) {
 48+ return Status::newFatal( 'gadget-manager-readonly-repository' );
 49+ }
 50+
 51+ // Try to detect a naming conflict beforehand
 52+ $this->loadData();
 53+ $name = $gadget->getName();
 54+ if ( isset( $this->data[$name] ) ) {
 55+ return Status::newFatal( 'gadget-manager-create-exists', $name );
 56+ }
 57+
 58+ $json = $gadget->getJSON();
 59+ $dbw = $this->getMasterDB();
 60+ $ts = $dbw->timestamp();
 61+ // Use INSERT IGNORE so we don't die when there's a race condition causing a naming conflict
 62+ $dbw->insert( 'gadgets', array( array(
 63+ 'gd_name' => $name,
 64+ 'gd_blob' => $json,
 65+ 'gd_shared' => $gadget->isShared(),
 66+ 'gd_timestamp' => $ts
 67+ ) ), __METHOD__, array( 'IGNORE' )
 68+ );
 69+
 70+ // Detect naming conflict after the fact
 71+ if ( $dbw->affectedRows() === 0 ) {
 72+ return Status::newFatal( 'gadget-manager-create-exists', $name );
 73+ }
 74+
 75+ // Update our in-object cache
 76+ // This looks stupid: we have an object that we could be caching. But I prefer
 77+ // to keep $this->data in a consistent format and have getGadget() always return
 78+ // a clone. If it returned a reference to a cached object, the caller could change
 79+ // that object and cause weird things to happen.
 80+ $this->data[$name] = array( 'json' => $json, 'timestamp' => $ts );
 81+
 82+ return Status::newGood();
 83+ }
 84+
 85+ public function modifyGadget( Gadget $gadget ) {
 86+ if ( !$this->isWriteable() ) {
 87+ return Status::newFatal( 'gadget-manager-readonly-repository' );
 88+ }
 89+
 90+ $this->loadData();
 91+ $name = $gadget->getName();
 92+ if ( !isset( $this->data[$name] ) ) {
 93+ return Status::newFatal( 'gadget-manager-nosuchgadget', $name );
 94+ }
 95+
 96+ $json = $gadget->getJSON();
 97+ $ts = $gadget->getTimestamp();
 98+ $dbw = $this->getMasterDB();
 99+ $newTs = $dbw->timestamp();
 100+ $dbw->update( 'gadgets', array(
 101+ 'gd_blob' => $json,
 102+ 'gd_shared' => $gadget->isShared(),
 103+ 'gd_timestamp' => $dbw->timestamp()
 104+ ), array(
 105+ 'gd_name' => $name,
 106+ 'gd_timestamp' => $ts // for conflict detection
 107+ ), __METHOD__, array( 'IGNORE' )
 108+ );
 109+
 110+ // Detect conflicts
 111+ if ( $dbw->affectedRows() === 0 ) {
 112+ // Some conflict occurred. Either the UPDATE failed because the
 113+ // timestamp condition didn't match, in which case someone else
 114+ // modified the gadget concurrently, or it failed to find a row
 115+ // for this gadget name at all, in which case someone else deleted
 116+ // the gadget entirely. We don't really care what happened, we'll
 117+ // just return an error and let the caller figure it out.
 118+ return Status::newFatal( 'gadgets-manager-modify-conflict', $name, $ts );
 119+ }
 120+
 121+ // Update our in-object cache
 122+ // See comment in addGadget() for an explanation of why it's done this way
 123+ $this->data[$name] = array( 'json' => $json, 'timestamp' => $newTs );
 124+
 125+ return Status::newGood();
 126+ }
 127+
 128+ public function deleteGadget( $name ) {
 129+ if ( !$this->isWriteable() ) {
 130+ return Status::newFatal( 'gadget-manager-readonly-repository' );
 131+ }
 132+
 133+ $this->loadData();
 134+ if ( !isset( $this->data[$name] ) ) {
 135+ return Status::newFatal( 'gadgets-manager-nosuchgadget', $name );
 136+ }
 137+
 138+ unset( $this->data[$name] );
 139+ $dbw = $this->getMasterDB();
 140+ $dbw->delete( 'gadgets', array( 'gd_name' => $name ), __METHOD__ );
 141+ if ( $dbw->affectedRows() === 0 ) {
 142+ return Status::newFatal( 'gadgets-manager-nosuchgadget', $name );
 143+ }
 144+ return Status::newGood();
 145+ }
 146+
 147+ /*** Protected methods ***/
 148+
 149+ /**
 150+ * Get the master DB connection. Subclasses can override this to use a different DB
 151+ * @return Database
 152+ */
 153+ protected function getMasterDB() {
 154+ return wfGetDB( DB_MASTER );
 155+ }
 156+
 157+ /**
 158+ * Get the slave DB connection. Subclasses can override this to use a different DB
 159+ * @return Database
 160+ */
 161+ public function getDB() {
 162+ return wfGetDB( DB_SLAVE );
 163+ }
 164+
 165+ /*** Protected methods ***/
 166+
 167+ /**
 168+ * Populate $this->data from the DB, if that hasn't happened yet. All methods using
 169+ * $this->data must call this before accessing $this->data .
 170+ */
 171+ protected function loadData() {
 172+ if ( is_array( $this->data ) ) {
 173+ // Already loaded
 174+ return;
 175+ }
 176+ $this->data = array();
 177+
 178+ $query = $this->getLoadDataQuery();
 179+ $dbr = $this->getDB();
 180+ $res = $dbr->select( $query['tables'], $query['fields'], $query['conds'], __METHOD__,
 181+ $query['options'], $query['join_conds'] );
 182+
 183+ foreach ( $res as $row ) {
 184+ $this->data[$row->gd_name] = array( 'json' => $row->gd_blob, 'timestamp' => $row->gd_timestamp );
 185+ }
 186+ }
 187+
 188+ /**
 189+ * Get the DB query to use in loadData(). Subclasses can override this to tweak the query.
 190+ * @return Array
 191+ */
 192+ protected function getLoadDataQuery() {
 193+ return array(
 194+ 'tables' => 'gadgets',
 195+ 'fields' => array( 'gd_name', 'gd_blob', 'gd_timestamp' ),
 196+ 'conds' => '', // no WHERE clause
 197+ 'options' => array(),
 198+ 'join_conds' => array(),
 199+ );
 200+ }
 201+}
Property changes on: branches/RL2/extensions/Gadgets/backend/LocalGadgetRepo.php
___________________________________________________________________
Added: svn:eol-style
1202 + native
Index: branches/RL2/extensions/Gadgets/backend/GadgetResourceLoaderModule.php
@@ -0,0 +1,77 @@
 2+<?php
 3+/**
 4+ * ResourceLoader module for a single gadget
 5+ */
 6+class GadgetResourceLoaderModule extends ResourceLoaderWikiModule {
 7+ protected $pages, $dependencies, $messages, $source, $timestamp;
 8+
 9+ /**
 10+ * Creates an instance of this class
 11+ * @param $pages Array: Associative array of pages in ResourceLoaderWikiModule-compatible
 12+ * format, for example:
 13+ * array(
 14+ * 'MediaWiki:Gadget-foo.js' => array( 'type' => 'script' ),
 15+ * 'MediaWiki:Gadget-foo.css' => array( 'type' => 'style' ),
 16+ * )
 17+ * @param $dependencies Array: Names of resources this module depends on
 18+ * @param $messages Array: Keys of the i18n messages that this module needs
 19+ * @param $source String: Name of the source of this module, as defined in ResourceLoader
 20+ * @param $timestamp String: Last modification timestamp of the gadget metadata
 21+ * @param $db Database: Remote database object // TODO: How will this work for ForeignAPIGadgetRepo?
 22+ */
 23+ public function __construct( $pages, $dependencies, $messages, $source, $timestamp, $db ) {
 24+ $this->pages = $pages;
 25+ $this->dependencies = $dependencies;
 26+ $this->messages = $messages;
 27+ $this->source = $source;
 28+ $this->timestamp = $timestamp;
 29+ $this->db = $db;
 30+ }
 31+
 32+ protected function getDB() {
 33+ return $this->db;
 34+ }
 35+
 36+ /**
 37+ * Overrides the abstract function from ResourceLoaderWikiModule class
 38+ * @return Array: $pages passed to __construct()
 39+ */
 40+ protected function getPages( ResourceLoaderContext $context ) {
 41+ return $this->pages;
 42+ }
 43+
 44+ /**
 45+ * Overrides ResourceLoaderModule::getDependencies()
 46+ * @return Array: Names of resources this module depends on
 47+ */
 48+ public function getDependencies() {
 49+ return $this->dependencies;
 50+ }
 51+
 52+ /**
 53+ * Overrides ResourceLoaderModule::getMessages()
 54+ * @return Array: Keys of messages this module needs
 55+ */
 56+ public function getMessages() {
 57+ return $this->messages;
 58+ }
 59+
 60+ /**
 61+ * Overrides ResourceLoaderModule::getSource()
 62+ * @return String: Name of the source of this module as defined in ResourceLoader
 63+ */
 64+ public function getSource() {
 65+ return $this->source;
 66+ }
 67+
 68+ /**
 69+ * Overrides ResourceLoaderWikiModule::getModifiedTime() to take $timestamp
 70+ * into account.
 71+ * @param $context ResourceLoaderContext object
 72+ * @return int UNIX timestamp
 73+ */
 74+ public function getModifiedTime( ResourceLoaderContext $context ) {
 75+ $retval = parent::getModifiedTime( $context );
 76+ return max( $retval, wfTimestamp( TS_UNIX, $this->timestamp ) );
 77+ }
 78+}
Property changes on: branches/RL2/extensions/Gadgets/backend/GadgetResourceLoaderModule.php
___________________________________________________________________
Added: svn:eol-style
179 + native
Index: branches/RL2/extensions/Gadgets/backend/ForeignDBGadgetRepo.php
@@ -0,0 +1,69 @@
 2+<?php
 3+/**
 4+ * Gadget repository that gets its gadgets from a foreign database.
 5+ *
 6+ * Options (all of these are MANDATORY):
 7+ * 'source': Name of the source these gadgets are loaded from, as defined in ResourceLoader
 8+ * 'dbType': Database type, see DatabaseBase::factory()
 9+ * 'dbServer': Database host
 10+ * 'dbUser': Database user name
 11+ * 'dbPassword': Database password
 12+ * 'dbName': Database name
 13+ * 'dbFlags': Bitmap of the DBO_* flags. Recommended value is ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT
 14+ * 'tablePrefix': Table prefix
 15+ //* 'hasSharedCache': Whether the foreign wiki's cache is accessible through $wgMemc // TODO: needed?
 16+ */
 17+class ForeignDBGadgetRepo extends LocalGadgetRepo {
 18+ protected $db = null;
 19+
 20+ protected $source, $dbServer, $dbUser, $dbPassword, $dbName, $dbFlags, $tablePrefix/*, $hasSharedCache*/;
 21+
 22+ /**
 23+ * Constructor.
 24+ * @param $options array See class documentation comment for option details
 25+ */
 26+ public function __construct( array $options ) {
 27+ parent::__construct( $options );
 28+
 29+ $optionKeys = array( 'source', 'dbType', 'dbServer', 'dbUser', 'dbPassword', 'dbName',
 30+ 'dbFlags', 'tablePrefix'/*, 'hasSharedCache'*/ );
 31+ foreach ( $optionKeys as $optionKey ) {
 32+ $this->{$optionKey} = $options[$optionKey];
 33+ }
 34+ }
 35+
 36+ public function isWriteable() {
 37+ return false;
 38+ }
 39+
 40+ public function getSource() {
 41+ return $this->source;
 42+ }
 43+
 44+ public function getDB() {
 45+ return $this->getMasterDB();
 46+ }
 47+
 48+ /*** Overridden protected functions from LocalGadgetRepo ***/
 49+ protected function getMasterDB() {
 50+ if ( $this->db === null ) {
 51+ $this->db = DatabaseBase::factory( $this->dbType,
 52+ array(
 53+ 'host' => $this->dbServer,
 54+ 'user' => $this->dbUser,
 55+ 'password' => $this->dbPassword,
 56+ 'dbname' => $this->dbName,
 57+ 'flags' => $this->dbFlags,
 58+ 'tablePrefix' => $this->tablePrefix
 59+ )
 60+ );
 61+ }
 62+ return $this->db;
 63+ }
 64+
 65+ protected function getLoadDataQuery() {
 66+ $query = parent::getLoadDataQuery();
 67+ $query['conds']['gd_shared'] = 1;
 68+ return $query;
 69+ }
 70+}
Property changes on: branches/RL2/extensions/Gadgets/backend/ForeignDBGadgetRepo.php
___________________________________________________________________
Added: svn:eol-style
171 + native
Index: branches/RL2/extensions/Gadgets/backend/GadgetRepo.php
@@ -0,0 +1,85 @@
 2+<?php
 3+// TODO: Fix comment lengths, inconsistent across this project
 4+/**
 5+ * Abstract base class for gadget repositories, can be local or remote
 6+ */
 7+abstract class GadgetRepo {
 8+ /**
 9+ * Constructor.
 10+ * @param $info array with configuration data, depends on repo type
 11+ */
 12+ public function __construct( array $info ) {
 13+ // TODO: Common config stuff for all repos?
 14+ }
 15+
 16+ /**
 17+ * Get the name of the ResourceLoader source of the modules
 18+ * returned by this repository.
 19+ * @return string Source name
 20+ */
 21+ abstract public function getSource();
 22+
 23+ /**
 24+ * Get the names of the gadgets provided by this repository
 25+ * @return array of names (strings)
 26+ */
 27+ abstract public function getGadgetNames();
 28+
 29+ /**
 30+ * Get a Gadget object for a given gadget name
 31+ * @param $name string Gadget name
 32+ * @return Gadget object or null if no such gadget
 33+ */
 34+ abstract public function getGadget( $name );
 35+
 36+ /**
 37+ * Clear any in-object caches this repository may have. In particular,
 38+ * the return values of getGadgetNames() and getGadget() may be cached.
 39+ * Callers may wish to clear this cache and reobtain a Gadget object
 40+ * when they get a conflict error.
 41+ */
 42+ abstract public function clearInObjectCache();
 43+
 44+ /**
 45+ * Check whether this repository allows write actions. If this method returns false,
 46+ * methods that modify the state of the repository or the gadgets in it (i.e. addGadget(),
 47+ * modifyGadget() and deleteGadget()) will always fail.
 48+ * @return bool
 49+ */
 50+ abstract public function isWriteable();
 51+
 52+ /**
 53+ * Get the Database object for the database this repository is based on, or null if this
 54+ * repository is not based on a database (but e.g. on a remote API)
 55+ * @return Database object (slave connection) or null
 56+ */
 57+ abstract public function getDB();
 58+
 59+ /**
 60+ * Add a new gadget to the repository. Will fail if there is already
 61+ * a gadget with the same name.
 62+ * @param $gadget Gadget object
 63+ * @return Status
 64+ */
 65+ abstract public function addGadget( Gadget $gadget );
 66+
 67+ /**
 68+ * Modify an existing gadget, replacing its metadata with the
 69+ * metadata in the provided Gadget object. The name is taken
 70+ * from the Gadget object as well. Will fail if there is no
 71+ * gadget by the same name.
 72+ * @param $gadget Gadget object
 73+ * @return Status
 74+ */
 75+ abstract public function modifyGadget( Gadget $gadget );
 76+
 77+ /**
 78+ * Irrevocably delete a gadget from the repository. Will fail
 79+ * if there is no gadget by the given name.
 80+ * @param $name string Name of the gadget to delete
 81+ * @return Status
 82+ */
 83+ abstract public function deleteGadget( $name );
 84+
 85+ // TODO: cache purging
 86+}
Property changes on: branches/RL2/extensions/Gadgets/backend/GadgetRepo.php
___________________________________________________________________
Added: svn:eol-style
187 + native

Status & tagging log