dbalConnection)) { $this->dbalConnection = $this->createDbalConnection(); } return $this->dbalConnection; } public function getPdoConnection(): PDO { if (!isset($this->pdoConnection)) { $this->pdoConnection = $this->createPdoConnection(); } return $this->pdoConnection; } public function setPdoConnection(PDO $pdoConnection): void { $this->pdoConnection = $pdoConnection; } public function createDbalConnection(): DBALConnection { /** @var ?array $params */ $params = $this->config->get('database'); if (empty($params)) { throw new RuntimeException('Database params cannot be empty for DBAL connection.'); } $databaseParams = $this->createDatabaseParams($params); $platform = $databaseParams->getPlatform() ?? self::DEFAULT_PLATFORM; return $this->dbalConnectionFactoryFactory ->create($platform, $this->getPdoConnection()) ->create($databaseParams); } /** * Create PDO connection. * * @param array $params */ public function createPdoConnection(array $params = [], bool $skipDatabaseName = false): PDO { $params = array_merge( $this->config->get('database') ?? [], $params ); if ($skipDatabaseName && isset($params['dbname'])) { unset($params['dbname']); } $databaseParams = $this->createDatabaseParams($params); $platform = $databaseParams->getPlatform(); $pdoFactory = $this->pdoFactoryFactory->create($platform ?? ''); return $pdoFactory->create($databaseParams); } /** * @param array $params * @throws RuntimeException */ private function createDatabaseParams(array $params): DatabaseParams { $databaseParams = DatabaseParams::create() ->withHost($params['host'] ?? null) ->withPort(isset($params['port']) ? (int) $params['port'] : null) ->withName($params['dbname'] ?? null) ->withUsername($params['user'] ?? null) ->withPassword($params['password'] ?? null) ->withCharset($params['charset'] ?? 'utf8') ->withPlatform($params['platform'] ?? null) ->withSslCa($params['sslCA'] ?? null) ->withSslCert($params['sslCert'] ?? null) ->withSslKey($params['sslKey'] ?? null) ->withSslCaPath($params['sslCAPath'] ?? null) ->withSslCipher($params['sslCipher'] ?? null) ->withSslVerifyDisabled($params['sslVerifyDisabled'] ?? false); if (!$databaseParams->getPlatform()) { $databaseParams = $databaseParams->withPlatform(self::DEFAULT_PLATFORM); } return $databaseParams; } /** * Get maximum index length. If a table name is null, then get a value for all database tables. */ public function getMaxIndexLength(?string $tableName = null): int { $databaseType = $this->getDatabaseType(); if ($databaseType === self::TYPE_POSTGRESQL) { return 2704; // @todo Revise. } $tableEngine = $this->getTableEngine($tableName); if (!$tableEngine) { return self::DEFAULT_INDEX_LIMIT; } switch ($tableEngine) { case 'InnoDB': $databaseType = $this->getDatabaseType(); $version = $this->getDatabaseVersion() ?? ''; switch ($databaseType) { case self::TYPE_MARIADB: if (version_compare($version, '10.2.2') >= 0) { return 3072; // InnoDB, MariaDB 10.2.2+ } break; case self::TYPE_MYSQL: return 3072; } return 767; // InnoDB } return 1000; // MyISAM } /** * Get a database type (MySQL, MariaDB, PostgreSQL). */ public function getDatabaseType(): string { $version = $this->getFullDatabaseVersion() ?? ''; if (preg_match('/mariadb/i', $version)) { return self::TYPE_MARIADB; } if (preg_match('/postgresql/i', $version)) { return self::TYPE_POSTGRESQL; } return self::TYPE_MYSQL; } private function getFullDatabaseVersion(): ?string { $connection = $this->getPdoConnection(); $sth = $connection->prepare("select version()"); $sth->execute(); /** @var string|null|false $result */ $result = $sth->fetchColumn(); if ($result === false || $result === null) { return null; } return $result; } /** * Get a database version. * * @todo Add PostgreSQL support. */ public function getDatabaseVersion(): ?string { $fullVersion = $this->getFullDatabaseVersion() ?? ''; if (preg_match('/[0-9]+\.[0-9]+\.[0-9]+/', $fullVersion, $match)) { return $match[0]; } return null; } /** * Get a table or default engine. If a table name is null, get a value for all database tables. */ private function getTableEngine(?string $tableName = null): ?string { $databaseType = $this->getDatabaseType(); if (!in_array($databaseType, [self::TYPE_MYSQL, self::TYPE_MARIADB])) { return null; } $query = $tableName ? "SHOW TABLE STATUS WHERE Engine = 'MyISAM' AND Name = :tableName" : "SHOW TABLE STATUS WHERE Engine = 'MyISAM'"; $vars = []; if ($tableName) { $vars[':tableName'] = $tableName; } $sth = $this->getPdoConnection()->prepare($query); $sth->execute($vars); $result = $sth->fetchColumn(); if (!empty($result)) { return 'MyISAM'; } return 'InnoDB'; } public function getDatabaseParam(string $name): ?string { $databaseType = $this->getDatabaseType(); if ($databaseType === self::TYPE_POSTGRESQL) { // @todo Implement. return null; } $sql = "SHOW VARIABLES LIKE :param";; $sth = $this->getPdoConnection()->prepare($sql); $sth->execute([':param' => $name]); $row = $sth->fetch(PDO::FETCH_NUM); $index = 1; $value = $row[$index] ?: null; if ($value === null) { return null; } return (string) $value; } public function getDatabaseServerVersion(): string { $databaseType = $this->getDatabaseType(); $param = $databaseType === self::TYPE_POSTGRESQL ? 'server_version' : 'version'; return (string) $this->getDatabaseParam($param); } }