From d65f1308275efcf8675d271fe7604e5689acac1b Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sun, 1 Apr 2018 19:53:57 -0700 Subject: [PATCH] [DBAL-3079] Reworked the usage of PDO in PDOConnection from inheritance to composition --- lib/Doctrine/DBAL/Connection.php | 17 ++-- .../Connections/MasterSlaveConnection.php | 9 +- lib/Doctrine/DBAL/Driver/Connection.php | 5 +- .../DBAL/Driver/IBMDB2/DB2Connection.php | 5 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 5 +- .../DBAL/Driver/OCI8/OCI8Connection.php | 6 +- lib/Doctrine/DBAL/Driver/PDOConnection.php | 82 +++++++++++++++---- lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 8 +- lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 6 +- .../SQLAnywhere/SQLAnywhereConnection.php | 7 +- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 5 +- lib/Doctrine/DBAL/Portability/Connection.php | 7 +- .../Tests/DBAL/Driver/PDOPgSql/DriverTest.php | 9 +- .../Tests/DBAL/Functional/DataAccessTest.php | 5 +- .../Functional/Driver/PDOConnectionTest.php | 4 +- .../Driver/PDOSqlsrv/DriverTest.php | 11 ++- .../DBAL/Functional/Ticket/DBAL630Test.php | 16 +++- 17 files changed, 128 insertions(+), 79 deletions(-) diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 10d1d909055..1579d276042 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -23,7 +23,6 @@ use Throwable; use function array_key_exists; use function assert; -use function func_get_args; use function implode; use function is_int; use function is_string; @@ -990,25 +989,19 @@ public function project($query, array $params, Closure $function) } /** - * Executes an SQL statement, returning a result set as a Statement object. - * - * @return \Doctrine\DBAL\Driver\Statement - * - * @throws DBALException + * {@inheritDoc} */ - public function query() + public function query(string $sql) { $connection = $this->getWrappedConnection(); - $args = func_get_args(); - $logger = $this->_config->getSQLLogger(); - $logger->startQuery($args[0]); + $logger->startQuery($sql); try { - $statement = $connection->query(...$args); + $statement = $connection->query($sql); } catch (Throwable $ex) { - throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); + throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } $statement->setFetchMode($this->defaultFetchMode); diff --git a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php index ba76be2db79..6cf1c371d83 100644 --- a/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php +++ b/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php @@ -13,7 +13,6 @@ use function array_rand; use function assert; use function count; -use function func_get_args; /** * Master-Slave Connection @@ -342,17 +341,15 @@ public function rollbackSavepoint($savepoint) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) { $this->connect('master'); assert($this->_conn instanceof DriverConnection); - $args = func_get_args(); - $logger = $this->getConfiguration()->getSQLLogger(); - $logger->startQuery($args[0]); + $logger->startQuery($sql); - $statement = $this->_conn->query(...$args); + $statement = $this->_conn->query($sql); $statement->setFetchMode($this->defaultFetchMode); diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 1574581c2ad..8d1d1384db0 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Driver; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\ParameterType; /** @@ -25,8 +26,10 @@ public function prepare($prepareString); * Executes an SQL statement, returning a result set as a Statement object. * * @return Statement + * + * @throws DBALException */ - public function query(); + public function query(string $sql); /** * Quotes a string for use in a query. diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php index cb1e6018f3e..561c9eb22a9 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -22,7 +22,6 @@ use function db2_rollback; use function db2_server_info; use function db2_stmt_errormsg; -use function func_get_args; class DB2Connection implements Connection, ServerInfoAwareConnection { @@ -89,10 +88,8 @@ public function prepare($sql) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 1f1a1d218c3..39ef8b2bd2a 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -15,7 +15,6 @@ use const MYSQLI_SERVER_PUBLIC_KEY; use function defined; use function floor; -use function func_get_args; use function in_array; use function ini_get; use function mysqli_errno; @@ -134,10 +133,8 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index c1857936f5a..4d95b66628b 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -10,7 +10,6 @@ use const OCI_DEFAULT; use const OCI_NO_AUTO_COMMIT; use function addcslashes; -use function func_get_args; use function is_float; use function is_int; use function oci_commit; @@ -111,11 +110,8 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; - //$fetchMode = $args[1]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index e3736a9da8b..09edf471662 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -4,14 +4,18 @@ use Doctrine\DBAL\ParameterType; use PDO; -use function func_get_args; +use function assert; /** * PDO implementation of the Connection interface. + * * Used by all PDO-based drivers. */ -class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection +class PDOConnection implements Connection, ServerInfoAwareConnection { + /** @var PDO */ + private $connection; + /** * @param string $dsn * @param string|null $user @@ -23,8 +27,8 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection public function __construct($dsn, $user = null, $password = null, ?array $options = null) { try { - parent::__construct($dsn, (string) $user, (string) $password, (array) $options); - $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection = new PDO($dsn, (string) $user, (string) $password, (array) $options); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -36,7 +40,7 @@ public function __construct($dsn, $user = null, $password = null, ?array $option public function exec($statement) { try { - return parent::exec($statement); + return $this->connection->exec($statement); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -47,17 +51,17 @@ public function exec($statement) */ public function getServerVersion() { - return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); + return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION); } /** * {@inheritdoc} */ - public function prepare($prepareString, $driverOptions = []) + public function prepare($prepareString) { try { return $this->createStatement( - parent::prepare($prepareString, $driverOptions) + $this->connection->prepare($prepareString) ); } catch (\PDOException $exception) { throw new PDOException($exception); @@ -67,14 +71,13 @@ public function prepare($prepareString, $driverOptions = []) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - try { - return $this->createStatement( - parent::query(...$args) - ); + $stmt = $this->connection->query($sql); + assert($stmt instanceof \PDOStatement); + + return $this->createStatement($stmt); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -85,7 +88,7 @@ public function query() */ public function quote($input, $type = ParameterType::STRING) { - return parent::quote($input, $type); + return $this->connection->quote($input, $type); } /** @@ -95,10 +98,10 @@ public function lastInsertId($name = null) { try { if ($name === null) { - return parent::lastInsertId(); + return $this->connection->lastInsertId(); } - return parent::lastInsertId($name); + return $this->connection->lastInsertId($name); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -119,4 +122,49 @@ protected function createStatement(\PDOStatement $stmt) : PDOStatement { return new PDOStatement($stmt); } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + return $this->connection->beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() + { + return $this->connection->commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + return $this->connection->rollBack(); + } + + /** + * {@inheritDoc} + */ + public function errorCode() + { + return $this->connection->errorCode(); + } + + /** + * {@inheritDoc} + */ + public function errorInfo() + { + return $this->connection->errorInfo(); + } + + public function getWrappedConnection() : PDO + { + return $this->connection; + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php index f25cd5cded3..f77f967ae47 100644 --- a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -20,7 +20,7 @@ class Driver extends AbstractPostgreSQLDriver public function connect(array $params, $username = null, $password = null, array $driverOptions = []) { try { - $pdo = new PDOConnection( + $connection = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, @@ -32,7 +32,7 @@ public function connect(array $params, $username = null, $password = null, array || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true ) ) { - $pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); + $connection->getWrappedConnection()->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); } /* defining client_encoding via SET NAMES to avoid inconsistent DSN support @@ -40,10 +40,10 @@ public function connect(array $params, $username = null, $password = null, array * - passing client_encoding via the 'options' param breaks pgbouncer support */ if (isset($params['charset'])) { - $pdo->exec('SET NAMES \'' . $params['charset'] . '\''); + $connection->exec('SET NAMES \'' . $params['charset'] . '\''); } - return $pdo; + return $connection; } catch (PDOException $e) { throw DBALException::driverException($this, $e); } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php index d08c6a2c848..7c960ab3e14 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -35,7 +35,7 @@ public function connect(array $params, $username = null, $password = null, array } try { - $pdo = new PDOConnection( + $connection = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, @@ -45,11 +45,13 @@ public function connect(array $params, $username = null, $password = null, array throw DBALException::driverException($this, $ex); } + $pdo = $connection->getWrappedConnection(); + foreach ($this->_userDefinedFunctions as $fn => $data) { $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); } - return $pdo; + return $connection; } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index d47782003e6..29de2ab95f3 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\ParameterType; use function assert; -use function func_get_args; use function is_float; use function is_int; use function is_resource; @@ -151,11 +150,9 @@ public function prepare($prepareString) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $stmt = $this->prepare($args[0]); - + $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index 35ad913ff5b..f64c5c537b2 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\ParameterType; use const SQLSRV_ERR_ERRORS; -use function func_get_args; use function is_float; use function is_int; use function sprintf; @@ -83,10 +82,8 @@ public function prepare($sql) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); diff --git a/lib/Doctrine/DBAL/Portability/Connection.php b/lib/Doctrine/DBAL/Portability/Connection.php index 0d5a7b3de8c..e2f660cef0c 100644 --- a/lib/Doctrine/DBAL/Portability/Connection.php +++ b/lib/Doctrine/DBAL/Portability/Connection.php @@ -8,7 +8,6 @@ use PDO; use const CASE_LOWER; use const CASE_UPPER; -use function func_get_args; /** * Portability wrapper for a Connection. @@ -65,7 +64,7 @@ public function connect() if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { if ($this->_conn instanceof PDOConnection) { // make use of c-level support for case handling - $this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); + $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); } else { $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; } @@ -116,11 +115,11 @@ public function prepare($statement) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) { $connection = $this->getWrappedConnection(); - $stmt = $connection->query(...func_get_args()); + $stmt = $connection->query($sql); $stmt = new Statement($stmt, $this); $stmt->setFetchMode($this->defaultFetchMode); diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php index 2b976233c27..ba0036ebe4a 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php @@ -36,7 +36,7 @@ public function testConnectionDisablesPreparesOnPhp56() : void self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); @@ -63,7 +63,10 @@ public function testConnectionDoesNotDisablePreparesOnPhp56WhenAttributeDefined( self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertNotSame(true, $connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertNotSame( + true, + $connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES) + ); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); @@ -90,7 +93,7 @@ public function testConnectionDisablePreparesOnPhp56WhenDisablePreparesIsExplici self::assertInstanceOf(PDOConnection::class, $connection); try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); + self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index b7d625c8600..e6381044a71 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -954,8 +954,9 @@ private function beforeFetchClassTest() : void } /** @var PDOConnection $connection */ - $connection = $this->connection->getWrappedConnection(); - $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); + $connection = $this->connection + ->getWrappedConnection(); + $connection->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php index 6dfb1b85c3d..204103a771a 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php @@ -90,7 +90,9 @@ public function testThrowsWrappedExceptionOnPrepare() : void // Emulated prepared statements have to be disabled for this test // so that PDO actually communicates with the database server to check the query. - $this->driverConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->driverConnection + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->expectException(PDOException::class); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php index d2dfd5925f5..ef468ccb99c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php @@ -4,9 +4,11 @@ use Doctrine\DBAL\Driver as DriverInterface; use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver; use Doctrine\Tests\DBAL\Functional\Driver\AbstractDriverTest; use PDO; +use function assert; use function extension_loaded; class DriverTest extends AbstractDriverTest @@ -70,6 +72,13 @@ public function testDriverOptions() : void { $connection = $this->getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]); - self::assertSame(PDO::CASE_UPPER, $connection->getAttribute(PDO::ATTR_CASE)); + assert($connection instanceof PDOConnection); + + self::assertSame( + PDO::CASE_UPPER, + $connection + ->getWrappedConnection() + ->getAttribute(PDO::ATTR_CASE) + ); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php index 687e6e834a0..b146d5a00fa 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php @@ -37,7 +37,9 @@ protected function setUp() : void protected function tearDown() : void { if ($this->running) { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } parent::tearDown(); @@ -71,7 +73,9 @@ public function testBooleanConversionBoolParamRealPrepares() : void public function testBooleanConversionBoolParamEmulatedPrepares() : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -95,7 +99,9 @@ public function testBooleanConversionNullParamEmulatedPrepares( ?bool $statementValue, ?bool $databaseConvertedValue ) : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -119,7 +125,9 @@ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInB ?bool $statementValue, bool $databaseConvertedValue ) : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->connection->getWrappedConnection() + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform();