Share PDO connection between Doctrine and legacy ORM
[MAILPOET-2014]
This commit is contained in:
@ -1,64 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
use ORM as ORM;
|
use ORM;
|
||||||
use PDO as PDO;
|
use PDO;
|
||||||
|
|
||||||
if (!defined('ABSPATH')) exit;
|
if (!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
|
||||||
|
|
||||||
class Database {
|
class Database {
|
||||||
public $driver_option_wait_timeout = 60;
|
function init(PDO $pdo) {
|
||||||
|
ORM::setDb($pdo);
|
||||||
function init() {
|
|
||||||
$this->setupConnection();
|
|
||||||
$this->setupLogging();
|
$this->setupLogging();
|
||||||
$this->setupDriverOptions();
|
|
||||||
$this->defineTables();
|
$this->defineTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupConnection() {
|
|
||||||
ORM::configure(Env::$db_source_name);
|
|
||||||
ORM::configure('username', Env::$db_username);
|
|
||||||
ORM::configure('password', Env::$db_password);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupLogging() {
|
function setupLogging() {
|
||||||
ORM::configure('logging', WP_DEBUG);
|
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() {
|
function defineTables() {
|
||||||
if (!defined('MP_SETTINGS_TABLE')) {
|
if (!defined('MP_SETTINGS_TABLE')) {
|
||||||
define('MP_SETTINGS_TABLE', Env::$db_prefix . 'settings');
|
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 $lib_path;
|
||||||
static $plugin_prefix;
|
static $plugin_prefix;
|
||||||
static $db_prefix;
|
static $db_prefix;
|
||||||
static $db_source_name;
|
|
||||||
static $db_host;
|
static $db_host;
|
||||||
static $db_socket;
|
static $db_socket;
|
||||||
static $db_port;
|
static $db_port;
|
||||||
@ -79,33 +78,9 @@ class Env {
|
|||||||
self::$db_charset = $wpdb->charset;
|
self::$db_charset = $wpdb->charset;
|
||||||
self::$db_collation = $wpdb->collate;
|
self::$db_collation = $wpdb->collate;
|
||||||
self::$db_charset_collate = $wpdb->get_charset_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();
|
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) {
|
static function getDbTimezoneOffset($offset = false) {
|
||||||
$offset = ($offset) ? $offset : WPFunctions::get()->getOption('gmt_offset');
|
$offset = ($offset) ? $offset : WPFunctions::get()->getOption('gmt_offset');
|
||||||
$mins = $offset * 60;
|
$mins = $offset * 60;
|
||||||
|
@ -57,6 +57,9 @@ class Initializer {
|
|||||||
/** @var Shortcodes */
|
/** @var Shortcodes */
|
||||||
private $shortcodes;
|
private $shortcodes;
|
||||||
|
|
||||||
|
/** @var DatabaseInitializer */
|
||||||
|
private $database_initializer;
|
||||||
|
|
||||||
const INITIALIZED = 'MAILPOET_INITIALIZED';
|
const INITIALIZED = 'MAILPOET_INITIALIZED';
|
||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
@ -71,7 +74,8 @@ class Initializer {
|
|||||||
Menu $menu,
|
Menu $menu,
|
||||||
CronTrigger $cron_trigger,
|
CronTrigger $cron_trigger,
|
||||||
PermanentNotices $permanent_notices,
|
PermanentNotices $permanent_notices,
|
||||||
Shortcodes $shortcodes
|
Shortcodes $shortcodes,
|
||||||
|
DatabaseInitializer $database_initializer
|
||||||
) {
|
) {
|
||||||
$this->renderer_factory = $renderer_factory;
|
$this->renderer_factory = $renderer_factory;
|
||||||
$this->access_control = $access_control;
|
$this->access_control = $access_control;
|
||||||
@ -85,6 +89,7 @@ class Initializer {
|
|||||||
$this->cron_trigger = $cron_trigger;
|
$this->cron_trigger = $cron_trigger;
|
||||||
$this->permanent_notices = $permanent_notices;
|
$this->permanent_notices = $permanent_notices;
|
||||||
$this->shortcodes = $shortcodes;
|
$this->shortcodes = $shortcodes;
|
||||||
|
$this->database_initializer = $database_initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@ -100,7 +105,7 @@ class Initializer {
|
|||||||
$this->setupLocalizer();
|
$this->setupLocalizer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->setupDB();
|
$this->database_initializer->initializeConnection();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return WPNotice::displayError(Helpers::replaceLinkTags(
|
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'),
|
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();
|
return $this->activator->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupDB() {
|
|
||||||
$database = new Database();
|
|
||||||
$database->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
function preInitialize() {
|
function preInitialize() {
|
||||||
try {
|
try {
|
||||||
$this->renderer = $this->renderer_factory->getRenderer();
|
$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\Activator::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Config\Populator::class);
|
$container->autowire(\MailPoet\Config\Populator::class);
|
||||||
$container->autowire(\MailPoet\Config\Changelog::class)->setPublic(true);
|
$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\Hooks::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Config\Initializer::class)->setPublic(true);
|
$container->autowire(\MailPoet\Config\Initializer::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Config\Menu::class)->setPublic(true);
|
$container->autowire(\MailPoet\Config\Menu::class)->setPublic(true);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace MailPoet\Test\Config;
|
namespace MailPoet\Test\Config;
|
||||||
|
|
||||||
use Codeception\Util\Stub;
|
|
||||||
use MailPoet\Config\Database;
|
use MailPoet\Config\Database;
|
||||||
use MailPoet\Config\Env;
|
use MailPoet\Config\Env;
|
||||||
|
|
||||||
@ -26,29 +26,8 @@ class DatabaseTest extends \MailPoetTest {
|
|||||||
expect(\ORM::get_config('logging'))->equals(WP_DEBUG);
|
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() {
|
function testItSetsDBDriverOptions() {
|
||||||
$this->database->init();
|
$this->database->init($this->connection->getWrappedConnection());
|
||||||
$result = \ORM::for_table("")
|
$result = \ORM::for_table("")
|
||||||
->raw_query(
|
->raw_query(
|
||||||
'SELECT ' .
|
'SELECT ' .
|
||||||
@ -61,26 +40,4 @@ class DatabaseTest extends \MailPoetTest {
|
|||||||
// time zone should be set based on WP's time zone
|
// time zone should be set based on WP's time zone
|
||||||
expect($result->time_zone)->equals(Env::$db_timezone_offset);
|
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');
|
Env::init('file', '1.0.0', 'localhost', 'db_user', 'pass123', 'db_name');
|
||||||
expect(Env::$db_host)->equals('localhost');
|
expect(Env::$db_host)->equals('localhost');
|
||||||
expect(Env::$db_port)->equals('3306');
|
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');
|
Env::init('file', '1.0.0', 'localhost:3307', 'db_user', 'pass123', 'db_name');
|
||||||
expect(Env::$db_host)->equals('localhost');
|
expect(Env::$db_host)->equals('localhost');
|
||||||
expect(Env::$db_port)->equals('3307');
|
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() {
|
function testItProcessDBHostWithSocket() {
|
||||||
Env::init('file', '1.0.0', 'localhost:/var/lib/mysql/mysql55.sock', 'db_user', 'pass123', 'db_name');
|
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_host)->equals('localhost');
|
||||||
expect(Env::$db_socket)->equals('/var/lib/mysql/mysql55.sock');
|
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() {
|
function testItProcessDBHostWithIpV6Address() {
|
||||||
Env::init('file', '1.0.0', '::1', 'db_user', 'pass123', 'db_name');
|
Env::init('file', '1.0.0', '::1', 'db_user', 'pass123', 'db_name');
|
||||||
expect(Env::$db_host)->equals('::1');
|
expect(Env::$db_host)->equals('::1');
|
||||||
expect(Env::$db_socket)->equals(null);
|
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');
|
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_host)->equals('b57e:9b70:ab96:6a0b:5ba2:49e3:ebba:a036');
|
||||||
expect(Env::$db_socket)->equals(null);
|
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() {
|
function testItCanReturnDbName() {
|
||||||
expect(Env::$db_name)->equals(DB_NAME);
|
expect(Env::$db_name)->equals(DB_NAME);
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,6 @@ class ModelTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _after() {
|
function _after() {
|
||||||
\ORM::setDb(null);
|
\ORM::setDb($this->connection->getWrappedConnection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user