vendor/doctrine/dbal/src/DriverManager.php line 164

  1. <?php
  2. namespace Doctrine\DBAL;
  3. use Doctrine\Common\EventManager;
  4. use Doctrine\DBAL\Driver\IBMDB2;
  5. use Doctrine\DBAL\Driver\Mysqli;
  6. use Doctrine\DBAL\Driver\OCI8;
  7. use Doctrine\DBAL\Driver\PDO;
  8. use Doctrine\DBAL\Driver\PgSQL;
  9. use Doctrine\DBAL\Driver\SQLite3;
  10. use Doctrine\DBAL\Driver\SQLSrv;
  11. use Doctrine\DBAL\Exception\MalformedDsnException;
  12. use Doctrine\DBAL\Tools\DsnParser;
  13. use Doctrine\Deprecations\Deprecation;
  14. use SensitiveParameter;
  15. use function array_keys;
  16. use function array_merge;
  17. use function is_a;
  18. /**
  19.  * Factory for creating {@see Connection} instances.
  20.  *
  21.  * @psalm-type OverrideParams = array{
  22.  *     application_name?: string,
  23.  *     charset?: string,
  24.  *     dbname?: string,
  25.  *     default_dbname?: string,
  26.  *     driver?: key-of<self::DRIVER_MAP>,
  27.  *     driverClass?: class-string<Driver>,
  28.  *     driverOptions?: array<mixed>,
  29.  *     host?: string,
  30.  *     password?: string,
  31.  *     path?: string,
  32.  *     persistent?: bool,
  33.  *     platform?: Platforms\AbstractPlatform,
  34.  *     port?: int,
  35.  *     serverVersion?: string,
  36.  *     url?: string,
  37.  *     user?: string,
  38.  *     unix_socket?: string,
  39.  * }
  40.  * @psalm-type Params = array{
  41.  *     application_name?: string,
  42.  *     charset?: string,
  43.  *     dbname?: string,
  44.  *     defaultTableOptions?: array<string, mixed>,
  45.  *     default_dbname?: string,
  46.  *     driver?: key-of<self::DRIVER_MAP>,
  47.  *     driverClass?: class-string<Driver>,
  48.  *     driverOptions?: array<mixed>,
  49.  *     host?: string,
  50.  *     keepSlave?: bool,
  51.  *     keepReplica?: bool,
  52.  *     master?: OverrideParams,
  53.  *     memory?: bool,
  54.  *     password?: string,
  55.  *     path?: string,
  56.  *     persistent?: bool,
  57.  *     platform?: Platforms\AbstractPlatform,
  58.  *     port?: int,
  59.  *     primary?: OverrideParams,
  60.  *     replica?: array<OverrideParams>,
  61.  *     serverVersion?: string,
  62.  *     sharding?: array<string,mixed>,
  63.  *     slaves?: array<OverrideParams>,
  64.  *     url?: string,
  65.  *     user?: string,
  66.  *     wrapperClass?: class-string<Connection>,
  67.  *     unix_socket?: string,
  68.  * }
  69.  */
  70. final class DriverManager
  71. {
  72.     /**
  73.      * List of supported drivers and their mappings to the driver classes.
  74.      *
  75.      * To add your own driver use the 'driverClass' parameter to {@see DriverManager::getConnection()}.
  76.      */
  77.     private const DRIVER_MAP = [
  78.         'pdo_mysql'          => PDO\MySQL\Driver::class,
  79.         'pdo_sqlite'         => PDO\SQLite\Driver::class,
  80.         'pdo_pgsql'          => PDO\PgSQL\Driver::class,
  81.         'pdo_oci'            => PDO\OCI\Driver::class,
  82.         'oci8'               => OCI8\Driver::class,
  83.         'ibm_db2'            => IBMDB2\Driver::class,
  84.         'pdo_sqlsrv'         => PDO\SQLSrv\Driver::class,
  85.         'mysqli'             => Mysqli\Driver::class,
  86.         'pgsql'              => PgSQL\Driver::class,
  87.         'sqlsrv'             => SQLSrv\Driver::class,
  88.         'sqlite3'            => SQLite3\Driver::class,
  89.     ];
  90.     /**
  91.      * List of URL schemes from a database URL and their mappings to driver.
  92.      *
  93.      * @deprecated Use actual driver names instead.
  94.      *
  95.      * @var array<string, string>
  96.      * @psalm-var array<string, key-of<self::DRIVER_MAP>>
  97.      */
  98.     private static array $driverSchemeAliases = [
  99.         'db2'        => 'ibm_db2',
  100.         'mssql'      => 'pdo_sqlsrv',
  101.         'mysql'      => 'pdo_mysql',
  102.         'mysql2'     => 'pdo_mysql'// Amazon RDS, for some weird reason
  103.         'postgres'   => 'pdo_pgsql',
  104.         'postgresql' => 'pdo_pgsql',
  105.         'pgsql'      => 'pdo_pgsql',
  106.         'sqlite'     => 'pdo_sqlite',
  107.         'sqlite3'    => 'pdo_sqlite',
  108.     ];
  109.     /**
  110.      * Private constructor. This class cannot be instantiated.
  111.      *
  112.      * @codeCoverageIgnore
  113.      */
  114.     private function __construct()
  115.     {
  116.     }
  117.     /**
  118.      * Creates a connection object based on the specified parameters.
  119.      * This method returns a Doctrine\DBAL\Connection which wraps the underlying
  120.      * driver connection.
  121.      *
  122.      * $params must contain at least one of the following.
  123.      *
  124.      * Either 'driver' with one of the array keys of {@see DRIVER_MAP},
  125.      * OR 'driverClass' that contains the full class name (with namespace) of the
  126.      * driver class to instantiate.
  127.      *
  128.      * Other (optional) parameters:
  129.      *
  130.      * <b>user (string)</b>:
  131.      * The username to use when connecting.
  132.      *
  133.      * <b>password (string)</b>:
  134.      * The password to use when connecting.
  135.      *
  136.      * <b>driverOptions (array)</b>:
  137.      * Any additional driver-specific options for the driver. These are just passed
  138.      * through to the driver.
  139.      *
  140.      * <b>wrapperClass</b>:
  141.      * You may specify a custom wrapper class through the 'wrapperClass'
  142.      * parameter but this class MUST inherit from Doctrine\DBAL\Connection.
  143.      *
  144.      * <b>driverClass</b>:
  145.      * The driver class to use.
  146.      *
  147.      * @param Configuration|null $config       The configuration to use.
  148.      * @param EventManager|null  $eventManager The event manager to use.
  149.      * @psalm-param Params $params
  150.      *
  151.      * @psalm-return ($params is array{wrapperClass: class-string<T>} ? T : Connection)
  152.      *
  153.      * @throws Exception
  154.      *
  155.      * @template T of Connection
  156.      */
  157.     public static function getConnection(
  158.         #[SensitiveParameter]
  159.         array $params,
  160.         ?Configuration $config null,
  161.         ?EventManager $eventManager null
  162.     ): Connection {
  163.         // create default config and event manager, if not set
  164.         $config       ??= new Configuration();
  165.         $eventManager ??= new EventManager();
  166.         $params         self::parseDatabaseUrl($params);
  167.         // URL support for PrimaryReplicaConnection
  168.         if (isset($params['primary'])) {
  169.             $params['primary'] = self::parseDatabaseUrl($params['primary']);
  170.         }
  171.         if (isset($params['replica'])) {
  172.             foreach ($params['replica'] as $key => $replicaParams) {
  173.                 $params['replica'][$key] = self::parseDatabaseUrl($replicaParams);
  174.             }
  175.         }
  176.         $driver self::createDriver($params['driver'] ?? null$params['driverClass'] ?? null);
  177.         foreach ($config->getMiddlewares() as $middleware) {
  178.             $driver $middleware->wrap($driver);
  179.         }
  180.         $wrapperClass $params['wrapperClass'] ?? Connection::class;
  181.         if (! is_a($wrapperClassConnection::class, true)) {
  182.             throw Exception::invalidWrapperClass($wrapperClass);
  183.         }
  184.         return new $wrapperClass($params$driver$config$eventManager);
  185.     }
  186.     /**
  187.      * Returns the list of supported drivers.
  188.      *
  189.      * @return string[]
  190.      * @psalm-return list<key-of<self::DRIVER_MAP>>
  191.      */
  192.     public static function getAvailableDrivers(): array
  193.     {
  194.         return array_keys(self::DRIVER_MAP);
  195.     }
  196.     /**
  197.      * @throws Exception
  198.      *
  199.      * @psalm-assert key-of<self::DRIVER_MAP>|null $driver
  200.      * @psalm-assert class-string<Driver>|null     $driverClass
  201.      */
  202.     private static function createDriver(?string $driver, ?string $driverClass): Driver
  203.     {
  204.         if ($driverClass === null) {
  205.             if ($driver === null) {
  206.                 throw Exception::driverRequired();
  207.             }
  208.             if (! isset(self::DRIVER_MAP[$driver])) {
  209.                 throw Exception::unknownDriver($driverarray_keys(self::DRIVER_MAP));
  210.             }
  211.             $driverClass self::DRIVER_MAP[$driver];
  212.         } elseif (! is_a($driverClassDriver::class, true)) {
  213.             throw Exception::invalidDriverClass($driverClass);
  214.         }
  215.         return new $driverClass();
  216.     }
  217.     /**
  218.      * Extracts parts from a database URL, if present, and returns an
  219.      * updated list of parameters.
  220.      *
  221.      * @param mixed[] $params The list of parameters.
  222.      * @psalm-param Params $params
  223.      *
  224.      * @return mixed[] A modified list of parameters with info from a database
  225.      *                 URL extracted into indidivual parameter parts.
  226.      * @psalm-return Params
  227.      *
  228.      * @throws Exception
  229.      */
  230.     private static function parseDatabaseUrl(
  231.         #[SensitiveParameter]
  232.         array $params
  233.     ): array {
  234.         if (! isset($params['url'])) {
  235.             return $params;
  236.         }
  237.         Deprecation::trigger(
  238.             'doctrine/dbal',
  239.             'https://github.com/doctrine/dbal/pull/5843',
  240.             'The "url" connection parameter is deprecated. Please use %s to parse a database url before calling %s.',
  241.             DsnParser::class,
  242.             self::class,
  243.         );
  244.         $parser = new DsnParser(self::$driverSchemeAliases);
  245.         try {
  246.             $parsedParams $parser->parse($params['url']);
  247.         } catch (MalformedDsnException $e) {
  248.             throw new Exception('Malformed parameter "url".'0$e);
  249.         }
  250.         if (isset($parsedParams['driver'])) {
  251.             // The requested driver from the URL scheme takes precedence
  252.             // over the default custom driver from the connection parameters (if any).
  253.             unset($params['driverClass']);
  254.         }
  255.         $params array_merge($params$parsedParams);
  256.         // If a schemeless connection URL is given, we require a default driver or default custom driver
  257.         // as connection parameter.
  258.         if (! isset($params['driverClass']) && ! isset($params['driver'])) {
  259.             throw Exception::driverRequired($params['url']);
  260.         }
  261.         return $params;
  262.     }
  263. }