Share PDO connection between Doctrine and legacy ORM

[MAILPOET-2014]
This commit is contained in:
Jan Jakeš
2019-07-18 15:40:15 +02:00
committed by M. Shull
parent a07043cfb4
commit 0045683d92
8 changed files with 41 additions and 130 deletions

View File

@ -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');

View 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());
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -84,6 +84,6 @@ class ModelTest extends \MailPoetTest {
}
function _after() {
\ORM::setDb(null);
\ORM::setDb($this->connection->getWrappedConnection());
}
}