29
0
mirror of https://github.com/joomla/joomla-cms.git synced 2024-06-25 23:02:55 +00:00

[add] Add support for PDO based connections for MySQL. Closes #4123

This commit is contained in:
Michael Babker 2014-08-31 20:30:00 +02:00 committed by Thomas Hunziker
parent 8c2b02640b
commit 216b687439
37 changed files with 3805 additions and 39 deletions

View File

@ -193,7 +193,7 @@
type="databaseconnection"
label="COM_CONFIG_FIELD_DATABASE_TYPE_LABEL"
description="COM_CONFIG_FIELD_DATABASE_TYPE_DESC"
supported="mysql,mysqli,postgresql,sqlsrv,sqlazure"
supported="mysql,mysqli,pdomysql,postgresql,sqlsrv,sqlazure"
filter="string" />
<field

View File

@ -60,10 +60,11 @@ class ContactTableContact extends JTable
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified = $date->toSql();
if ($this->id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else

View File

@ -103,7 +103,7 @@ abstract class FinderIndexer
// Setup the adapter for the indexer.
$format = JFactory::getDbo()->name;
if ($format == 'mysqli')
if ($format == 'mysqli' || $format == 'pdomysql')
{
$format = 'mysql';
}

View File

@ -198,10 +198,11 @@ class FinderTableFilter extends JTable
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified = $date->toSql();
if ($this->filter_id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else

View File

@ -110,10 +110,12 @@ class NewsfeedsTableNewsfeed extends JTable
{
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified = $date->toSql();
if ($this->id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else

View File

@ -96,12 +96,9 @@ class RedirectTableLink extends JTable
{
$date = JFactory::getDate()->toSql();
if ($this->id)
{
// Existing item
$this->modified_date = $date;
}
else
$this->modified_date = $date;
if (!$this->id)
{
// New record.
$this->created_date = $date;

View File

@ -156,9 +156,11 @@ class TagsTableTag extends JTableNested
{
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified_time = $date->toSql();
if ($this->id) {
// Existing item
$this->modified_time = $date->toSql();
$this->modified_user_id = $user->get('id');
}
else

View File

@ -46,6 +46,8 @@ class UsersTableNote extends JTable
$date = JFactory::getDate()->toSql();
$userId = JFactory::getUser()->get('id');
$this->modified_time = $date;
if (empty($this->id))
{
// New record.
@ -55,7 +57,6 @@ class UsersTableNote extends JTable
else
{
// Existing record.
$this->modified_time = $date;
$this->modified_user_id = $userId;
}

View File

@ -80,10 +80,11 @@ class WeblinksTableWeblink extends JTable
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified = $date->toSql();
if ($this->id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else

View File

@ -950,6 +950,7 @@ PHPMAILER_TLS="Could not start TLS"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -180,6 +180,7 @@ INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="English (AU)"
;Database Model
INSTL_DATABASE_COULD_NOT_CONNECT="Could not connect to the database. Connector returned number: %s"
INSTL_DATABASE_COULD_NOT_CREATE_DATABASE="The installer could not connect to the specified database and was unable to create the database. Please verify your settings and if necessary manually create your database."
INSTL_DATABASE_COULD_NOT_REFRESH_MANIFEST_CACHE="Could not refresh manifest cache for extension: %s"
INSTL_DATABASE_EMPTY_NAME=""
INSTL_DATABASE_ERROR_BACKINGUP="Some errors occurred in backing up the database."
@ -191,6 +192,8 @@ INSTL_DATABASE_FIX_TOO_LONG="The MySQL table prefix must be a maximum of 15 char
INSTL_DATABASE_INVALID_DB_DETAILS="The database details provided are incorrect and/or empty."
INSTL_DATABASE_INVALID_MYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_MYSQLI_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_PDOMYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_POSTGRESQL_VERSION="You need PostgreSQL 8.3.18 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLSRV_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLZURE_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_TYPE="Please select the database type"
@ -306,6 +309,7 @@ SITE_NAME="Site Name"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -180,6 +180,7 @@ INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="English (UK)"
;Database Model
INSTL_DATABASE_COULD_NOT_CONNECT="Could not connect to the database. Connector returned number: %s"
INSTL_DATABASE_COULD_NOT_CREATE_DATABASE="The installer could not connect to the specified database and was unable to create the database. Please verify your settings and if necessary manually create your database."
INSTL_DATABASE_COULD_NOT_REFRESH_MANIFEST_CACHE="Could not refresh manifest cache for extension: %s"
INSTL_DATABASE_EMPTY_NAME=""
INSTL_DATABASE_ERROR_BACKINGUP="Some errors occurred in backing up the database."
@ -191,6 +192,8 @@ INSTL_DATABASE_FIX_TOO_LONG="The MySQL table prefix must be a maximum of 15 char
INSTL_DATABASE_INVALID_DB_DETAILS="The database details provided are incorrect and/or empty."
INSTL_DATABASE_INVALID_MYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_MYSQLI_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_PDOMYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_POSTGRESQL_VERSION="You need PostgreSQL 8.3.18 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLSRV_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLZURE_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_TYPE="Please select the database type"
@ -306,6 +309,7 @@ SITE_NAME="Site Name"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -178,6 +178,7 @@ INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="English (UK)"
;Database Model
INSTL_DATABASE_COULD_NOT_CONNECT="Could not connect to the database. Connector returned number: %s"
INSTL_DATABASE_COULD_NOT_CREATE_DATABASE="The installer could not connect to the specified database and was unable to create the database. Please verify your settings and if necessary manually create your database."
INSTL_DATABASE_COULD_NOT_REFRESH_MANIFEST_CACHE="Could not refresh manifest cache for extension: %s"
INSTL_DATABASE_EMPTY_NAME=""
INSTL_DATABASE_ERROR_BACKINGUP="Some errors occurred in backing up the database."
@ -189,6 +190,8 @@ INSTL_DATABASE_FIX_TOO_LONG="The MySQL table prefix must be a maximum of 15 char
INSTL_DATABASE_INVALID_DB_DETAILS="The database details provided are incorrect and/or empty."
INSTL_DATABASE_INVALID_MYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_MYSQLI_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_PDOMYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_POSTGRESQL_VERSION="You need PostgreSQL 8.3.18 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLSRV_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLZURE_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_TYPE="Please select the database type"
@ -304,6 +307,7 @@ SITE_NAME="Site Name"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -180,6 +180,7 @@ INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="English (US)"
;Database Model
INSTL_DATABASE_COULD_NOT_CONNECT="Could not connect to the database. Connector returned number: %s"
INSTL_DATABASE_COULD_NOT_CREATE_DATABASE="The installer could not connect to the specified database and was unable to create the database. Please verify your settings and if necessary manually create your database."
INSTL_DATABASE_COULD_NOT_REFRESH_MANIFEST_CACHE="Could not refresh manifest cache for extension: %s"
INSTL_DATABASE_EMPTY_NAME=""
INSTL_DATABASE_ERROR_BACKINGUP="Some errors occurred in backing up the database."
@ -191,6 +192,8 @@ INSTL_DATABASE_FIX_TOO_LONG="The MySQL table prefix must be a maximum of 15 char
INSTL_DATABASE_INVALID_DB_DETAILS="The database details provided are incorrect and/or empty."
INSTL_DATABASE_INVALID_MYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_MYSQLI_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_PDOMYSQL_VERSION="You need MySQL 5.0.4 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_POSTGRESQL_VERSION="You need PostgreSQL 8.3.18 or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLSRV_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_SQLZURE_VERSION="You need SQL Server 2008 R2 (10.50.1600.1) or higher to continue the installation. Your version is: %s"
INSTL_DATABASE_INVALID_TYPE="Please select the database type"
@ -306,6 +309,7 @@ SITE_NAME="Site Name"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -83,7 +83,7 @@ class InstallationModelDatabase extends JModelBase
*
* @param array $options The options to use for configuration
*
* @return boolean True on success
* @return JDatabaseDriver|boolean Database object on success, boolean false on failure
*
* @since 3.1
*/
@ -208,8 +208,70 @@ class InstallationModelDatabase extends JModelBase
}
catch (RuntimeException $e)
{
$app->enqueueMessage(JText::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'notice');
return false;
/*
* We may get here if the database doesn't exist, if so then explain that to users instead of showing the database connector's error
* This only supports PostgreSQL and the PDO MySQL drivers presently
*
* Error Messages:
* PDO MySQL: [1049] Unknown database 'database_name'
* PostgreSQL: Error connecting to PGSQL database
*/
if ($type == 'pdomysql' && strpos($e->getMessage(), '[1049] Unknown database') === 42)
{
/*
* Now we're really getting insane here; we're going to try building a new JDatabaseDriver instance without the database name
* in order to trick the connection into creating the database
*/
$altDBoptions = array(
'driver' => $options->db_type,
'host' => $options->db_host,
'user' => $options->db_user,
'password' => $options->db_pass,
'prefix' => $options->db_prefix,
'select' => $options->db_select
);
$altDB = JDatabaseDriver::getInstance($altDBoptions);
// Try to create the database now using the alternate driver
try
{
$this->createDB($altDB, $options, $altDB->hasUTFSupport());
}
catch (RuntimeException $e)
{
// We did everything we could
$app->enqueueMessage(JText::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 'notice');
return false;
}
// If we got here, the database should have been successfully created, now try one more time to get the version
try
{
$db_version = $db->getVersion();
}
catch (RuntimeException $e)
{
// We did everything we could
$app->enqueueMessage(JText::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'notice');
return false;
}
}
elseif ($type == 'postgresql' && strpos($e->getMessage(), 'Error connecting to PGSQL database') === 42)
{
$app->enqueueMessage(JText::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 'notice');
return false;
}
// Anything getting into this part of the conditional either doesn't support manually creating the database or isn't that type of error
else
{
$app->enqueueMessage(JText::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'notice');
return false;
}
}
if (!$db->isMinimumVersion())
@ -218,7 +280,7 @@ class InstallationModelDatabase extends JModelBase
return false;
}
if (($type == 'mysql') || ($type == 'mysqli'))
if (($type == 'mysql') || ($type == 'mysqli') || ($type == 'pdomysql'))
{
// @internal MySQL versions pre 5.1.6 forbid . / or \ or NULL
if ((preg_match('#[\\\/\.\0]#', $options->db_name)) && (!version_compare($db_version, '5.1.6', '>=')))
@ -377,7 +439,7 @@ class InstallationModelDatabase extends JModelBase
$this->setDatabaseCharset($db, $options->db_name);
// Set the appropriate schema script based on UTF-8 support.
if ($type == 'mysqli' || $type == 'mysql')
if (($type == 'mysql') || ($type == 'mysqli') || ($type == 'pdomysql'))
{
$schema = 'sql/mysql/joomla.sql';
}
@ -406,7 +468,7 @@ class InstallationModelDatabase extends JModelBase
// Attempt to update the table #__schema.
$pathPart = JPATH_ADMINISTRATOR . '/components/com_admin/sql/updates/';
if ($type == 'mysqli' || $type == 'mysql')
if (($type == 'mysql') || ($type == 'mysqli') || ($type == 'pdomysql'))
{
$pathPart .= 'mysql/';
}
@ -486,7 +548,7 @@ class InstallationModelDatabase extends JModelBase
}
// Load the localise.sql for translating the data in joomla.sql
if ($type == 'mysqli' || $type == 'mysql')
if (($type == 'mysql') || ($type == 'mysqli') || ($type == 'pdomysql'))
{
$dblocalise = 'sql/mysql/localise.sql';
}
@ -583,7 +645,7 @@ class InstallationModelDatabase extends JModelBase
// Build the path to the sample data file.
$type = $options->db_type;
if ($type == 'mysqli')
if ($type == 'mysqli' || $type == 'pdomysql')
{
$type = 'mysql';
}

View File

@ -40,7 +40,7 @@ class JFormFieldSample extends JFormFieldRadio
$type = $this->form->getValue('db_type');
// Some database drivers share DDLs; point these drivers to the correct parent
if ($type == 'mysqli')
if ($type == 'mysqli' || $type == 'pdomysql')
{
$type = 'mysql';
}

View File

@ -5,7 +5,7 @@
<field name="db_type" type="databaseconnection"
id="db_type" class="inputbox"
label="INSTL_DATABASE_TYPE_LABEL"
supported="mysql,mysqli,postgresql,sqlsrv,sqlazure"
supported="mysql,mysqli,pdomysql,postgresql,sqlsrv,sqlazure"
required="true"
default="mysqli"
filter="string"

View File

@ -332,6 +332,7 @@ PHPMAILER_TLS="Could not start TLS"
MYSQL="MySQL"
MYSQLI="MySQLi"
ORACLE="Oracle"
PDOMYSQL="MySQL (PDO)"
POSTGRESQL="PostgreSQL"
SQLAZURE="Microsoft SQL Azure"
SQLITE="SQLite"

View File

@ -891,7 +891,7 @@ class JInstaller extends JAdapter
$db = & $this->_db;
$dbDriver = strtolower($db->name);
if ($dbDriver == 'mysqli')
if ($dbDriver == 'mysqli' || $dbDriver == 'pdomysql')
{
$dbDriver = 'mysql';
}
@ -902,7 +902,7 @@ class JInstaller extends JAdapter
$fCharset = (strtolower($file->attributes()->charset) == 'utf8') ? 'utf8' : '';
$fDriver = strtolower($file->attributes()->driver);
if ($fDriver == 'mysqli')
if ($fDriver == 'mysqli' || $fDriver == 'pdomysql')
{
$fDriver = 'mysql';
}
@ -987,7 +987,7 @@ class JInstaller extends JAdapter
{
$dbDriver = strtolower($db->name);
if ($dbDriver == 'mysqli')
if ($dbDriver == 'mysqli' || $dbDriver == 'pdomysql')
{
$dbDriver = 'mysql';
}
@ -1054,7 +1054,7 @@ class JInstaller extends JAdapter
{
$dbDriver = strtolower($db->name);
if ($dbDriver == 'mysqli')
if ($dbDriver == 'mysqli' || $dbDriver == 'pdomysql')
{
$dbDriver = 'mysql';
}
@ -1068,7 +1068,7 @@ class JInstaller extends JAdapter
// Assuming that the type is a mandatory attribute but if it is not mandatory then there should be a discussion for it.
$uDriver = strtolower($attrs['type']);
if ($uDriver == 'mysqli')
if ($uDriver == 'mysqli' || $uDriver == 'pdomysql')
{
$uDriver = 'mysql';
}

View File

@ -143,7 +143,7 @@ abstract class JSchemaChangeitem
// Get the class name
$dbname = $db->name;
if ($dbname == 'mysqli')
if ($dbname == 'mysqli' || $dbname == 'pdomysql')
{
$dbname = 'mysql';
}

View File

@ -195,7 +195,7 @@ class JSchemaChangeset
// Get the folder from the database name
$sqlFolder = $this->db->name;
if ($sqlFolder == 'mysqli')
if ($sqlFolder == 'mysqli' || $sqlFolder == 'pdomysql')
{
$sqlFolder = 'mysql';
}

View File

@ -201,13 +201,15 @@ abstract class JDatabaseDriverPdo extends JDatabaseDriver
break;
// The pdomysql case is a special case within the CMS environment
case 'pdomysql':
case 'mysql':
$this->options['port'] = (isset($this->options['port'])) ? $this->options['port'] : 3306;
$format = 'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$format = 'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#;charset=#CHARSET#';
$replace = array('#HOST#', '#PORT#', '#DBNAME#');
$with = array($this->options['host'], $this->options['port'], $this->options['database']);
$replace = array('#HOST#', '#PORT#', '#DBNAME#', '#CHARSET#');
$with = array($this->options['host'], $this->options['port'], $this->options['database'], $this->options['charset']);
break;
@ -253,7 +255,6 @@ abstract class JDatabaseDriverPdo extends JDatabaseDriver
break;
case 'sqlite':
if (isset($this->options['version']) && $this->options['version'] == 2)
{
$format = 'sqlite2:#DBNAME#';

View File

@ -0,0 +1,485 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database driver supporting PDO based connections
*
* @package Joomla.Platform
* @subpackage Database
* @see http://php.net/manual/en/ref.pdo-mysql.php
* @since 3.4
*/
class JDatabaseDriverPdomysql extends JDatabaseDriverPdo
{
/**
* The name of the database driver.
*
* @var string
* @since 3.4
*/
public $name = 'pdomysql';
/**
* The character(s) used to quote SQL statement names such as table names or field names,
* etc. The child classes should define this as necessary. If a single character string the
* same character is used for both sides of the quoted name, else the first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.4
*/
protected $nameQuote = '`';
/**
* The null or zero representation of a timestamp for the database driver. This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.4
*/
protected $nullDate = '0000-00-00 00:00:00';
/**
* The minimum supported database version.
*
* @var string
* @since 3.4
*/
protected static $dbMinimum = '5.0.4';
/**
* Constructor.
*
* @param array $options Array of database options with keys: host, user, password, database, select.
*
* @since 3.4
*/
public function __construct($options)
{
// Get some basic values from the options.
$options['driver'] = 'mysql';
$options['charset'] = (isset($options['charset'])) ? $options['charset'] : 'utf8';
$this->charset = $options['charset'];
// Finalize initialisation.
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.4
* @throws RuntimeException
*/
public function connect()
{
parent::connect();
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
/**
* Test to see if the MySQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.4
*/
public static function isSupported()
{
return in_array('mysql', PDO::getAvailableDrivers());
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
*
* @return JDatabaseDriverPdomysql Returns this object to support chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true);
$query->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $this->quoteName($tableName));
$this->setQuery($query);
$this->execute();
return $this;
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.4
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
$this->setQuery('USE ' . $this->quoteName($database));
$this->execute();
return $this;
}
/**
* Method to get the database collation in use by sampling a text field of a table in the database.
*
* @return mixed The collation in use by the database (string) or boolean false if not supported.
*
* @since 3.4
* @throws RuntimeException
*/
public function getCollation()
{
$this->connect();
// Attempt to get the database collation by accessing the server system variable.
$this->setQuery('SHOW VARIABLES LIKE "collation_database"');
$result = $this->loadObject();
if (property_exists($result, 'Value'))
{
return $result->Value;
}
else
{
return false;
}
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
// Initialise variables.
$result = array();
// Sanitize input to an array and iterate over the list.
settype($tables, 'array');
foreach ($tables as $table)
{
$this->setQuery('SHOW CREATE TABLE ' . $this->quoteName($table));
$row = $this->loadRow();
// Populate the result array based on the create statements.
$result[$table] = $row[1];
}
return $result;
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$result = array();
// Set the query to get the table fields statement.
$this->setQuery('SHOW FULL COLUMNS FROM ' . $this->quoteName($table));
$fields = $this->loadObjectList();
// If we only want the type as the value add just that to the list.
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->Field] = preg_replace("/[(0-9)]/", '', $field->Type);
}
}
// If we want the whole field data object add that to the list.
else
{
foreach ($fields as $field)
{
$result[$field->Field] = $field;
}
}
return $result;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// Get the details columns information.
$this->setQuery('SHOW KEYS FROM ' . $this->quoteName($table));
$keys = $this->loadObjectList();
return $keys;
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
// Set the query to get the tables statement.
$this->setQuery('SHOW TABLES');
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.4
*/
public function getVersion()
{
$this->connect();
return $this->getOption(PDO::ATTR_SERVER_VERSION);
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseDriverPdomysql Returns this object to support chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function lockTable($table)
{
$this->setQuery('LOCK TABLES ' . $this->quoteName($table) . ' WRITE')->execute();
return $this;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by MySQL.
* @param string $prefix Not used by MySQL.
*
* @return JDatabaseDriverPdomysql Returns this object to support chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
{
$this->setQuery('RENAME TABLE ' . $this->quoteName($oldTable) . ' TO ' . $this->quoteName($newTable));
$this->execute();
return $this;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* Oracle escaping reference:
* http://www.orafaq.com/wiki/SQL_FAQ#How_does_one_escape_special_characters_when_writing_SQL_queries.3F
*
* SQLite escaping notes:
* http://www.sqlite.org/faq.html#q14
*
* Method body is as implemented by the Zend Framework
*
* Note: Using query objects with bound variables is
* preferable to the below.
*
* @param string $text The string to be escaped.
* @param boolean $extra Unused optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 3.4
*/
public function escape($text, $extra = false)
{
$this->connect();
if (is_int($text) || is_float($text))
{
return $text;
}
$result = substr($this->connection->quote($text), 1, -1);
if ($extra)
{
$result = addcslashes($result, '%_');
}
return $result;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverPdomysql Returns this object to support chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function unlockTables()
{
$this->setQuery('UNLOCK TABLES')->execute();
return $this;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionCommit($toSavepoint);
}
else
{
$this->transactionDepth--;
}
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last savepoint.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionRollback($toSavepoint);
}
else
{
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' . $this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
parent::transactionStart($asSavepoint);
}
else
{
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
}
}

View File

@ -0,0 +1,113 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL export driver for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseExporterPdomysql extends JDatabaseExporter
{
/**
* Builds the XML data for the tables to export.
*
* @return string An XML string
*
* @since 3.4
* @throws Exception if an error occurs.
*/
protected function buildXml()
{
$buffer = array();
$buffer[] = '<?xml version="1.0"?>';
$buffer[] = '<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$buffer[] = ' <database name="">';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' </database>';
$buffer[] = '</mysqldump>';
return implode("\n", $buffer);
}
/**
* Builds the XML structure to export.
*
* @return array An array of XML lines (strings).
*
* @since 3.4
* @throws Exception if an error occurs.
*/
protected function buildXmlStructure()
{
$buffer = array();
foreach ($this->from as $table)
{
// Replace the magic prefix if found.
$table = $this->getGenericTableName($table);
// Get the details columns information.
$fields = $this->db->getTableColumns($table, false);
$keys = $this->db->getTableKeys($table);
$buffer[] = ' <table_structure name="' . $table . '">';
foreach ($fields as $field)
{
$buffer[] = ' <field Field="' . $field->Field . '"' . ' Type="' . $field->Type . '"' . ' Null="' . $field->Null . '"' . ' Key="' .
$field->Key . '"' . (isset($field->Default) ? ' Default="' . $field->Default . '"' : '') . ' Extra="' . $field->Extra . '"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' <key Table="' . $table . '"' . ' Non_unique="' . $key->Non_unique . '"' . ' Key_name="' . $key->Key_name . '"' .
' Seq_in_index="' . $key->Seq_in_index . '"' . ' Column_name="' . $key->Column_name . '"' . ' Collation="' . $key->Collation . '"' .
' Null="' . $key->Null . '"' . ' Index_type="' . $key->Index_type . '"' . ' Comment="' . htmlspecialchars($key->Comment) . '"' .
' />';
}
$buffer[] = ' </table_structure>';
}
return $buffer;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterPdomysql Method supports chaining.
*
* @since 3.4
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPdomysql))
{
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}

View File

@ -0,0 +1,437 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL import driver for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseImporterPdomysql extends JDatabaseImporter
{
/**
* Get the SQL syntax to add a column.
*
* @param string $table The table name.
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.4
*/
protected function getAddColumnSQL($table, SimpleXMLElement $field)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD COLUMN ' . $this->getColumnSQL($field);
return $sql;
}
/**
* Get the SQL syntax to add a key.
*
* @param string $table The table name.
* @param array $keys An array of the fields pertaining to this key.
*
* @return string
*
* @since 3.4
*/
protected function getAddKeySQL($table, $keys)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySQL($keys);
return $sql;
}
/**
* Get alters for table if there is a difference.
*
* @param SimpleXMLElement $structure The XML structure pf the table.
*
* @return array
*
* @since 3.4
*/
protected function getAlterTableSQL(SimpleXMLElement $structure)
{
// Initialise variables.
$table = $this->getRealTableName($structure['name']);
$oldFields = $this->db->getTableColumns($table);
$oldKeys = $this->db->getTableKeys($table);
$alters = array();
// Get the fields and keys from the XML that we are aiming for.
$newFields = $structure->xpath('field');
$newKeys = $structure->xpath('key');
// Loop through each field in the new structure.
foreach ($newFields as $field)
{
$fName = (string) $field['Field'];
if (isset($oldFields[$fName]))
{
// The field exists, check it's the same.
$column = $oldFields[$fName];
// Test whether there is a change.
$change = ((string) $field['Type'] != $column->Type) || ((string) $field['Null'] != $column->Null)
|| ((string) $field['Default'] != $column->Default) || ((string) $field['Extra'] != $column->Extra);
if ($change)
{
$alters[] = $this->getChangeColumnSQL($table, $field);
}
// Unset this field so that what we have left are fields that need to be removed.
unset($oldFields[$fName]);
}
else
{
// The field is new.
$alters[] = $this->getAddColumnSQL($table, $field);
}
}
// Any columns left are orphans
foreach ($oldFields as $name => $column)
{
// Delete the column.
$alters[] = $this->getDropColumnSQL($table, $name);
}
// Get the lookups for the old and new keys.
$oldLookup = $this->getKeyLookup($oldKeys);
$newLookup = $this->getKeyLookup($newKeys);
// Loop through each key in the new structure.
foreach ($newLookup as $name => $keys)
{
// Check if there are keys on this field in the existing table.
if (isset($oldLookup[$name]))
{
$same = true;
$newCount = count($newLookup[$name]);
$oldCount = count($oldLookup[$name]);
// There is a key on this field in the old and new tables. Are they the same?
if ($newCount == $oldCount)
{
// Need to loop through each key and do a fine grained check.
for ($i = 0; $i < $newCount; $i++)
{
$same = (((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique)
&& ((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name)
&& ((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index)
&& ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation)
&& ((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type));
/*
Debug.
echo '<pre>';
echo '<br />Non_unique: '.
((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique ? 'Pass' : 'Fail').' '.
(string) $newLookup[$name][$i]['Non_unique'].' vs '.$oldLookup[$name][$i]->Non_unique;
echo '<br />Column_name: '.
((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name ? 'Pass' : 'Fail').' '.
(string) $newLookup[$name][$i]['Column_name'].' vs '.$oldLookup[$name][$i]->Column_name;
echo '<br />Seq_in_index: '.
((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index ? 'Pass' : 'Fail').' '.
(string) $newLookup[$name][$i]['Seq_in_index'].' vs '.$oldLookup[$name][$i]->Seq_in_index;
echo '<br />Collation: '.
((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '.
(string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation;
echo '<br />Index_type: '.
((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type ? 'Pass' : 'Fail').' '.
(string) $newLookup[$name][$i]['Index_type'].' vs '.$oldLookup[$name][$i]->Index_type;
echo '<br />Same = '.($same ? 'true' : 'false');
echo '</pre>';
*/
if (!$same)
{
// Break out of the loop. No need to check further.
break;
}
}
}
else
{
// Count is different, just drop and add.
$same = false;
}
if (!$same)
{
$alters[] = $this->getDropKeySQL($table, $name);
$alters[] = $this->getAddKeySQL($table, $keys);
}
// Unset this field so that what we have left are fields that need to be removed.
unset($oldLookup[$name]);
}
else
{
// This is a new key.
$alters[] = $this->getAddKeySQL($table, $keys);
}
}
// Any keys left are orphans.
foreach ($oldLookup as $name => $keys)
{
if (strtoupper($name) == 'PRIMARY')
{
$alters[] = $this->getDropPrimaryKeySQL($table);
}
else
{
$alters[] = $this->getDropKeySQL($table, $name);
}
}
return $alters;
}
/**
* Get the syntax to alter a column.
*
* @param string $table The name of the database table to alter.
* @param SimpleXMLElement $field The XML definition for the field.
*
* @return string
*
* @since 3.4
*/
protected function getChangeColumnSQL($table, SimpleXMLElement $field)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' '
. $this->getColumnSQL($field);
return $sql;
}
/**
* Get the SQL syntax for a single column that would be included in a table create or alter statement.
*
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.4
*/
protected function getColumnSQL(SimpleXMLElement $field)
{
// Initialise variables.
// TODO Incorporate into parent class and use $this.
$blobs = array('text', 'smalltext', 'mediumtext', 'largetext');
$fName = (string) $field['Field'];
$fType = (string) $field['Type'];
$fNull = (string) $field['Null'];
$fDefault = isset($field['Default']) ? (string) $field['Default'] : null;
$fExtra = (string) $field['Extra'];
$sql = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$sql .= ' NOT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault);
}
}
else
{
if ($fDefault === null)
{
$sql .= ' DEFAULT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' DEFAULT ' . $this->db->quote($fDefault);
}
}
if ($fExtra)
{
$sql .= ' ' . strtoupper($fExtra);
}
return $sql;
}
/**
* Get the SQL syntax to drop a column.
*
* @param string $table The table name.
* @param string $name The name of the field to drop.
*
* @return string
*
* @since 3.4
*/
protected function getDropColumnSQL($table, $name)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP COLUMN ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
* @param string $name The name of the key to drop.
*
* @return string
*
* @since 3.4
*/
protected function getDropKeySQL($table, $name)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
*
* @return string
*
* @since 3.4
*/
protected function getDropPrimaryKeySQL($table)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY';
return $sql;
}
/**
* Get the details list of keys for a table.
*
* @param array $keys An array of objects that comprise the keys for the table.
*
* @return array The lookup array. array({key name} => array(object, ...))
*
* @since 3.4
* @throws Exception
*/
protected function getKeyLookup($keys)
{
// First pass, create a lookup of the keys.
$lookup = array();
foreach ($keys as $key)
{
if ($key instanceof SimpleXMLElement)
{
$kName = (string) $key['Key_name'];
}
else
{
$kName = $key->Key_name;
}
if (empty($lookup[$kName]))
{
$lookup[$kName] = array();
}
$lookup[$kName][] = $key;
}
return $lookup;
}
/**
* Get the SQL syntax for a key.
*
* @param array $columns An array of SimpleXMLElement objects comprising the key.
*
* @return string
*
* @since 3.4
*/
protected function getKeySQL($columns)
{
// TODO Error checking on array and element types.
$kNonUnique = (string) $columns[0]['Non_unique'];
$kName = (string) $columns[0]['Key_name'];
$kColumn = (string) $columns[0]['Column_name'];
$prefix = '';
if ($kName == 'PRIMARY')
{
$prefix = 'PRIMARY ';
}
elseif ($kNonUnique == 0)
{
$prefix = 'UNIQUE ';
}
$nColumns = count($columns);
$kColumns = array();
if ($nColumns == 1)
{
$kColumns[] = $this->db->quoteName($kColumn);
}
else
{
foreach ($columns as $column)
{
$kColumns[] = (string) $column['Column_name'];
}
}
$sql = $prefix . 'KEY ' . ($kName != 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')';
return $sql;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterPdomysql Method supports chaining.
*
* @since 3.4
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPdomysql))
{
throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database iterator for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @see http://dev.mysql.com/doc/
* @since 3.4
*/
class JDatabaseIteratorPdomysql extends JDatabaseIteratorPdo
{
}

View File

@ -0,0 +1,21 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseQueryPdomysql extends JDatabaseQueryMysqli
{
}

View File

@ -210,10 +210,11 @@ class JTableCategory extends JTableNested
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified_time = $date->toSql();
if ($this->id)
{
// Existing category
$this->modified_time = $date->toSql();
$this->modified_user_id = $user->get('id');
}
else

View File

@ -249,10 +249,11 @@ class JTableContent extends JTable
$date = JFactory::getDate();
$user = JFactory::getUser();
$this->modified = $date->toSql();
if ($this->id)
{
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
}
else

View File

@ -4,6 +4,7 @@
<php>
<const name="JTEST_DATABASE_MYSQL_DSN" value="host=localhost;dbname=joomla_ut;user=utuser;pass=ut1234" />
<const name="JTEST_DATABASE_MYSQLI_DSN" value="host=localhost;dbname=joomla_ut;user=utuser;pass=ut1234" />
<const name="JTEST_DATABASE_PDO_MYSQL_DSN" value="host=localhost;dbname=joomla_ut;user=utuser;pass=ut1234" />
<const name="JTEST_DATABASE_POSTGRESQL_DSN" value="host=localhost;port=5432;dbname=joomla_ut;user=utuser;pass=ut1234" />
<const name="JTEST_DATABASE_SQLSRV_DSN" value="host=localhost;dbname=joomla_ut;user=utuser;pass=ut1234" />
</php>

View File

@ -749,7 +749,7 @@ class PlgSystemDebug extends JPlugin
// Run a SHOW PROFILE query.
$profile = '';
if (in_array($db->name, array('mysqli', 'mysql')))
if (in_array($db->name, array('mysqli', 'mysql', 'pdomysql')))
{
if (isset($this->sqlShowProfileEach[$id]))
{
@ -1379,7 +1379,7 @@ class PlgSystemDebug extends JPlugin
}
}
if (in_array($db->name, array('mysqli', 'mysql', 'postgresql')))
if (in_array($db->name, array('mysqli', 'mysql', 'pdomysql', 'postgresql')))
{
$log = $db->getLog();

View File

@ -0,0 +1,138 @@
<?php
/**
* @package Joomla.Test
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
/**
* Abstract test case class for MySQL database testing with the PDO based driver.
*
* @package Joomla.Test
* @since 3.4
*/
abstract class TestCaseDatabasePdomysql extends TestCaseDatabase
{
/**
* @var JDatabaseDriverPdomysql The active database driver being used for the tests.
* @since 3.4
*/
protected static $driver;
/**
* @var array The JDatabaseDriver options for the connection.
* @since 3.4
*/
private static $_options = array('driver' => 'pdomysql');
/**
* @var JDatabaseDriverPdomysql The saved database driver to be restored after these tests.
* @since 3.4
*/
private static $_stash;
/**
* This method is called before the first test of this test class is run.
*
* An example DSN would be: host=localhost;dbname=joomla_ut;user=utuser;pass=ut1234
*
* @return void
*
* @since 3.4
*/
public static function setUpBeforeClass()
{
// First let's look to see if we have a DSN defined or in the environment variables.
if (defined('JTEST_DATABASE_PDO_MYSQL_DSN') || getenv('JTEST_DATABASE_PDO_MYSQL_DSN'))
{
$dsn = defined('JTEST_DATABASE_PDO_MYSQL_DSN') ? JTEST_DATABASE_PDO_MYSQL_DSN : getenv('JTEST_DATABASE_PDO_MYSQL_DSN');
}
else
{
return;
}
// First let's trim the mysql: part off the front of the DSN if it exists.
if (strpos($dsn, 'mysql:') === 0)
{
$dsn = substr($dsn, 6);
}
// Split the DSN into its parts over semicolons.
$parts = explode(';', $dsn);
// Parse each part and populate the options array.
foreach ($parts as $part)
{
list ($k, $v) = explode('=', $part, 2);
switch ($k)
{
case 'host':
self::$_options['host'] = $v;
break;
case 'dbname':
self::$_options['database'] = $v;
break;
case 'user':
self::$_options['user'] = $v;
break;
case 'pass':
self::$_options['password'] = $v;
break;
}
}
try
{
// Attempt to instantiate the driver.
self::$driver = JDatabaseDriver::getInstance(self::$_options);
}
catch (RuntimeException $e)
{
self::$driver = null;
}
// If for some reason an exception object was returned set our database object to null.
if (self::$driver instanceof Exception)
{
self::$driver = null;
}
// Setup the factory pointer for the driver and stash the old one.
self::$_stash = JFactory::$database;
JFactory::$database = self::$driver;
}
/**
* This method is called after the last test of this test class is run.
*
* @return void
*
* @since 3.4
*/
public static function tearDownAfterClass()
{
JFactory::$database = self::$_stash;
self::$driver = null;
}
/**
* Returns the default database connection for running the tests.
*
* @return PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection
*
* @since 3.4
*/
protected function getConnection()
{
// Compile the connection DSN.
$dsn = 'mysql:host=' . self::$_options['host'] . ';dbname=' . self::$_options['database'];
// Create the PDO object from the DSN and options.
$pdo = new PDO($dsn, self::$_options['user'], self::$_options['password']);
return $this->createDefaultDBConnection($pdo, self::$_options['database']);
}
}

View File

@ -0,0 +1,820 @@
<?php
/**
* @package Joomla.UnitTest
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
/**
* Test class for JDatabaseDriverPdomysql.
*
* @package Joomla.UnitTest
* @subpackage Database
* @since 3.4
*/
class JDatabaseDriverPdomysqlTest extends TestCaseDatabasePdomysql
{
/**
* Data for the testEscape test.
*
* @return array
*
* @since 3.4
*/
public function dataTestEscape()
{
return array(
array("'%_abc123", false, '\\\'%_abc123'),
array("'%_abc123", true, '\\\'\\%\_abc123')
);
}
/**
* Data for the testTransactionRollback test.
*
* @return array
*
* @since 3.4
*/
public function dataTestTransactionRollback()
{
return array(array(null, 0), array('transactionSavepoint', 1));
}
/**
* Tests the __destruct method.
*
* @return void
*
* @since 3.4
*/
public function test__destruct()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Tests the connected method.
*
* @return void
*
* @since 3.4
*/
public function testConnected()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Tests the dropTable method.
*
* @return void
*
* @since 3.4
*/
public function testDropTable()
{
// Create #__bar table first
self::$driver->setQuery('CREATE TABLE IF NOT EXISTS `#__bar` (`id` int(10) unsigned NOT NULL);');
self::$driver->execute();
// Check return self or not.
$this->assertThat(
self::$driver->dropTable('#__bar', true),
$this->isInstanceOf('JDatabaseDriverPdomysql'),
'The table is dropped if present.'
);
// Check is table dropped.
self::$driver->setQuery("SHOW TABLES LIKE '%#__bar%'");
$exists = self::$driver->loadResult();
$this->assertNull($exists);
}
/**
* Tests the escape method.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
* @param string $expected The expected result.
*
* @return void
*
* @dataProvider dataTestEscape
* @since 3.4
*/
public function testEscape($text, $extra, $expected)
{
$this->assertThat(
self::$driver->escape($text, $extra),
$this->equalTo($expected),
'The string was not escaped properly'
);
}
/**
* Test getAffectedRows method.
*
* @return void
*
* @since 3.4
*/
public function testGetAffectedRows()
{
$query = self::$driver->getQuery(true);
$query->delete();
$query->from('#__dbtest');
self::$driver->setQuery($query);
self::$driver->execute();
$this->assertThat(
self::$driver->getAffectedRows(),
$this->equalTo(4),
__LINE__
);
}
/**
* Test getCollation method.
*
* @return void
*
* @since 3.4
*/
public function testGetCollation()
{
$this->assertThat(
self::$driver->getCollation(),
$this->equalTo('utf8_general_ci'),
'Line:' . __LINE__ . ' The getCollation method should return the collation of the database.'
);
}
/**
* Test getExporter method.
*
* @return void
*
* @since 3.4
*/
public function testGetExporter()
{
$this->assertThat(
self::$driver->getExporter(),
$this->isInstanceOf('JDatabaseExporterPdomysql'),
'Line:' . __LINE__ . ' The getExporter method should return the correct exporter.'
);
}
/**
* Test getImporter method.
*
* @return void
*
* @since 3.4
*/
public function testGetImporter()
{
$this->assertThat(
self::$driver->getImporter(),
$this->isInstanceOf('JDatabaseImporterPdomysql'),
'Line:' . __LINE__ . ' The getImporter method should return the correct importer.'
);
}
/**
* Test getNumRows method.
*
* @return void
*
* @since 3.4
*/
public function testGetNumRows()
{
$query = self::$driver->getQuery(true);
$query->select('*');
$query->from('#__dbtest');
$query->where('description = ' . self::$driver->quote('one'));
self::$driver->setQuery($query);
$res = self::$driver->execute();
$this->assertThat(
self::$driver->getNumRows($res),
$this->equalTo(2),
__LINE__
);
}
/**
* Tests the getTableCreate method.
*
* @return void
*
* @since 3.4
*/
public function testGetTableCreate()
{
$this->assertThat(
self::$driver->getTableCreate('#__dbtest'),
$this->isType('array'),
'The statement to create the table is returned in an array.'
);
}
/**
* Test getTableColumns method.
*
* @return void
*
* @since 3.4
*/
public function testGetTableColumns()
{
$tableCol = array('id' => 'int unsigned', 'title' => 'varchar', 'start_date' => 'datetime', 'description' => 'text');
$this->assertThat(
self::$driver->getTableColumns('#__dbtest'),
$this->equalTo($tableCol),
__LINE__
);
/* Not only type field */
$id = new stdClass;
$id->Default = null;
$id->Field = 'id';
$id->Type = 'int(10) unsigned';
$id->Null = 'NO';
$id->Key = 'PRI';
$id->Collation = null;
$id->Extra = 'auto_increment';
$id->Privileges = 'select,insert,update,references';
$id->Comment = '';
$title = new stdClass;
$title->Default = null;
$title->Field = 'title';
$title->Type = 'varchar(50)';
$title->Null = 'NO';
$title->Key = '';
$title->Collation = 'utf8_general_ci';
$title->Extra = '';
$title->Privileges = 'select,insert,update,references';
$title->Comment = '';
$start_date = new stdClass;
$start_date->Default = null;
$start_date->Field = 'start_date';
$start_date->Type = 'datetime';
$start_date->Null = 'NO';
$start_date->Key = '';
$start_date->Collation = null;
$start_date->Extra = '';
$start_date->Privileges = 'select,insert,update,references';
$start_date->Comment = '';
$description = new stdClass;
$description->Default = null;
$description->Field = 'description';
$description->Type = 'text';
$description->Null = 'NO';
$description->Key = '';
$description->Collation = 'utf8_general_ci';
$description->Extra = '';
$description->Privileges = 'select,insert,update,references';
$description->Comment = '';
$this->assertThat(
self::$driver->getTableColumns('#__dbtest', false),
$this->equalTo(
array(
'id' => $id,
'title' => $title,
'start_date' => $start_date,
'description' => $description
)
),
__LINE__
);
}
/**
* Tests the getTableKeys method.
*
* @return void
*
* @since 3.4
*/
public function testGetTableKeys()
{
$this->assertThat(
self::$driver->getTableKeys('#__dbtest'),
$this->isType('array'),
'The list of keys for the table is returned in an array.'
);
}
/**
* Tests the getTableList method.
*
* @return void
*
* @since 3.4
*/
public function testGetTableList()
{
$this->assertThat(
self::$driver->getTableList(),
$this->isType('array'),
'The list of tables for the database is returned in an array.'
);
}
/**
* Test getVersion method.
*
* @return void
*
* @since 3.4
*/
public function testGetVersion()
{
$this->assertThat(
strlen(self::$driver->getVersion()),
$this->greaterThan(0),
'Line:' . __LINE__ . ' The getVersion method should return something without error.'
);
}
/**
* Test insertid method.
*
* @return void
*
* @since 3.4
*/
public function testInsertid()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Test loadAssoc method.
*
* @return void
*
* @since 3.4
*/
public function testLoadAssoc()
{
$query = self::$driver->getQuery(true);
$query->select('title');
$query->from('#__dbtest');
self::$driver->setQuery($query);
$result = self::$driver->loadAssoc();
$this->assertThat(
$result,
$this->equalTo(
array(
'title' => 'Testing'
)),
__LINE__
);
}
/**
* Test loadAssocList method.
*
* @return void
*
* @since 3.4
*/
public function testLoadAssocList()
{
$query = self::$driver->getQuery(true);
$query->select('title');
$query->from('#__dbtest');
self::$driver->setQuery($query);
$result = self::$driver->loadAssocList();
$this->assertThat(
$result,
$this->equalTo(array(array('title' => 'Testing'), array('title' => 'Testing2'), array('title' => 'Testing3'), array('title' => 'Testing4'))),
__LINE__
);
}
/**
* Test loadColumn method
*
* @return void
*
* @since 3.4
*/
public function testLoadColumn()
{
$query = self::$driver->getQuery(true);
$query->select('title');
$query->from('#__dbtest');
self::$driver->setQuery($query);
$result = self::$driver->loadColumn();
$this->assertThat(
$result,
$this->equalTo(array('Testing', 'Testing2', 'Testing3', 'Testing4')),
__LINE__
);
}
/**
* Test loadNextObject method.
*
* @return void
*
* @since 3.4
*/
public function testLoadNextObject()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Test loadNextRow method.
*
* @return void
*
* @since 3.4
*/
public function testLoadNextRow()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Test loadObject method
*
* @return void
*
* @since 3.4
*/
public function testLoadObject()
{
$query = self::$driver->getQuery(true);
$query->select('*');
$query->from('#__dbtest');
$query->where('description=' . self::$driver->quote('three'));
self::$driver->setQuery($query);
$result = self::$driver->loadObject();
$objCompare = new stdClass;
$objCompare->id = 3;
$objCompare->title = 'Testing3';
$objCompare->start_date = '1980-04-18 00:00:00';
$objCompare->description = 'three';
$this->assertThat(
$result,
$this->equalTo($objCompare),
__LINE__
);
}
/**
* Test loadObjectList method
*
* @return void
*
* @since 3.4
*/
public function testLoadObjectList()
{
$query = self::$driver->getQuery(true);
$query->select('*');
$query->from('#__dbtest');
$query->order('id');
self::$driver->setQuery($query);
$result = self::$driver->loadObjectList();
$expected = array();
$objCompare = new stdClass;
$objCompare->id = 1;
$objCompare->title = 'Testing';
$objCompare->start_date = '1980-04-18 00:00:00';
$objCompare->description = 'one';
$expected[] = clone $objCompare;
$objCompare = new stdClass;
$objCompare->id = 2;
$objCompare->title = 'Testing2';
$objCompare->start_date = '1980-04-18 00:00:00';
$objCompare->description = 'one';
$expected[] = clone $objCompare;
$objCompare = new stdClass;
$objCompare->id = 3;
$objCompare->title = 'Testing3';
$objCompare->start_date = '1980-04-18 00:00:00';
$objCompare->description = 'three';
$expected[] = clone $objCompare;
$objCompare = new stdClass;
$objCompare->id = 4;
$objCompare->title = 'Testing4';
$objCompare->start_date = '1980-04-18 00:00:00';
$objCompare->description = 'four';
$expected[] = clone $objCompare;
$this->assertThat(
$result,
$this->equalTo($expected),
__LINE__
);
}
/**
* Test loadResult method
*
* @return void
*
* @since 3.4
*/
public function testLoadResult()
{
$query = self::$driver->getQuery(true);
$query->select('id');
$query->from('#__dbtest');
$query->where('title=' . self::$driver->quote('Testing2'));
self::$driver->setQuery($query);
$result = self::$driver->loadResult();
$this->assertThat(
$result,
$this->equalTo(2),
__LINE__
);
}
/**
* Test loadRow method
*
* @return void
*
* @since 3.4
*/
public function testLoadRow()
{
$query = self::$driver->getQuery(true);
$query->select('*');
$query->from('#__dbtest');
$query->where('description=' . self::$driver->quote('three'));
self::$driver->setQuery($query);
$result = self::$driver->loadRow();
$expected = array(3, 'Testing3', '1980-04-18 00:00:00', 'three');
$this->assertThat(
$result,
$this->equalTo($expected),
__LINE__
);
}
/**
* Test loadRowList method
*
* @return void
*
* @since 3.4
*/
public function testLoadRowList()
{
$query = self::$driver->getQuery(true);
$query->select('*');
$query->from('#__dbtest');
$query->where('description=' . self::$driver->quote('one'));
self::$driver->setQuery($query);
$result = self::$driver->loadRowList();
$expected = array(array(1, 'Testing', '1980-04-18 00:00:00', 'one'), array(2, 'Testing2', '1980-04-18 00:00:00', 'one'));
$this->assertThat(
$result,
$this->equalTo($expected),
__LINE__
);
}
/**
* Test the JDatabaseDriverPdomysql::execute() method
*
* @return void
*
* @since 3.4
*/
public function testExecute()
{
self::$driver->setQuery(
"REPLACE INTO `jos_dbtest` SET `id` = 5, `title` = 'testTitle', `start_date` = '2014-08-17 00:00:00', `description` = 'testDescription'"
);
$this->assertThat(
(bool) self::$driver->execute(),
$this->isTrue(),
__LINE__
);
$this->assertThat(
self::$driver->insertid(),
$this->equalTo(5),
__LINE__
);
}
/**
* Tests the renameTable method.
*
* @return void
*
* @since 3.4
*/
public function testRenameTable()
{
$newTableName = 'bak_jos_dbtest';
self::$driver->renameTable('jos_dbtest', $newTableName);
// Check name change
$tableList = self::$driver->getTableList();
$this->assertThat(
in_array($newTableName, $tableList),
$this->isTrue(),
__LINE__
);
// Restore initial state
self::$driver->renameTable($newTableName, 'jos_dbtest');
}
/**
* Test select method.
*
* @return void
*
* @since 3.4
*/
public function testSelect()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Test setUTF method.
*
* @return void
*
* @since 3.4
*/
public function testSetUTF()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
/**
* Tests the transactionCommit method.
*
* @return void
*
* @since 3.4
*/
public function testTransactionCommit()
{
self::$driver->transactionStart();
$queryIns = self::$driver->getQuery(true);
$queryIns->insert('#__dbtest')
->columns('id, title, start_date, description')
->values("6, 'testTitle', '1970-01-01', 'testDescription'");
self::$driver->setQuery($queryIns)->execute();
self::$driver->transactionCommit();
/* Check if value is present */
$queryCheck = self::$driver->getQuery(true);
$queryCheck->select('*')
->from('#__dbtest')
->where('id = 6');
self::$driver->setQuery($queryCheck);
$result = self::$driver->loadRow();
$expected = array('6', 'testTitle', '1970-01-01 00:00:00', 'testDescription');
$this->assertThat(
$result,
$this->equalTo($expected),
__LINE__
);
}
/**
* Tests the transactionRollback method, with and without savepoint.
*
* @param string $toSavepoint Savepoint name to rollback transaction to
* @param int $tupleCount Number of tuple found after insertion and rollback
*
* @return void
*
* @since 3.4
* @dataProvider dataTestTransactionRollback
*/
public function testTransactionRollback($toSavepoint, $tupleCount)
{
self::$driver->transactionStart();
/* Try to insert this tuple, inserted only when savepoint != null */
$queryIns = self::$driver->getQuery(true);
$queryIns->insert('#__dbtest')
->columns('id, title, start_date, description')
->values("7, 'testRollback', '1970-01-01', 'testRollbackSp'");
self::$driver->setQuery($queryIns)->execute();
/* Create savepoint only if is passed by data provider */
if (!is_null($toSavepoint))
{
self::$driver->transactionStart((boolean) $toSavepoint);
}
/* Try to insert this tuple, always rolled back */
$queryIns = self::$driver->getQuery(true);
$queryIns->insert('#__dbtest')
->columns('id, title, start_date, description')
->values("8, 'testRollback', '1972-01-01', 'testRollbackSp'");
self::$driver->setQuery($queryIns)->execute();
self::$driver->transactionRollback((boolean) $toSavepoint);
/* Release savepoint and commit only if a savepoint exists */
if (!is_null($toSavepoint))
{
self::$driver->transactionCommit();
}
/* Find how many rows have description='testRollbackSp' :
* - 0 if a savepoint doesn't exist
* - 1 if a savepoint exists
*/
$queryCheck = self::$driver->getQuery(true);
$queryCheck->select('*')
->from('#__dbtest')
->where("description = 'testRollbackSp'");
self::$driver->setQuery($queryCheck);
$result = self::$driver->loadRowList();
$this->assertThat(
count($result),
$this->equalTo($tupleCount),
__LINE__
);
}
/**
* Test isSupported method.
*
* @return void
*
* @since 3.4
*/
public function testIsSupported()
{
$this->assertThat(
JDatabaseDriverPdomysql::isSupported(),
$this->isTrue(),
__LINE__
);
}
/**
* Test updateObject method.
*
* @return void
*
* @since 3.4
*/
public function testUpdateObject()
{
$this->markTestIncomplete('This test has not been implemented yet.');
}
}

View File

@ -0,0 +1,593 @@
<?php
/**
* @package Joomla.UnitTest
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
/**
* Tests the JDatabaseExporterPdomysql class.
*
* @package Joomla.UnitTest
* @subpackage Database
* @since 3.4
*/
class JDatabaseExporterPdomysqlTest extends PHPUnit_Framework_TestCase
{
/**
* @var object The mocked database object for use by test methods.
* @since 3.4
*/
protected $dbo = null;
/**
* Sets up the testing conditions
*
* @return void
*
* @since 3.4
*/
public function setup()
{
parent::setUp();
// Set up the database object mock.
$this->dbo = $this->getMock(
'JDatabaseDriverPdomysql',
array(
'getErrorNum',
'getPrefix',
'getTableColumns',
'getTableKeys',
'quoteName',
'loadObjectList',
'setQuery',
),
array(),
'',
false
);
$this->dbo->expects(
$this->any()
)
->method('getPrefix')
->will(
$this->returnValue(
'jos_'
)
);
$this->dbo->expects(
$this->any()
)
->method('getTableColumns')
->will(
$this->returnValue(
array(
(object) array(
'Field' => 'id',
'Type' => 'int(11) unsigned',
'Collation' => null,
'Null' => 'NO',
'Key' => 'PRI',
'Default' => '',
'Extra' => 'auto_increment',
'Privileges' => 'select,insert,update,references',
'Comment' => '',
),
(object) array(
'Field' => 'title',
'Type' => 'varchar(255)',
'Collation' => 'utf8_general_ci',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
'Privileges' => 'select,insert,update,references',
'Comment' => '',
),
)
)
);
$this->dbo->expects(
$this->any()
)
->method('getTableKeys')
->will(
$this->returnValue(
array(
(object) array(
'Table' => 'jos_test',
'Non_unique' => '0',
'Key_name' => 'PRIMARY',
'Seq_in_index' => '1',
'Column_name' => 'id',
'Collation' => 'A',
'Cardinality' => '2695',
'Sub_part' => '',
'Packed' => '',
'Null' => '',
'Index_type' => 'BTREE',
'Comment' => '',
)
)
)
);
$this->dbo->expects(
$this->any()
)
->method('quoteName')
->will(
$this->returnCallback(
array($this, 'callbackQuoteName')
)
);
$this->dbo->expects(
$this->any()
)
->method('setQuery')
->will(
$this->returnCallback(
array($this, 'callbackSetQuery')
)
);
$this->dbo->expects(
$this->any()
)
->method('loadObjectList')
->will(
$this->returnCallback(
array($this, 'callbackLoadObjectList')
)
);
}
/**
* Callback for the dbo loadObjectList method.
*
* @return array An array of results based on the setting of the last query.
*
* @since 3.4
*/
public function callbackLoadObjectList()
{
return array();
}
/**
* Callback for the dbo quoteName method.
*
* @param string $value The value to be quoted.
*
* @return string The value passed wrapped in MySQL quotes.
*
* @since 3.4
*/
public function callbackQuoteName($value)
{
return "`$value`";
}
/**
* Callback for the dbo setQuery method.
*
* @param string $query The query.
*
* @return void
*
* @since 3.4
*/
public function callbackSetQuery($query)
{
$this->lastQuery = $query;
}
/**
* Test the magic __toString method.
*
* @return void
*
* @since 3.4
*/
public function test__toString()
{
$instance = new JDatabaseExporterPdomysql;
// Set up the export settings.
$instance
->setDbo($this->dbo)
->from('#__test')
->withStructure(true);
$expecting = '<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="">
<table_structure name="#__test">
<field Field="id" Type="int(11) unsigned" Null="NO" Key="PRI" Default="" Extra="auto_increment" />
<field Field="title" Type="varchar(255)" Null="NO" Key="" Default="" Extra="" />
<key Table="#__test" Non_unique="0" Key_name="PRIMARY" Seq_in_index="1" Column_name="id" Collation="A" Null="" Index_type="BTREE" Comment="" />
</table_structure>
</database>
</mysqldump>';
$this->assertThat(
preg_replace('/\v/', '', (string) $instance),
$this->equalTo(
preg_replace('/\v/', '', $expecting)
),
'__toString has not returned the expected result.'
);
}
/**
* Tests the asXml method.
*
* @return void
*
* @since 3.4
*/
public function testAsXml()
{
$instance = new JDatabaseExporterPdomysql;
$result = $instance->asXml();
$this->assertThat(
$result,
$this->identicalTo($instance),
'asXml must return an object to support chaining.'
);
$this->assertThat(
TestReflection::getValue($instance, 'asFormat'),
$this->equalTo('xml'),
'The asXml method should set the protected asFormat property to "xml".'
);
}
/**
* Test the buildXML method.
*
* @return void
*
* @since 3.4
*/
public function testBuildXml()
{
$instance = new JDatabaseExporterPdomysql;
// Set up the export settings.
$instance
->setDbo($this->dbo)
->from('#__test')
->withStructure(true);
$expecting = '<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="">
<table_structure name="#__test">
<field Field="id" Type="int(11) unsigned" Null="NO" Key="PRI" Default="" Extra="auto_increment" />
<field Field="title" Type="varchar(255)" Null="NO" Key="" Default="" Extra="" />
<key Table="#__test" Non_unique="0" Key_name="PRIMARY" Seq_in_index="1" Column_name="id" Collation="A" Null="" Index_type="BTREE" Comment="" />
</table_structure>
</database>
</mysqldump>';
// Replace used to prevent platform conflicts
$this->assertThat(
preg_replace('/\v/', '', TestReflection::invoke($instance, 'buildXml')),
$this->equalTo(
preg_replace('/\v/', '', $expecting)
),
'buildXml has not returned the expected result.'
);
}
/**
* Tests the buildXmlStructure method.
*
* @return void
*
* @since 3.4
*/
public function testBuildXmlStructure()
{
$instance = new JDatabaseExporterPdomysql;
// Set up the export settings.
$instance
->setDbo($this->dbo)
->from('#__test')
->withStructure(true);
$this->assertThat(
TestReflection::invoke($instance, 'buildXmlStructure'),
$this->equalTo(
array(
' <table_structure name="#__test">',
' <field Field="id" Type="int(11) unsigned" Null="NO" Key="PRI" Default="" Extra="auto_increment" />',
' <field Field="title" Type="varchar(255)" Null="NO" Key="" Default="" Extra="" />',
' <key Table="#__test" Non_unique="0" Key_name="PRIMARY" Seq_in_index="1" Column_name="id" Collation="A" ' .
'Null="" Index_type="BTREE" Comment="" />',
' </table_structure>'
)
),
'buildXmlStructure has not returned the expected result.'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithNoDbo()
{
$instance = new JDatabaseExporterPdomysql;
try
{
$instance->check();
}
catch (Exception $e)
{
// Exception expected.
return;
}
$this->fail(
'Check method should throw exception if DBO not set'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithNoTables()
{
$instance = new JDatabaseExporterPdomysql;
$instance->setDbo($this->dbo);
try
{
$instance->check();
}
catch (Exception $e)
{
// Exception expected.
return;
}
$this->fail(
'Check method should throw exception if DBO not set'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithGoodInput()
{
$instance = new JDatabaseExporterPdomysql;
$instance->setDbo($this->dbo);
$instance->from('foobar');
try
{
$result = $instance->check();
$this->assertThat(
$result,
$this->identicalTo($instance),
'check must return an object to support chaining.'
);
}
catch (Exception $e)
{
$this->fail(
'Check method should not throw exception with good setup: ' . $e->getMessage()
);
}
}
/**
* Tests the from method with bad input.
*
* @return void
*
* @since 3.4
*/
public function testFromWithBadInput()
{
$instance = new JDatabaseExporterPdomysql;
try
{
$instance->from(new stdClass);
}
catch (Exception $e)
{
// Exception expected.
return;
}
$this->fail(
'From method should thrown an exception if argument is not a string or array.'
);
}
/**
* Tests the from method with expected good inputs.
*
* @return void
*
* @since 3.4
*/
public function testFromWithGoodInput()
{
$instance = new JDatabaseExporterPdomysql;
try
{
$result = $instance->from('jos_foobar');
$this->assertThat(
$result,
$this->identicalTo($instance),
'from must return an object to support chaining.'
);
$this->assertThat(
TestReflection::getValue($instance, 'from'),
$this->equalTo(array('jos_foobar')),
'The from method should convert a string input to an array.'
);
}
catch (Exception $e)
{
$this->fail(
'From method should not throw exception with good input: ' . $e->getMessage()
);
}
}
/**
* Tests the method getGenericTableName method.
*
* @return void
*
* @since 3.4
*/
public function testGetGenericTableName()
{
$instance = new JDatabaseExporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getGenericTableName', 'jos_test'),
$this->equalTo('#__test'),
'The testGetGenericTableName should replace the database prefix with #__.'
);
}
/**
* Tests the setDbo method with the wrong type of class.
*
* @return void
*
* @since 3.4
*/
public function testSetDboWithBadInput()
{
$instance = new JDatabaseExporterPdomysql;
try
{
$instance->setDbo(new stdClass);
}
catch (PHPUnit_Framework_Error $e)
{
// Expecting the error, so just ignore it.
return;
}
$this->fail(
'setDbo requires a JDatabaseDriverPdomysql object and should throw an exception.'
);
}
/**
* Tests the setDbo method with the wrong type of class.
*
* @return void
*
* @since 3.4
*/
public function testSetDboWithGoodInput()
{
$instance = new JDatabaseExporterPdomysql;
try
{
$result = $instance->setDbo($this->dbo);
$this->assertThat(
$result,
$this->identicalTo($instance),
'setDbo must return an object to support chaining.'
);
}
catch (PHPUnit_Framework_Error $e)
{
// Unknown error has occurred.
$this->fail(
$e->getMessage()
);
}
}
/**
* Tests the withStructure method.
*
* @return void
*
* @since 3.4
*/
public function testWithStructure()
{
$instance = new JDatabaseExporterPdomysql;
$result = $instance->withStructure();
$this->assertThat(
$result,
$this->identicalTo($instance),
'withStructure must return an object to support chaining.'
);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isTrue(),
'The default use of withStructure should result in true.'
);
$instance->withStructure(true);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isTrue(),
'The explicit use of withStructure with true should result in true.'
);
$instance->withStructure(false);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isFalse(),
'The explicit use of withStructure with false should result in false.'
);
}
}

View File

@ -0,0 +1,871 @@
<?php
/**
* @package Joomla.UnitTest
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
/**
* Tests the JDatabaseImporterPdomysql class.
*
* @package Joomla.UnitTest
* @subpackage Database
* @since 3.4
*/
class JDatabaseImporterPdomysqlTest extends PHPUnit_Framework_TestCase
{
/**
* @var object The mocked database object for use by test methods.
* @since 3.4
*/
protected $dbo = null;
/**
* @var string The last query sent to the dbo setQuery method.
* @since 3.4
*/
protected $lastQuery = '';
/**
* @var array Selected sample data for tests.
* @since 3.4
*/
protected $sample = array(
'xml-id-field' =>
'<field Field="id" Type="int(11) unsigned" Null="NO" Key="PRI" Default="" Extra="auto_increment" />',
'xml-title-field' =>
'<field Field="title" Type="varchar(50)" Null="NO" Key="" Default="" Extra="" />',
'xml-body-field' =>
'<field Field="body" Type="mediumtext" Null="NO" Key="" Default="" Extra="" />',
'xml-primary-key' =>
'<key Table="#__test" Non_unique="0" Key_name="PRIMARY" Seq_in_index="1" Column_name="id" Collation="A" Null="" Index_type="BTREE" Comment="" />',
);
/**
* Sets up the testing conditions
*
* @return void
*
* @since 3.4
*/
public function setup()
{
parent::setUp();
// Set up the database object mock.
$this->dbo = $this->getMock(
'JDatabaseDriverPdomysql',
array(
'getErrorNum',
'getPrefix',
'getTableColumns',
'getTableKeys',
'quoteName',
'loadObjectList',
'quote',
'setQuery',
),
array(),
'',
false
);
$this->dbo->expects(
$this->any()
)
->method('getPrefix')
->will(
$this->returnValue(
'jos_'
)
);
$this->dbo->expects(
$this->any()
)
->method('getTableColumns')
->will(
$this->returnValue(
array(
'id' => (object) array(
'Field' => 'id',
'Type' => 'int(11) unsigned',
'Collation' => null,
'Null' => 'NO',
'Key' => 'PRI',
'Default' => '',
'Extra' => 'auto_increment',
'Privileges' => 'select,insert,update,references',
'Comment' => '',
),
'title' => (object) array(
'Field' => 'title',
'Type' => 'varchar(255)',
'Collation' => 'utf8_general_ci',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
'Privileges' => 'select,insert,update,references',
'Comment' => '',
),
)
)
);
$this->dbo->expects(
$this->any()
)
->method('getTableKeys')
->will(
$this->returnValue(
array(
(object) array(
'Table' => 'jos_test',
'Non_unique' => '0',
'Key_name' => 'PRIMARY',
'Seq_in_index' => '1',
'Column_name' => 'id',
'Collation' => 'A',
'Cardinality' => '2695',
'Sub_part' => '',
'Packed' => '',
'Null' => '',
'Index_type' => 'BTREE',
'Comment' => '',
)
)
)
);
$this->dbo->expects(
$this->any()
)
->method('quoteName')
->will(
$this->returnCallback(
array($this, 'callbackQuoteName')
)
);
$this->dbo->expects(
$this->any()
)
->method('quote')
->will(
$this->returnCallback(
array($this, 'callbackQuote')
)
);
$this->dbo->expects(
$this->any()
)
->method('setQuery')
->will(
$this->returnCallback(
array($this, 'callbackSetQuery')
)
);
$this->dbo->expects(
$this->any()
)
->method('loadObjectList')
->will(
$this->returnCallback(
array($this, 'callbackLoadObjectList')
)
);
}
/**
* Callback for the dbo loadObjectList method.
*
* @return array An array of results based on the setting of the last query.
*
* @since 3.4
*/
public function callbackLoadObjectList()
{
return array();
}
/**
* Callback for the dbo quote method.
*
* @param string $value The value to be quoted.
*
* @return string The value passed wrapped in MySQL quotes.
*
* @since 3.4
*/
public function callbackQuote($value)
{
return "'$value'";
}
/**
* Callback for the dbo quoteName method.
*
* @param string $value The value to be quoted.
*
* @return string The value passed wrapped in MySQL quotes.
*
* @since 3.4
*/
public function callbackQuoteName($value)
{
return "`$value`";
}
/**
* Callback for the dbo setQuery method.
*
* @param string $query The query.
*
* @return void
*
* @since 3.4
*/
public function callbackSetQuery($query)
{
$this->lastQuery = $query;
}
/**
* Data for the testGetAlterTableSQL test.
*
* @return array Each array element must be an array with 3 elements: SimpleXMLElement field, expected result, error message.
*
* @since 3.4
*/
public function dataGetAlterTableSQL()
{
$f1 = '<field Field="id" Type="int(11) unsigned" Null="NO" Key="PRI" Default="" Extra="auto_increment" />';
$f2 = '<field Field="title" Type="varchar(255)" Null="NO" Key="" Default="" Extra="" />';
$f3 = '<field Field="alias" Type="varchar(255)" Null="NO" Key="" Default="" Extra="" />';
$k1 = '<key Table="#__test" Non_unique="0" Key_name="PRIMARY" Seq_in_index="1"' .
' Column_name="id" Collation="A" Null="" Index_type="BTREE" Comment="" />';
$k2 = '<key Table="#__test" Non_unique="0" Key_name="idx_title" Seq_in_index="1"' .
' Column_name="title" Collation="A" Null="" Index_type="BTREE" Comment="" />';
return array(
array(
new SimpleXmlElement('<table_structure name="#__test">' . $f1 . $f2 . $k1 . '</table_structure>'),
array(),
'getAlterTableSQL should not change anything.'
),
array(
new SimpleXmlElement('<table_structure name="#__test">' . $f1 . $f2 . $f3 . $k1 . '</table_structure>'),
array(
"ALTER TABLE `jos_test` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''",
),
'getAlterTableSQL should add the new alias column.'
),
array(
new SimpleXmlElement('<table_structure name="#__test">' . $f1 . $f2 . $k1 . $k2 . '</table_structure>'),
array(
"ALTER TABLE `jos_test` ADD UNIQUE KEY `idx_title` (`title`)",
),
'getAlterTableSQL should add the new key.'
),
array(
new SimpleXmlElement('<table_structure name="#__test">' . $f1 . $k1 . '</table_structure>'),
array(
"ALTER TABLE `jos_test` DROP COLUMN `title`",
),
'getAlterTableSQL should remove the title column.'
),
array(
new SimpleXmlElement('<table_structure name="#__test">' . $f1 . $f2 . '</table_structure>'),
array(
"ALTER TABLE `jos_test` DROP PRIMARY KEY",
),
'getAlterTableSQL should drop the old primary key.'
),
);
}
/**
* Data for the testGetColumnSQL test.
*
* @return array Each array element must be an array with 3 elements: SimpleXMLElement field, expected result, error message.
*
* @since 3.4
*/
public function dataGetColumnSQL()
{
return array(
array(
new SimpleXmlElement(
$this->sample['xml-id-field']
),
"`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT",
'Typical primary key field',
),
array(
new SimpleXmlElement(
$this->sample['xml-title-field']
),
"`title` varchar(50) NOT NULL DEFAULT ''",
'Typical text field',
),
array(
new SimpleXmlElement(
$this->sample['xml-body-field']
),
"`body` mediumtext NOT NULL",
'Typical blob field',
),
);
}
/**
* Data for the testGetColumnSQL test.
*
* @return array Each array element must be an array with 3 elements: SimpleXMLElement field, expected result, error message.
*
* @since 3.4
*/
public function dataGetKeySQL()
{
return array(
array(
// Keys come in arrays.
array(
new SimpleXmlElement(
$this->sample['xml-primary-key']
),
),
"primary key (`id`)",
'Typical primary key index',
),
);
}
/**
* Tests the asXml method.
*
* @return void
*
* @since 3.4
*/
public function testAsXml()
{
$instance = new JDatabaseImporterPdomysql;
$result = $instance->asXml();
$this->assertThat(
$result,
$this->identicalTo($instance),
'asXml must return an object to support chaining.'
);
$this->assertThat(
TestReflection::getValue($instance, 'asFormat'),
$this->equalTo('xml'),
'The asXml method should set the protected asFormat property to "xml".'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithNoDbo()
{
$instance = new JDatabaseImporterPdomysql;
try
{
$instance->check();
}
catch (Exception $e)
{
// Exception expected.
return;
}
$this->fail(
'Check method should throw exception if DBO not set'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithNoFrom()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
try
{
$instance->check();
}
catch (Exception $e)
{
// Exception expected.
return;
}
$this->fail(
'Check method should throw exception if DBO not set'
);
}
/**
* Tests the check method.
*
* @return void
*
* @since 3.4
*/
public function testCheckWithGoodInput()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$instance->from('foobar');
try
{
$result = $instance->check();
$this->assertThat(
$result,
$this->identicalTo($instance),
'check must return an object to support chaining.'
);
}
catch (Exception $e)
{
$this->fail(
'Check method should not throw exception with good setup: ' . $e->getMessage()
);
}
}
/**
* Tests the from method with expected good inputs.
*
* @return void
*
* @since 3.4
*/
public function testFromWithGoodInput()
{
$instance = new JDatabaseImporterPdomysql;
try
{
$result = $instance->from('foobar');
$this->assertThat(
$result,
$this->identicalTo($instance),
'from must return an object to support chaining.'
);
$this->assertThat(
TestReflection::getValue($instance, 'from'),
$this->equalTo('foobar'),
'The from method did not store the value as expected.'
);
}
catch (Exception $e)
{
$this->fail(
'From method should not throw exception with good input: ' . $e->getMessage()
);
}
}
/**
* Tests the getAddColumnSQL method.
*
* Note that combinations of fields is tested in testGetColumnSQL.
*
* @return void
*
* @since 3.4
*/
public function testGetAddColumnSQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getAddColumnSql', 'jos_test', new SimpleXmlElement($this->sample['xml-title-field'])),
$this->equalTo(
"ALTER TABLE `jos_test` ADD COLUMN `title` varchar(50) NOT NULL DEFAULT ''"
),
'testGetAddColumnSQL did not yield the expected result.'
);
}
/**
* Tests the getAddKeySQL method.
*
* Note that combinations of keys is tested in testGetKeySQL.
*
* @return void
*
* @since 3.4
*/
public function testGetAddKeySQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getAddKeySQL', 'jos_test', array(new SimpleXmlElement($this->sample['xml-primary-key']))),
$this->equalTo(
"ALTER TABLE `jos_test` ADD PRIMARY KEY (`id`)"
),
'testGetAddKeySQL did not yield the expected result.'
);
}
/**
* Tests the getAlterTableSQL method.
*
* @param string $structure @todo
* @param string $expected @todo
* @param string $message @todo
*
* @return void
*
* @since 3.4
*
* @dataProvider dataGetAlterTableSQL
*/
public function testGetAlterTableSQL($structure, $expected, $message)
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getAlterTableSQL', $structure),
$this->equalTo(
$expected
),
$message
);
}
/**
* Tests the getChangeColumnSQL method.
*
* Note that combinations of fields is tested in testGetColumnSQL.
*
* @return void
*
* @since 3.4
*/
public function testGetChangeColumnSQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getChangeColumnSQL', 'jos_test', new SimpleXmlElement($this->sample['xml-title-field'])),
$this->equalTo(
"ALTER TABLE `jos_test` CHANGE COLUMN `title` `title` varchar(50) NOT NULL DEFAULT ''"
),
'getChangeColumnSQL did not yield the expected result.'
);
}
/**
* Tests the getColumnSQL method.
*
* @param string $field @todo
* @param string $expected The expected result from the getColumnSQL method.
* @param string $message The error message to display if the result does not match the expected value.
*
* @internal param \SimpleXmlElement $xml The database field as an object.
* @return void
*
* @since 3.4
*
* @dataProvider dataGetColumnSQL
*/
public function testGetColumnSQL($field, $expected, $message)
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
strtolower(TestReflection::invoke($instance, 'getColumnSQL', $field)),
$this->equalTo(strtolower($expected)),
$message
);
}
/**
* Tests the getDropColumnSQL method.
*
* @return void
*
* @since 3.4
*/
public function testGetDropColumnSQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getDropColumnSQL', 'jos_test', 'title'),
$this->equalTo(
"ALTER TABLE `jos_test` DROP COLUMN `title`"
),
'getDropColumnSQL did not yield the expected result.'
);
}
/**
* Tests the getDropKeySQL method.
*
* @return void
*
* @since 3.4
*/
public function testGetDropKeySQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getDropKeySQL', 'jos_test', 'idx_title'),
$this->equalTo(
"ALTER TABLE `jos_test` DROP KEY `idx_title`"
),
'getDropKeySQL did not yield the expected result.'
);
}
/**
* Tests the getDropPrimaryKeySQL method.
*
* @return void
*
* @since 3.4
*/
public function testGetDropPrimaryKeySQL()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getDropPrimaryKeySQL', 'jos_test'),
$this->equalTo(
"ALTER TABLE `jos_test` DROP PRIMARY KEY"
),
'getDropPrimaryKeySQL did not yield the expected result.'
);
}
/**
* Tests the getKeyLookup method.
*
* @return void
*
* @since 3.4
*/
public function testGetKeyLookup()
{
$instance = new JDatabaseImporterPdomysql;
$o1 = (object) array('Key_name' => 'id', 'foo' => 'bar1');
$o2 = (object) array('Key_name' => 'id', 'foo' => 'bar2');
$o3 = (object) array('Key_name' => 'title', 'foo' => 'bar3');
$this->assertThat(
TestReflection::invoke($instance, 'getKeyLookup', array($o1, $o2, $o3)),
$this->equalTo(
array(
'id' => array($o1, $o2),
'title' => array($o3)
)
),
'getKeyLookup, using array input, did not yield the expected result.'
);
$o1 = new SimpleXmlElement('<key Key_name="id" foo="bar1" />');
$o2 = new SimpleXmlElement('<key Key_name="id" foo="bar2" />');
$o3 = new SimpleXmlElement('<key Key_name="title" foo="bar3" />');
$this->assertThat(
TestReflection::invoke($instance, 'getKeyLookup', array($o1, $o2, $o3)),
$this->equalTo(
array(
'id' => array($o1, $o2),
'title' => array($o3)
)
),
'getKeyLookup, using SimpleXmlElement input, did not yield the expected result.'
);
}
/**
* Tests the getKeySQL method.
*
* @param string $field @todo
* @param string $expected The expected result from the getKeySQL method.
* @param string $message The error message to display if the result does not match the expected value.
*
* @internal param \SimpleXmlElement $xml The database key as an object.
* @return void
*
* @since 3.4
*
* @dataProvider dataGetKeySQL
*/
public function testGetKeySQL($field, $expected, $message)
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
strtolower(TestReflection::invoke($instance, 'getKeySQL', $field)),
$this->equalTo(strtolower($expected)),
$message
);
}
/**
* Tests the getRealTableName method with the wrong type of class.
*
* @return void
*
* @since 3.4
*/
public function testGetRealTableName()
{
$instance = new JDatabaseImporterPdomysql;
$instance->setDbo($this->dbo);
$this->assertThat(
TestReflection::invoke($instance, 'getRealTableName', '#__test'),
$this->equalTo('jos_test'),
'getRealTableName should return the name of the table with #__ converted to the database prefix.'
);
}
/**
* Tests the setDbo method with the wrong type of class.
*
* @return void
*
* @since 3.4
*/
public function testSetDboWithBadInput()
{
$instance = new JDatabaseImporterPdomysql;
try
{
$instance->setDbo(new stdClass);
}
catch (PHPUnit_Framework_Error $e)
{
// Expecting the error, so just ignore it.
return;
}
$this->fail(
'setDbo requires a JDatabaseDriverPdomysql object and should throw an exception.'
);
}
/**
* Tests the setDbo method with the wrong type of class.
*
* @return void
*
* @since 3.4
*/
public function testSetDboWithGoodInput()
{
$instance = new JDatabaseImporterPdomysql;
try
{
$result = $instance->setDbo($this->dbo);
$this->assertThat(
$result,
$this->identicalTo($instance),
'setDbo must return an object to support chaining.'
);
}
catch (PHPUnit_Framework_Error $e)
{
// Unknown error has occurred.
$this->fail(
$e->getMessage()
);
}
}
/**
* Tests the withStructure method.
*
* @return void
*
* @since 3.4
*/
public function testWithStructure()
{
$instance = new JDatabaseImporterPdomysql;
$result = $instance->withStructure();
$this->assertThat(
$result,
$this->identicalTo($instance),
'withStructure must return an object to support chaining.'
);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isTrue(),
'The default use of withStructure should result in true.'
);
$instance->withStructure(true);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isTrue(),
'The explicit use of withStructure with true should result in true.'
);
$instance->withStructure(false);
$options = TestReflection::getValue($instance, 'options');
$this->assertThat(
$options->withStructure,
$this->isFalse(),
'The explicit use of withStructure with false should result in false.'
);
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
* @package Joomla.UnitTest
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
/**
* Test class for JDatabaseIteratorPdomysql.
*
* @package Joomla.UnitTest
* @subpackage Database
* @since 3.4
*/
class JDatabaseIteratorPdomysqlTest extends TestCaseDatabasePdomysql
{
/**
* Data provider for the testForEach method
*
* @return array
*
* @since 3.4
*/
public function casesForEachData()
{
return array(
// Testing 'stdClass' type without specific index, offset or limit
array(
'title',
'#__dbtest',
null,
'stdClass',
0,
0,
array(
(object) array('title' => 'Testing'),
(object) array('title' => 'Testing2'),
(object) array('title' => 'Testing3'),
(object) array('title' => 'Testing4')
),
null
),
// Testing 'stdClass' type, limit=2 without specific index or offset
array(
'title',
'#__dbtest',
null,
'stdClass',
2,
0,
array(
(object) array('title' => 'Testing'),
(object) array('title' => 'Testing2')
),
null
),
// Testing 'stdClass' type, offset=2 without specific index or limit
array(
'title',
'#__dbtest',
null,
'stdClass',
20,
2,
array(
(object) array('title' => 'Testing3'),
(object) array('title' => 'Testing4')
),
null
),
// Testing 'stdClass' type, index='title' without specific offset or limit
array(
'title, id',
'#__dbtest',
'title',
'stdClass',
0,
0,
array(
'Testing' => (object) array('title' => 'Testing', 'id' => '1'),
'Testing2' => (object) array('title' => 'Testing2', 'id' => '2'),
'Testing3' => (object) array('title' => 'Testing3', 'id' => '3'),
'Testing4' => (object) array('title' => 'Testing4', 'id' => '4')
),
null,
),
// Testing 'UnexistingClass' type, index='title' without specific offset or limit
array(
'title',
'#__dbtest',
'title',
'UnexistingClass',
0,
0,
array(),
'InvalidArgumentException',
),
);
}
/**
* Test foreach control
*
* @param string $select Fields to select
* @param string $from Table to search for
* @param string $column The column to use as a key.
* @param string $class The class on which to bind the result rows.
* @param integer $limit The result set record limit.
* @param integer $offset The result set record offset.
* @param array $expected Array of expected results
* @param mixed $exception Exception thrown
*
* @return void
*
* @dataProvider casesForEachData
*
* @since 3.4
*/
public function testForEach($select, $from, $column, $class, $limit, $offset, $expected, $exception)
{
if ($exception)
{
$this->setExpectedException($exception);
}
self::$driver->setQuery(self::$driver->getQuery(true)->select($select)->from($from), $offset, $limit);
$iterator = self::$driver->getIterator($column, $class);
// Run the Iterator pattern
$this->assertThat(
iterator_to_array($iterator),
$this->equalTo($expected),
__LINE__
);
}
/**
* Test count
*
* @return void
*
* @since 3.4
*/
public function testCount()
{
self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest'));
$this->assertThat(
count(self::$driver->getIterator()),
$this->equalTo(4),
__LINE__
);
self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest'), 0, 2);
$this->assertThat(
count(self::$driver->getIterator()),
$this->equalTo(2),
__LINE__
);
self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest'), 3, 2);
$this->assertThat(
count(self::$driver->getIterator()),
$this->equalTo(1),
__LINE__
);
}
}

View File

@ -3,6 +3,7 @@
<php>
<const name="JTEST_DATABASE_MYSQL_DSN" value="host=localhost;dbname=joomla_ut;user=root;pass=" />
<const name="JTEST_DATABASE_MYSQLI_DSN" value="host=localhost;dbname=joomla_ut;user=root;pass=" />
<const name="JTEST_DATABASE_PDO_MYSQL_DSN" value="host=localhost;dbname=joomla_ut;user=root;pass=" />
<const name="JTEST_DATABASE_POSTGRESQL_DSN" value="host=localhost;port=5432;dbname=joomla_ut;user=postgres;pass=" />
</php>