icingaweb2/library/Icinga/Web/Setup/DbTool.php

254 lines
7.0 KiB
PHP

<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Setup;
use PDO;
use PDOException;
use LogicException;
use Zend_Db_Adapter_Pdo_Mysql;
use Zend_Db_Adapter_Pdo_Pgsql;
use Icinga\Exception\ConfigurationError;
/**
* Utility class to ease working with databases when installing Icinga Web 2 or one of its modules
*/
class DbTool
{
/**
* The PDO database connection
*
* @var PDO
*/
protected $pdoConn;
/**
* The Zend database adapter
*
* @var Zend_Db_Adapter_Pdo_Abstract
*/
protected $zendConn;
/**
* The resource configuration
*
* @var array
*/
protected $config;
/**
* Create a new DbTool
*
* @param array $config The resource configuration to use
*/
public function __construct(array $config)
{
$this->config = $config;
}
/**
* Connect to the server
*
* @return self
*/
public function connectToHost()
{
$this->assertHostAccess();
$this->connect();
return $this;
}
/**
* Connect to the database
*
* @return self
*/
public function connectToDb()
{
$this->assertHostAccess();
$this->assertDatabaseAccess();
$this->connect($this->config['dbname']);
return $this;
}
/**
* Assert that all configuration values exist that are required to connect to a server
*
* @throws ConfigurationError
*/
protected function assertHostAccess()
{
if (false === isset($this->config['db'])) {
throw new ConfigurationError('Can\'t connect to database server of unknown type');
} elseif (false === isset($this->config['host'])) {
throw new ConfigurationError('Can\'t connect to database server without a hostname or address');
} elseif (false === isset($this->config['port'])) {
throw new ConfigurationError('Can\'t connect to database server without a port');
} elseif (false === isset($this->config['username'])) {
throw new ConfigurationError('Can\'t connect to database server without a username');
} elseif (false === isset($this->config['password'])) {
throw new ConfigurationError('Can\'t connect to database server without a password');
}
}
/**
* Assert that all configuration values exist that are required to connect to a database
*
* @throws ConfigurationError
*/
protected function assertDatabaseAccess()
{
if (false === isset($this->config['dbname'])) {
throw new ConfigurationError('Can\'t connect to database without a valid database name');
}
}
/**
* Assert that a connection with a database has been established
*
* @throws LogicException
*/
protected function assertConnectedToDb()
{
if ($this->zendConn === null) {
throw new LogicException('Not connected to database');
}
}
/**
* Establish a connection with the database or just the server by omitting the database name
*
* @param string $dbname The name of the database to connect to
*/
public function connect($dbname = null)
{
$this->_pdoConnect($dbname);
if ($dbname !== null) {
$this->_zendConnect($dbname);
}
}
/**
* Initialize Zend database adapter
*
* @param string $dbname The name of the database to connect with
*
* @throws ConfigurationError In case the resource type is not a supported PDO driver name
*/
protected function _zendConnect($dbname)
{
if ($this->zendConn !== null) {
return;
}
$config = array(
'dbname' => $dbname,
'username' => $this->config['username'],
'password' => $this->config['password']
);
if ($this->config['db'] === 'mysql') {
$this->zendConn = new Zend_Db_Adapter_Pdo_Mysql($config);
} elseif ($this->config['db'] === 'pgsql') {
$this->zendConn = new Zend_Db_Adapter_Pdo_Pgsql($config);
} else {
throw new ConfigurationError(
'Failed to connect to database. Unsupported PDO driver "%s"',
$this->config['db']
);
}
}
/**
* Initialize PDO connection
*
* @param string $dbname The name of the database to connect with
*/
protected function _pdoConnect($dbname)
{
if ($this->pdoConn !== null) {
return;
}
$this->pdoConn = new PDO(
$this->buildDsn($this->config['db'], $dbname),
$this->config['username'],
$this->config['password'],
array(PDO::ATTR_TIMEOUT => 1, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
}
/**
* Return a datasource name for the given database type and name
*
* @param string $dbtype
* @param string $dbname
*
* @return string
*
* @throws ConfigurationError In case the passed database type is not supported
*/
protected function buildDsn($dbtype, $dbname = null)
{
if ($dbtype === 'mysql') {
return 'mysql:host=' . $this->config['host'] . ';port=' . $this->config['port']
. ($dbname !== null ? ';dbname=' . $dbname : '');
} elseif ($dbtype === 'pgsql') {
return 'pgsql:host=' . $this->config['host'] . ';port=' . $this->config['port']
. ($dbname !== null ? ';dbname=' . $dbname : '');
} else {
throw new ConfigurationError(
'Failed to build data source name. Unsupported PDO driver "%s"',
$dbtype
);
}
}
/**
* Try to connect to the server and throw an exception if this fails
*
* @throws PDOException In case an error occurs that does not indicate that authentication failed
*/
public function checkConnectivity()
{
try {
$this->connectToHost();
} catch (PDOException $e) {
if ($this->config['db'] === 'mysql') {
$code = $e->getCode();
if ($code !== 1040 && $code !== 1045) {
throw $e;
}
} elseif ($this->config['db'] === 'pgsql') {
if (strpos($e->getMessage(), $this->config['username']) === false) {
throw $e;
}
}
}
}
/**
* Return whether the given privileges were granted
*
* @param array $privileges An array of strings with the required privilege names
*
* @return bool
*/
public function checkPrivileges(array $privileges)
{
return true; // TODO(7163): Implement privilege checks
}
/**
* Return a list of all existing database tables
*
* @return array
*/
public function listTables()
{
$this->assertConnectedToDb();
return $this->zendConn->listTables();
}
}