Share PDO connection between Doctrine and legacy ORM
[MAILPOET-2014]
This commit is contained in:
@ -1,64 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use ORM as ORM;
|
||||
use PDO as PDO;
|
||||
use ORM;
|
||||
use PDO;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
||||
|
||||
class Database {
|
||||
public $driver_option_wait_timeout = 60;
|
||||
|
||||
function init() {
|
||||
$this->setupConnection();
|
||||
function init(PDO $pdo) {
|
||||
ORM::setDb($pdo);
|
||||
$this->setupLogging();
|
||||
$this->setupDriverOptions();
|
||||
$this->defineTables();
|
||||
}
|
||||
|
||||
function setupConnection() {
|
||||
ORM::configure(Env::$db_source_name);
|
||||
ORM::configure('username', Env::$db_username);
|
||||
ORM::configure('password', Env::$db_password);
|
||||
}
|
||||
|
||||
function setupLogging() {
|
||||
ORM::configure('logging', WP_DEBUG);
|
||||
}
|
||||
|
||||
function setupDriverOptions() {
|
||||
$driver_options = [
|
||||
'TIME_ZONE = "' . Env::$db_timezone_offset . '"',
|
||||
'sql_mode=(SELECT REPLACE(@@sql_mode,"ONLY_FULL_GROUP_BY",""))',
|
||||
];
|
||||
|
||||
if (!empty(Env::$db_charset)) {
|
||||
$character_set = 'NAMES ' . Env::$db_charset;
|
||||
if (!empty(Env::$db_collation)) {
|
||||
$character_set .= ' COLLATE ' . Env::$db_collation;
|
||||
}
|
||||
$driver_options[] = $character_set;
|
||||
}
|
||||
|
||||
ORM::configure('driver_options', [
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET ' . implode(', ', $driver_options),
|
||||
]);
|
||||
|
||||
try {
|
||||
$current_options = ORM::for_table("")
|
||||
->raw_query('SELECT @@session.wait_timeout as wait_timeout')
|
||||
->findOne();
|
||||
if ($current_options && (int)$current_options->wait_timeout < $this->driver_option_wait_timeout) {
|
||||
ORM::raw_execute('SET SESSION wait_timeout = ' . $this->driver_option_wait_timeout);
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
// Rethrow PDOExceptions to prevent exposing sensitive data in stack traces
|
||||
throw new \Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function defineTables() {
|
||||
if (!defined('MP_SETTINGS_TABLE')) {
|
||||
define('MP_SETTINGS_TABLE', Env::$db_prefix . 'settings');
|
||||
|
24
lib/Config/DatabaseInitializer.php
Normal file
24
lib/Config/DatabaseInitializer.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||
use MailPoetVendor\Psr\Container\ContainerInterface;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class DatabaseInitializer {
|
||||
private $di_container;
|
||||
|
||||
function __construct(ContainerInterface $di_container) {
|
||||
$this->di_container = $di_container;
|
||||
}
|
||||
|
||||
function initializeConnection() {
|
||||
$connection = $this->di_container->get(Connection::class);
|
||||
|
||||
// pass the same PDO connection to legacy Database object
|
||||
$database = new Database();
|
||||
$database->init($connection->getWrappedConnection());
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@ class Env {
|
||||
static $lib_path;
|
||||
static $plugin_prefix;
|
||||
static $db_prefix;
|
||||
static $db_source_name;
|
||||
static $db_host;
|
||||
static $db_socket;
|
||||
static $db_port;
|
||||
@ -79,33 +78,9 @@ class Env {
|
||||
self::$db_charset = $wpdb->charset;
|
||||
self::$db_collation = $wpdb->collate;
|
||||
self::$db_charset_collate = $wpdb->get_charset_collate();
|
||||
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port, self::$db_charset, self::$db_name, $is_ipv6);
|
||||
self::$db_timezone_offset = self::getDbTimezoneOffset();
|
||||
}
|
||||
|
||||
private static function dbSourceName($host, $socket, $port, $charset, $db_name, $is_ipv6) {
|
||||
if ($is_ipv6) {
|
||||
$host = "[$host]";
|
||||
}
|
||||
$source_name = [
|
||||
'mysql:host=',
|
||||
$host,
|
||||
';',
|
||||
'port=',
|
||||
$port,
|
||||
';',
|
||||
'dbname=',
|
||||
$db_name,
|
||||
];
|
||||
if (!empty($socket)) {
|
||||
$source_name[] = ';unix_socket=' . $socket;
|
||||
}
|
||||
if (!empty($charset)) {
|
||||
$source_name[] = ';charset=' . $charset;
|
||||
}
|
||||
return implode('', $source_name);
|
||||
}
|
||||
|
||||
static function getDbTimezoneOffset($offset = false) {
|
||||
$offset = ($offset) ? $offset : WPFunctions::get()->getOption('gmt_offset');
|
||||
$mins = $offset * 60;
|
||||
|
@ -57,6 +57,9 @@ class Initializer {
|
||||
/** @var Shortcodes */
|
||||
private $shortcodes;
|
||||
|
||||
/** @var DatabaseInitializer */
|
||||
private $database_initializer;
|
||||
|
||||
const INITIALIZED = 'MAILPOET_INITIALIZED';
|
||||
|
||||
function __construct(
|
||||
@ -71,7 +74,8 @@ class Initializer {
|
||||
Menu $menu,
|
||||
CronTrigger $cron_trigger,
|
||||
PermanentNotices $permanent_notices,
|
||||
Shortcodes $shortcodes
|
||||
Shortcodes $shortcodes,
|
||||
DatabaseInitializer $database_initializer
|
||||
) {
|
||||
$this->renderer_factory = $renderer_factory;
|
||||
$this->access_control = $access_control;
|
||||
@ -85,6 +89,7 @@ class Initializer {
|
||||
$this->cron_trigger = $cron_trigger;
|
||||
$this->permanent_notices = $permanent_notices;
|
||||
$this->shortcodes = $shortcodes;
|
||||
$this->database_initializer = $database_initializer;
|
||||
}
|
||||
|
||||
function init() {
|
||||
@ -100,7 +105,7 @@ class Initializer {
|
||||
$this->setupLocalizer();
|
||||
|
||||
try {
|
||||
$this->setupDB();
|
||||
$this->database_initializer->initializeConnection();
|
||||
} catch (\Exception $e) {
|
||||
return WPNotice::displayError(Helpers::replaceLinkTags(
|
||||
WPFunctions::get()->__('Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.', 'mailpoet'),
|
||||
@ -158,11 +163,6 @@ class Initializer {
|
||||
return $this->activator->activate();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
$database = new Database();
|
||||
$database->init();
|
||||
}
|
||||
|
||||
function preInitialize() {
|
||||
try {
|
||||
$this->renderer = $this->renderer_factory->getRenderer();
|
||||
|
@ -80,6 +80,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
||||
$container->autowire(\MailPoet\Config\Activator::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Config\Populator::class);
|
||||
$container->autowire(\MailPoet\Config\Changelog::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Config\DatabaseInitializer::class);
|
||||
$container->autowire(\MailPoet\Config\Hooks::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Config\Initializer::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Config\Menu::class)->setPublic(true);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Test\Config;
|
||||
|
||||
use Codeception\Util\Stub;
|
||||
use MailPoet\Config\Database;
|
||||
use MailPoet\Config\Env;
|
||||
|
||||
@ -26,29 +26,8 @@ class DatabaseTest extends \MailPoetTest {
|
||||
expect(\ORM::get_config('logging'))->equals(WP_DEBUG);
|
||||
}
|
||||
|
||||
function testItSetsUpConnection() {
|
||||
expect(\ORM::get_config('username'))->equals(Env::$db_username);
|
||||
expect(\ORM::get_config('password'))->equals(Env::$db_password);
|
||||
}
|
||||
|
||||
function testItSelectivelyUpdatesDriverTimeoutOption() {
|
||||
$database = $this->database;
|
||||
$database->setupDriverOptions();
|
||||
$current_setting = \ORM::for_table("")
|
||||
->raw_query('SELECT @@session.wait_timeout as wait_timeout')
|
||||
->findOne();
|
||||
expect($current_setting->wait_timeout)->greaterThan($database->driver_option_wait_timeout);
|
||||
$this->_before();
|
||||
$database->driver_option_wait_timeout = 99999;
|
||||
$database->setupDriverOptions();
|
||||
$current_setting = \ORM::for_table("")
|
||||
->raw_query('SELECT @@session.wait_timeout as wait_timeout')
|
||||
->findOne();
|
||||
expect($current_setting->wait_timeout)->equals(99999);
|
||||
}
|
||||
|
||||
function testItSetsDBDriverOptions() {
|
||||
$this->database->init();
|
||||
$this->database->init($this->connection->getWrappedConnection());
|
||||
$result = \ORM::for_table("")
|
||||
->raw_query(
|
||||
'SELECT ' .
|
||||
@ -61,26 +40,4 @@ class DatabaseTest extends \MailPoetTest {
|
||||
// time zone should be set based on WP's time zone
|
||||
expect($result->time_zone)->equals(Env::$db_timezone_offset);
|
||||
}
|
||||
|
||||
function testItRethrowsPDOExceptions() {
|
||||
$message = 'Error message';
|
||||
$pdo = Stub::make(
|
||||
'PDO',
|
||||
[
|
||||
'prepare' => function() use ($message) {
|
||||
throw new \PDOException($message);
|
||||
},
|
||||
]
|
||||
);
|
||||
\ORM::setDb($pdo);
|
||||
try {
|
||||
$this->database->setupDriverOptions();
|
||||
$this->fail('Exception was not thrown');
|
||||
} catch (\Exception $e) {
|
||||
expect($e instanceof \PDOException)->false();
|
||||
expect($e->getMessage())->equals($message);
|
||||
}
|
||||
// Remove the DB stub
|
||||
$this->_before();
|
||||
}
|
||||
}
|
||||
|
@ -26,33 +26,28 @@ class EnvTest extends \MailPoetTest {
|
||||
Env::init('file', '1.0.0', 'localhost', 'db_user', 'pass123', 'db_name');
|
||||
expect(Env::$db_host)->equals('localhost');
|
||||
expect(Env::$db_port)->equals('3306');
|
||||
expect(Env::$db_source_name)->equals('mysql:host=localhost;port=3306;dbname=db_name;charset=' . ENV::$db_charset);
|
||||
|
||||
Env::init('file', '1.0.0', 'localhost:3307', 'db_user', 'pass123', 'db_name');
|
||||
expect(Env::$db_host)->equals('localhost');
|
||||
expect(Env::$db_port)->equals('3307');
|
||||
expect(Env::$db_source_name)->equals('mysql:host=localhost;port=3307;dbname=db_name;charset=' . ENV::$db_charset);
|
||||
}
|
||||
|
||||
function testItProcessDBHostWithSocket() {
|
||||
Env::init('file', '1.0.0', 'localhost:/var/lib/mysql/mysql55.sock', 'db_user', 'pass123', 'db_name');
|
||||
expect(Env::$db_host)->equals('localhost');
|
||||
expect(Env::$db_socket)->equals('/var/lib/mysql/mysql55.sock');
|
||||
expect(Env::$db_source_name)->equals('mysql:host=localhost;port=3306;dbname=db_name;unix_socket=/var/lib/mysql/mysql55.sock;charset=' . ENV::$db_charset);
|
||||
}
|
||||
|
||||
function testItProcessDBHostWithIpV6Address() {
|
||||
Env::init('file', '1.0.0', '::1', 'db_user', 'pass123', 'db_name');
|
||||
expect(Env::$db_host)->equals('::1');
|
||||
expect(Env::$db_socket)->equals(null);
|
||||
expect(Env::$db_source_name)->equals('mysql:host=[::1];port=3306;dbname=db_name;charset=' . ENV::$db_charset);
|
||||
|
||||
Env::init('file', '1.0.0', 'b57e:9b70:ab96:6a0b:5ba2:49e3:ebba:a036', 'db_user', 'pass123', 'db_name');
|
||||
expect(Env::$db_host)->equals('b57e:9b70:ab96:6a0b:5ba2:49e3:ebba:a036');
|
||||
expect(Env::$db_socket)->equals(null);
|
||||
expect(Env::$db_source_name)->equals('mysql:host=[b57e:9b70:ab96:6a0b:5ba2:49e3:ebba:a036];port=3306;dbname=db_name;charset=' . ENV::$db_charset);
|
||||
|
||||
}
|
||||
|
||||
function testItCanReturnDbName() {
|
||||
expect(Env::$db_name)->equals(DB_NAME);
|
||||
}
|
||||
|
@ -84,6 +84,6 @@ class ModelTest extends \MailPoetTest {
|
||||
}
|
||||
|
||||
function _after() {
|
||||
\ORM::setDb(null);
|
||||
\ORM::setDb($this->connection->getWrappedConnection());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user