rdbms: Simplify Database::factory()
authorTimo Tijhof <krinklemail@gmail.com>
Wed, 24 Jan 2018 19:33:37 +0000 (11:33 -0800)
committerKrinkle <krinklemail@gmail.com>
Thu, 25 Jan 2018 17:35:55 +0000 (17:35 +0000)
Follows-up 0ff2b7a776 (T120333) which removed support for the
deprecated php 'mysql' extension.

It surprised me that the 'DatabaseMysql' entry could safely be removed
from $classAliases. This was because the key is not direct input,
but based on $canonicalDBTypes, which maps mysql to mysqli.

Take this further by removing the indirection between type, driver
and class name.

* Map built-in db types directly to their class and driver.
* Change fallback to assign $class directly from $dbType, without
  indirection of a $driver variable.
* Remove unused $classAliases.

Change-Id: I1200b07f66f23624410d848b6f382cb2dafa5c59

includes/libs/rdbms/database/Database.php

index 323c147..1efa9a1 100644 (file)
@@ -336,53 +336,51 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @since 1.18
         */
        final public static function factory( $dbType, $p = [] ) {
-               static $canonicalDBTypes = [
-                       'mysql' => [ 'mysqli' ],
-                       'postgres' => [],
-                       'sqlite' => [],
-                       'oracle' => [],
-                       'mssql' => [],
-               ];
-               static $classAliases = [
-                       'DatabaseMssql' => DatabaseMssql::class,
-                       'DatabaseMysqli' => DatabaseMysqli::class,
-                       'DatabaseSqlite' => DatabaseSqlite::class,
-                       'DatabasePostgres' => DatabasePostgres::class
+               // For database types with built-in support, the below maps type to IDatabase
+               // implementations. For types with multipe driver implementations (PHP extensions),
+               // an array can be used, keyed by extension name. In case of an array, the
+               // optional 'driver' parameter can be used to force a specific driver. Otherwise,
+               // we auto-detect the first available driver. For types without built-in support,
+               // an class named "Database<Type>" us used, eg. DatabaseFoo for type 'foo'.
+               static $builtinTypes = [
+                       'mssql' => DatabaseMssql::class,
+                       'mysql' => [ 'mysqli' => DatabaseMysqli::class ],
+                       'sqlite' => DatabaseSqlite::class,
+                       'postgres' => DatabasePostgres::class,
                ];
 
-               $driver = false;
                $dbType = strtolower( $dbType );
-               if ( isset( $canonicalDBTypes[$dbType] ) && $canonicalDBTypes[$dbType] ) {
-                       $possibleDrivers = $canonicalDBTypes[$dbType];
-                       if ( !empty( $p['driver'] ) ) {
-                               if ( in_array( $p['driver'], $possibleDrivers ) ) {
-                                       $driver = $p['driver'];
-                               } else {
-                                       throw new InvalidArgumentException( __METHOD__ .
-                                               " type '$dbType' does not support driver '{$p['driver']}'" );
-                               }
+               $class = false;
+               if ( isset( $builtinTypes[$dbType] ) ) {
+                       $possibleDrivers = $builtinTypes[$dbType];
+                       if ( is_string( $possibleDrivers ) ) {
+                               $class = $possibleDrivers;
                        } else {
-                               foreach ( $possibleDrivers as $posDriver ) {
-                                       if ( extension_loaded( $posDriver ) ) {
-                                               $driver = $posDriver;
-                                               break;
+                               if ( !empty( $p['driver'] ) ) {
+                                       if ( !isset( $possibleDrivers[$p['driver']] ) ) {
+                                               throw new InvalidArgumentException( __METHOD__ .
+                                                       " type '$dbType' does not support driver '{$p['driver']}'" );
+                                       } else {
+                                               $class = $possibleDrivers[$p['driver']];
+                                       }
+                               } else {
+                                       foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
+                                               if ( extension_loaded( $posDriver ) ) {
+                                                       $class = $possibleClass;
+                                                       break;
+                                               }
                                        }
                                }
                        }
                } else {
-                       $driver = $dbType;
+                       $class = 'Database' . ucfirst( $dbType );
                }
 
-               if ( $driver === false || $driver === '' ) {
+               if ( $class === false ) {
                        throw new InvalidArgumentException( __METHOD__ .
                                " no viable database extension found for type '$dbType'" );
                }
 
-               $class = 'Database' . ucfirst( $driver );
-               if ( isset( $classAliases[$class] ) ) {
-                       $class = $classAliases[$class];
-               }
-
                if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) {
                        // Resolve some defaults for b/c
                        $p['host'] = isset( $p['host'] ) ? $p['host'] : false;