Merge "Cleaned up DatabaseBase constructor to use an array"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 7 Nov 2013 19:36:22 +0000 (19:36 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 7 Nov 2013 19:36:22 +0000 (19:36 +0000)
1  2 
includes/db/Database.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php

diff --combined includes/db/Database.php
@@@ -301,12 -301,6 +301,12 @@@ abstract class DatabaseBase implements 
         */
        protected $fileHandle = null;
  
 +      /**
 +       * @since 1.22
 +       * @var Process cache of VIEWs names in the database
 +       */
 +      protected $allViews = null;
 +
  # ------------------------------------------------------------------------------
  # Accessors
  # ------------------------------------------------------------------------------
         * connection object, by specifying no parameters to __construct(). This
         * feature is deprecated and should be removed.
         *
-        * FIXME: The long list of formal parameters here is not really appropriate
-        * for MySQL, and not at all appropriate for any other DBMS. It should be
-        * replaced by named parameters as in DatabaseBase::factory().
-        *
         * DatabaseBase subclasses should not be constructed directly in external
         * code. DatabaseBase::factory() should be used instead.
         *
-        * @param string $server database server host
-        * @param string $user database user name
-        * @param string $password database user password
-        * @param string $dbName database name
-        * @param $flags
-        * @param string $tablePrefix database table prefixes. By default use the prefix gave in LocalSettings.php
-        * @param bool $foreign disable some operations specific to local databases
+        * @param array Parameters passed from DatabaseBase::factory()
         */
-       function __construct( $server = false, $user = false, $password = false, $dbName = false,
-               $flags = 0, $tablePrefix = 'get from global', $foreign = false
-       ) {
+       function __construct( $params = null ) {
                global $wgDBprefix, $wgCommandLineMode, $wgDebugDBTransactions;
  
                $this->mTrxAtomicLevels = new SplStack;
-               $this->mFlags = $flags;
  
+               if ( is_array( $params ) ) { // MW 1.22
+                       $server = $params['host'];
+                       $user = $params['user'];
+                       $password = $params['password'];
+                       $dbName = $params['dbname'];
+                       $flags = $params['flags'];
+                       $tablePrefix = $params['tablePrefix'];
+                       $foreign = $params['foreign'];
+               } else { // legacy calling pattern
+                       wfDeprecated( __METHOD__ . " method called without parameter array.", "1.22" );
+                       $args = func_get_args();
+                       $server = isset( $args[0] ) ? $args[0] : false;
+                       $user = isset( $args[1] ) ? $args[1] : false;
+                       $password = isset( $args[2] ) ? $args[2] : false;
+                       $dbName = isset( $args[3] ) ? $args[3] : false;
+                       $flags = isset( $args[4] ) ? $args[4] : 0;
+                       $tablePrefix = isset( $args[5] ) ? $args[5] : 'get from global';
+                       $foreign = isset( $args[6] ) ? $args[6] : false;
+               }
+               $this->mFlags = $flags;
                if ( $this->mFlags & DBO_DEFAULT ) {
                        if ( $wgCommandLineMode ) {
                                $this->mFlags &= ~DBO_TRX;
  
                $class = 'Database' . ucfirst( $driver );
                if ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) {
-                       return new $class(
-                               isset( $p['host'] ) ? $p['host'] : false,
-                               isset( $p['user'] ) ? $p['user'] : false,
-                               isset( $p['password'] ) ? $p['password'] : false,
-                               isset( $p['dbname'] ) ? $p['dbname'] : false,
-                               isset( $p['flags'] ) ? $p['flags'] : 0,
-                               isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
-                               isset( $p['foreign'] ) ? $p['foreign'] : false
+                       $params = array(
+                               'host' => isset( $p['host'] ) ? $p['host'] : false,
+                               'user' => isset( $p['user'] ) ? $p['user'] : false,
+                               'password' => isset( $p['password'] ) ? $p['password'] : false,
+                               'dbname' => isset( $p['dbname'] ) ? $p['dbname'] : false,
+                               'flags' => isset( $p['flags'] ) ? $p['flags'] : 0,
+                               'tablePrefix' => isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
+                               'foreign' => isset( $p['foreign'] ) ? $p['foreign'] : false
                        );
+                       return new $class( $params );
                } else {
                        return null;
                }
                throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' );
        }
  
 +      /**
 +       * Reset the views process cache set by listViews()
 +       * @since 1.22
 +       */
 +      final public function clearViewsCache() {
 +              $this->allViews = null;
 +      }
 +
 +      /**
 +       * Lists all the VIEWs in the database
 +       *
 +       * For caching purposes the list of all views should be stored in
 +       * $this->allViews. The process cache can be cleared with clearViewsCache()
 +       *
 +       * @param string $prefix   Only show VIEWs with this prefix, eg. unit_test_
 +       * @param string $fname    Name of calling function
 +       * @throws MWException
 +       * @since 1.22
 +       */
 +      public function listViews( $prefix = null, $fname = __METHOD__ ) {
 +              throw new MWException( 'DatabaseBase::listViews is not implemented in descendant class' );
 +      }
 +
 +      /**
 +       * Differentiates between a TABLE and a VIEW
 +       *
 +       * @param $name string: Name of the database-structure to test.
 +       * @throws MWException
 +       * @since 1.22
 +       */
 +      public function isView( $name ) {
 +              throw new MWException( 'DatabaseBase::isView is not implemented in descendant class' );
 +      }
 +
        /**
         * Convert a timestamp in one of the formats accepted by wfTimestamp()
         * to the format used for inserting into timestamp fields in this DBMS.
@@@ -31,6 -31,7 +31,7 @@@
   */
  class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
        // From DatabaseBase
+       function __construct() {}
        protected function closeConnection() {}
        protected function doQuery( $sql ) {}
  
@@@ -123,87 -124,4 +124,87 @@@ class DatabaseMysqlBaseTest extends Med
                return json_decode( '"' . $str . '"' );
        }
  
 +      function getMockForViews() {
 +              $db = $this->getMockBuilder( 'DatabaseMysql' )
 +                      ->disableOriginalConstructor()
 +                      ->setMethods( array( 'fetchRow', 'query' ) )
 +                      ->getMock();
 +
 +              $db->expects( $this->any() )
 +                      ->method( 'query' )
 +                      ->with( $this->anything() )
 +                      ->will(
 +                              $this->returnValue( null )
 +                      );
 +
 +              $db->expects( $this->any() )
 +                      ->method( 'fetchRow' )
 +                      ->with( $this->anything() )
 +                      ->will( $this->onConsecutiveCalls(
 +                              array( 'Tables_in_' => 'view1' ),
 +                              array( 'Tables_in_' => 'view2' ),
 +                              array( 'Tables_in_' => 'myview' ),
 +                              false  # no more rows
 +                      ));
 +              return $db;
 +      }
 +      /**
 +       * @covers DatabaseMysqlBase::listViews
 +       */
 +      function testListviews() {
 +              $db = $this->getMockForViews();
 +
 +              // The first call populate an internal cache of views
 +              $this->assertEquals( array( 'view1', 'view2', 'myview'),
 +                      $db->listViews() );
 +              $this->assertEquals( array( 'view1', 'view2', 'myview'),
 +                      $db->listViews() );
 +
 +              // Prefix filtering
 +              $this->assertEquals( array( 'view1', 'view2' ),
 +                      $db->listViews( 'view' ) );
 +              $this->assertEquals( array( 'myview' ),
 +                      $db->listViews( 'my' ) );
 +              $this->assertEquals( array(),
 +                      $db->listViews( 'UNUSED_PREFIX' ) );
 +              $this->assertEquals( array( 'view1', 'view2', 'myview'),
 +                      $db->listViews( '' ) );
 +      }
 +
 +      /**
 +       * @covers DatabaseMysqlBase::isView
 +       * @dataProvider provideViewExistanceChecks
 +       */
 +      function testIsView( $isView, $viewName ) {
 +              $db = $this->getMockForViews();
 +
 +              switch( $isView ) {
 +                      case true:
 +                              $this->assertTrue( $db->isView( $viewName ),
 +                                      "$viewName should be considered a view" );
 +                      break;
 +
 +                      case false:
 +                              $this->assertFalse( $db->isView( $viewName ),
 +                                      "$viewName has not been defined as a view" );
 +                      break;
 +              }
 +
 +      }
 +
 +      function provideViewExistanceChecks() {
 +              return array(
 +                      // format: whether it is a view, view name
 +                      array( true, 'view1' ),
 +                      array( true, 'view2' ),
 +                      array( true, 'myview' ),
 +
 +                      array( false, 'user' ),
 +
 +                      array( false, 'view10' ),
 +                      array( false, 'my' ),
 +                      array( false, 'OH_MY_GOD' ),  # they killed kenny!
 +              );
 +      }
 +
  }