Commit 8ea8b35a authored by gdd's avatar gdd
Browse files

Merge remote-tracking branch 'core/8.x' into 8.x

parents 26394bec bdb71c6f
......@@ -174,7 +174,7 @@ Contextual module
Dashboard module
- ?
Database logging module
Database Logging module
- Khalid Baheyeldin 'kbahey' <http://drupal.org/user/4063>
Field module
......
......@@ -351,8 +351,6 @@ function ajax_get_form() {
/**
* Page callback: Handles Ajax requests for the #ajax Form API property.
*
* Path: system/ajax
*
* This rebuilds the form from cache and invokes the defined #ajax['callback']
* to return an Ajax command structure for JavaScript. In case no 'callback' has
* been defined, nothing will happen.
......@@ -388,11 +386,6 @@ function ajax_form_callback() {
/**
* Theme callback: Returns the correct theme for an Ajax request.
*
* Paths:
* - system/ajax
* - file/ajax
* - file/progress
*
* Many different pages can invoke an Ajax request to system/ajax or another
* generic Ajax path. It is almost always desired for an Ajax response to be
* rendered using the same theme as the base page, because most themes are built
......
<?php
use Drupal\Core\Database\Database;
use Symfony\Component\ClassLoader\UniversalClassLoader;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
......
<?php
use Drupal\Core\Database\Database;
/**
* @file
* Common functions that many Drupal modules will need to reference.
......
This diff is collapsed.
This diff is collapsed.
<?php
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Install\TaskException;
/**
* @file
* API functions for installing Drupal.
......@@ -223,6 +226,27 @@ function install_begin_request(&$install_state) {
// Allow command line scripts to override server variables used by Drupal.
require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
// Ensure that the class loader is available so that we can leverage classes
// as part of the install routine.
$loader = drupal_classloader();
// Register explicit vendor namespaces.
$loader->registerNamespaces(array(
// All Symfony-borrowed code lives in /core/includes/Symfony.
'Symfony' => DRUPAL_ROOT . '/core/vendor',
));
// Register the Drupal namespace for classes in core as a fallback.
// This allows to register additional namespaces within the Drupal namespace
// (e.g., for modules) and avoids an additional file_exists() on the Drupal
// core namespace, since the class loader can already determine the best
// namespace match based on a string comparison. It further allows modules to
// register/overload namespaces in Drupal core.
$loader->registerNamespaceFallbacks(array(
// All Drupal-namespaced code in core lives in /core/includes/Drupal.
'Drupal' => DRUPAL_ROOT . '/core/lib',
));
if (!$install_state['interactive']) {
drupal_override_server_variables($install_state['server']);
}
......@@ -961,7 +985,7 @@ function install_database_errors($database, $settings_file) {
try {
db_run_tasks($driver);
}
catch (DatabaseTaskException $e) {
catch (TaskException $e) {
// These are generic errors, so we do not have any specific key of the
// database connection array to attach them to; therefore, we just put
// them in the error array with standard numeric keys.
......
<?php
use Drupal\Core\Database\Database;
/**
* Indicates that a module has not been installed yet.
*/
......@@ -246,6 +248,7 @@ function drupal_detect_database_types() {
*/
function drupal_get_database_types() {
$databases = array();
$drivers = array();
// We define a driver as a directory in /core/includes/database that in turn
// contains a database.inc file. That allows us to drop in additional drivers
......@@ -253,8 +256,8 @@ function drupal_get_database_types() {
// Because we have no registry yet, we need to also include the install.inc
// file for the driver explicitly.
require_once DRUPAL_ROOT . '/core/includes/database/database.inc';
foreach (file_scan_directory(DRUPAL_ROOT . '/core/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
if (file_exists($file->uri . '/database.inc') && file_exists($file->uri . '/install.inc')) {
foreach (file_scan_directory(DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Driver', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
if (file_exists($file->uri . '/Install/Tasks.php')) {
$drivers[$file->filename] = $file->uri;
}
}
......@@ -276,305 +279,6 @@ function drupal_get_database_types() {
return $databases;
}
/**
* Database installer structure.
*
* Defines basic Drupal requirements for databases.
*/
abstract class DatabaseTasks {
/**
* Structure that describes each task to run.
*
* @var array
*
* Each value of the tasks array is an associative array defining the function
* to call (optional) and any arguments to be passed to the function.
*/
protected $tasks = array(
array(
'function' => 'checkEngineVersion',
'arguments' => array(),
),
array(
'arguments' => array(
'CREATE TABLE {drupal_install_test} (id int NULL)',
'Drupal can use CREATE TABLE database commands.',
'Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>',
TRUE,
),
),
array(
'arguments' => array(
'INSERT INTO {drupal_install_test} (id) VALUES (1)',
'Drupal can use INSERT database commands.',
'Failed to <strong>INSERT</strong> a value into a test table on your database server. We tried inserting a value with the command %query and the server reported the following error: %error.',
),
),
array(
'arguments' => array(
'UPDATE {drupal_install_test} SET id = 2',
'Drupal can use UPDATE database commands.',
'Failed to <strong>UPDATE</strong> a value in a test table on your database server. We tried updating a value with the command %query and the server reported the following error: %error.',
),
),
array(
'arguments' => array(
'DELETE FROM {drupal_install_test}',
'Drupal can use DELETE database commands.',
'Failed to <strong>DELETE</strong> a value from a test table on your database server. We tried deleting a value with the command %query and the server reported the following error: %error.',
),
),
array(
'arguments' => array(
'DROP TABLE {drupal_install_test}',
'Drupal can use DROP TABLE database commands.',
'Failed to <strong>DROP</strong> a test table from your database server. We tried dropping a table with the command %query and the server reported the following error %error.',
),
),
);
/**
* Results from tasks.
*
* @var array
*/
protected $results = array();
/**
* Ensure the PDO driver is supported by the version of PHP in use.
*/
protected function hasPdoDriver() {
return in_array($this->pdoDriver, PDO::getAvailableDrivers());
}
/**
* Assert test as failed.
*/
protected function fail($message) {
$this->results[$message] = FALSE;
}
/**
* Assert test as a pass.
*/
protected function pass($message) {
$this->results[$message] = TRUE;
}
/**
* Check whether Drupal is installable on the database.
*/
public function installable() {
return $this->hasPdoDriver() && empty($this->error);
}
/**
* Return the human-readable name of the driver.
*/
abstract public function name();
/**
* Return the minimum required version of the engine.
*
* @return
* A version string. If not NULL, it will be checked against the version
* reported by the Database engine using version_compare().
*/
public function minimumVersion() {
return NULL;
}
/**
* Run database tasks and tests to see if Drupal can run on the database.
*/
public function runTasks() {
// We need to establish a connection before we can run tests.
if ($this->connect()) {
foreach ($this->tasks as $task) {
if (!isset($task['function'])) {
$task['function'] = 'runTestQuery';
}
if (method_exists($this, $task['function'])) {
// Returning false is fatal. No other tasks can run.
if (FALSE === call_user_func_array(array($this, $task['function']), $task['arguments'])) {
break;
}
}
else {
throw new DatabaseTaskException(st("Failed to run all tasks against the database server. The task %task wasn't found.", array('%task' => $task['function'])));
}
}
}
// Check for failed results and compile message
$message = '';
foreach ($this->results as $result => $success) {
if (!$success) {
$message .= '<p class="error">' . $result . '</p>';
}
}
if (!empty($message)) {
$message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
throw new DatabaseTaskException($message);
}
}
/**
* Check if we can connect to the database.
*/
protected function connect() {
try {
// This doesn't actually test the connection.
db_set_active();
// Now actually do a check.
Database::getConnection();
$this->pass('Drupal can CONNECT to the database ok.');
}
catch (Exception $e) {
$this->fail(st('Failed to connect to your database server. The server reports the following message: %error.<ul><li>Is the database server running?</li><li>Does the database exist, and have you entered the correct database name?</li><li>Have you entered the correct username and password?</li><li>Have you entered the correct database hostname?</li></ul>', array('%error' => $e->getMessage())));
return FALSE;
}
return TRUE;
}
/**
* Run SQL tests to ensure the database can execute commands with the current user.
*/
protected function runTestQuery($query, $pass, $fail, $fatal = FALSE) {
try {
db_query($query);
$this->pass(st($pass));
}
catch (Exception $e) {
$this->fail(st($fail, array('%query' => $query, '%error' => $e->getMessage(), '%name' => $this->name())));
return !$fatal;
}
}
/**
* Check the engine version.
*/
protected function checkEngineVersion() {
if ($this->minimumVersion() && version_compare(Database::getConnection()->version(), $this->minimumVersion(), '<')) {
$this->fail(st("The database version %version is less than the minimum required version %minimum_version.", array('%version' => Database::getConnection()->version(), '%minimum_version' => $this->minimumVersion())));
}
}
/**
* Return driver specific configuration options.
*
* @param $database
* An array of driver specific configuration options.
*
* @return
* The options form array.
*/
public function getFormOptions($database) {
$form['database'] = array(
'#type' => 'textfield',
'#title' => st('Database name'),
'#default_value' => empty($database['database']) ? '' : $database['database'],
'#size' => 45,
'#required' => TRUE,
'#description' => st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_distribution_name())),
);
$form['username'] = array(
'#type' => 'textfield',
'#title' => st('Database username'),
'#default_value' => empty($database['username']) ? '' : $database['username'],
'#required' => TRUE,
'#size' => 45,
);
$form['password'] = array(
'#type' => 'password',
'#title' => st('Database password'),
'#default_value' => empty($database['password']) ? '' : $database['password'],
'#required' => FALSE,
'#size' => 45,
);
$form['advanced_options'] = array(
'#type' => 'fieldset',
'#title' => st('Advanced options'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider."),
'#weight' => 10,
);
$profile = drupal_get_profile();
$db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
$form['advanced_options']['db_prefix'] = array(
'#type' => 'textfield',
'#title' => st('Table prefix'),
'#default_value' => '',
'#size' => 45,
'#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_distribution_name(), '%prefix' => $db_prefix)),
'#weight' => 10,
);
$form['advanced_options']['host'] = array(
'#type' => 'textfield',
'#title' => st('Database host'),
'#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
'#size' => 45,
// Hostnames can be 255 characters long.
'#maxlength' => 255,
'#required' => TRUE,
'#description' => st('If your database is located on a different server, change this.'),
);
$form['advanced_options']['port'] = array(
'#type' => 'textfield',
'#title' => st('Database port'),
'#default_value' => empty($database['port']) ? '' : $database['port'],
'#size' => 45,
// The maximum port number is 65536, 5 digits.
'#maxlength' => 5,
'#description' => st('If your database server is listening to a non-standard port, enter its number.'),
);
return $form;
}
/**
* Validates driver specific configuration settings.
*
* Checks to ensure correct basic database settings and that a proper
* connection to the database can be established.
*
* @param $database
* An array of driver specific configuration options.
*
* @return
* An array of driver configuration errors, keyed by form element name.
*/
public function validateDatabaseSettings($database) {
$errors = array();
// Verify the table prefix.
if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
$errors[$database['driver'] . '][advanced_options][db_prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
}
// Verify the database port.
if (!empty($database['port']) && !is_numeric($database['port'])) {
$errors[$database['driver'] . '][advanced_options][port'] = st('Database port must be a number.');
}
return $errors;
}
}
/**
* Exception thrown if the database installer fails.
*/
class DatabaseTaskException extends Exception {
}
/**
* Replace values in settings.php with values in the submitted array.
*
......@@ -1300,7 +1004,8 @@ function db_run_tasks($driver) {
* The name of the driver.
*/
function db_installer_object($driver) {
Database::loadDriverFile($driver, array('install.inc'));
$task_class = 'DatabaseTasks_' . $driver;
// We cannot use Database::getConnection->getDriverClass() here, because
// the connection object is not yet functional.
$task_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Install\\Tasks";
return new $task_class();
}
<?php
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectExtender;
use Drupal\Core\Database\Query\SelectInterface;
/**
* @file
* Functions to aid in presenting database results as a set of pages.
*/
/**
* Query extender for pager queries.
*
* This is the "default" pager mechanism. It creates a paged query with a fixed
* number of entries per page.
*/
class PagerDefault extends SelectQueryExtender {
class PagerDefault extends SelectExtender {
/**
* The highest element we've autogenerated so far.
......@@ -42,7 +45,7 @@ class PagerDefault extends SelectQueryExtender {
*/
protected $customCountQuery = FALSE;
public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
public function __construct(SelectInterface $query, Connection $connection) {
parent::__construct($query, $connection);
// Add pager tag. Do this here to ensure that it is always added before
......@@ -103,7 +106,7 @@ protected function ensureElement() {
* The count query object. It must return a single row with a single column,
* which is the total number of records.
*/
public function setCountQuery(SelectQueryInterface $query) {
public function setCountQuery(SelectInterface $query) {
$this->customCountQuery = $query;
}
......
<?php
use Drupal\Core\Database\Database;
/**
* @file
* This file contains the code registry parser engine.
......@@ -20,18 +22,12 @@
*/
function _registry_update() {
// The registry serves as a central autoloader for all classes, including
// the database query builders. However, the registry rebuild process
// requires write ability to the database, which means having access to the
// query builders that require the registry in order to be loaded. That
// causes a fatal race condition. Therefore we manually include the
// appropriate query builders for the currently active database before the
// registry rebuild process runs.
// The registry serves as a central autoloader for all non-namespaced classes.
// It is backed by the database, but the database system is autoloaded using
// a PSR-0 class loader. That avoids a fata circular dependency here, since
// the other class loader will be able to load the database for us.
$connection_info = Database::getConnectionInfo();
$driver = $connection_info['default']['driver'];
require_once DRUPAL_ROOT . '/core/includes/database/query.inc';
require_once DRUPAL_ROOT . '/core/includes/database/select.inc';
require_once DRUPAL_ROOT . '/core/includes/database/' . $driver . '/query.inc';
// Get current list of modules and their files.
$modules = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAll();
......
<?php
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectExtender;
use Drupal\Core\Database\Query\SelectInterface;
/**
* @file
* Functions to aid in the creation of sortable tables.
......@@ -8,11 +12,10 @@
* column headers that the user can click on to sort the table by that column.
*/
/**
* Query extender class for tablesort queries.
*/
class TableSort extends SelectQueryExtender {
class TableSort extends SelectExtender {
/**
* The array of fields that can be sorted by.
......@@ -21,7 +24,7 @@ class TableSort extends SelectQueryExtender {
*/
protected $header = array();
public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
public function __construct(SelectInterface $query, Connection $connection) {
parent::__construct($query, $connection);
// Add convenience tag to mark that this is an extended query. We have to
......
This diff is collapsed.
<?php
/**
* @file
* Definition of Drupal\Core\Database\ConnectionNotDefinedException
*/
namespace Drupal\Core\Database;
use RuntimeException;
/**
* Exception thrown if an undefined database connection is requested.
*/
class ConnectionNotDefinedException extends RuntimeException {}
This diff is collapsed.
<?php
/**
* @file
* Definition of Drupal\Core\Database\DatabaseException
*/
namespace Drupal\Core\Database;
/**
* Interface for a database exception.
*
* All Database exceptions should implement this interface so that they can be
* caught collectively. Note that this applies only to Drupal-spawned
* exceptions. PDOException will not implement this interface and module
* developers should account for it separately.
*/
interface DatabaseException { }
......@@ -2,15 +2,24 @@
/**
* @file
* Database interface code for MySQL database servers.
* Definition of Drupal\Core\Database\Driver\mysql\Connection
*/
namespace Drupal\Core\Database\Driver\mysql;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\TransactionCommitFailedException;
use Drupal\Core\Database\Connection as DatabaseConnection;
use PDO;
use PDOException;
/**
* @ingroup database
* @{
*/
class DatabaseConnection_mysql extends DatabaseConnection {
class Connection extends DatabaseConnection {
/**
* Flag to indicate if we have registered the nextID cleanup function.
......@@ -165,7 +174,7 @@ protected function popCommittableTransactions() {
unset($this->transactionLayers[$name]);
if (empty($this->transactionLayers)) {
if (!PDO::commit()) {
throw new DatabaseTransactionCommitFailedException();
throw new TransactionCommitFailedException();
}
}
else {
......