summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.htaccess12
-rw-r--r--CHANGELOG.txt33
-rw-r--r--authorize.php35
-rw-r--r--includes/ajax.inc3
-rw-r--r--includes/bootstrap.inc52
-rw-r--r--includes/cache.inc69
-rw-r--r--includes/common.inc20
-rw-r--r--includes/database/database.inc43
-rw-r--r--includes/database/mysql/database.inc17
-rw-r--r--includes/database/query.inc9
-rw-r--r--includes/database/sqlite/query.inc27
-rw-r--r--includes/file.inc6
-rw-r--r--includes/form.inc29
-rw-r--r--includes/image.inc8
-rw-r--r--includes/install.core.inc33
-rw-r--r--includes/install.inc6
-rw-r--r--includes/language.inc179
-rw-r--r--includes/mail.inc28
-rw-r--r--includes/menu.inc1
-rw-r--r--includes/module.inc17
-rw-r--r--includes/password.inc2
-rw-r--r--includes/path.inc12
-rw-r--r--includes/session.inc2
-rw-r--r--includes/tablesort.inc16
-rw-r--r--includes/theme.inc149
-rw-r--r--includes/theme.maintenance.inc10
-rw-r--r--includes/token.inc12
-rw-r--r--includes/unicode.inc135
-rw-r--r--includes/update.inc12
-rw-r--r--includes/utility.inc1
-rw-r--r--install.php4
-rw-r--r--modules/aggregator/aggregator-rtl.css3
-rw-r--r--modules/aggregator/aggregator.admin.inc14
-rw-r--r--modules/aggregator/aggregator.css3
-rw-r--r--modules/aggregator/aggregator.module10
-rw-r--r--modules/aggregator/aggregator.pages.inc69
-rw-r--r--modules/aggregator/aggregator.processor.inc6
-rw-r--r--modules/aggregator/aggregator.test119
-rw-r--r--modules/book/book-rtl.css4
-rw-r--r--modules/book/book.admin.inc15
-rw-r--r--modules/book/book.css4
-rw-r--r--modules/book/book.js1
-rw-r--r--modules/book/book.module47
-rw-r--r--modules/book/book.pages.inc12
-rw-r--r--modules/book/book.test121
-rw-r--r--modules/comment/comment.admin.inc3
-rw-r--r--modules/comment/comment.module20
-rw-r--r--modules/dblog/dblog-rtl.css4
-rw-r--r--modules/dblog/dblog.admin.inc79
-rw-r--r--modules/dblog/dblog.css5
-rw-r--r--modules/dblog/dblog.module18
-rw-r--r--modules/dblog/dblog.test228
-rw-r--r--modules/field/field.api.php9
-rw-r--r--modules/field/field.attach.inc8
-rw-r--r--modules/field/field.crud.inc19
-rw-r--r--modules/field/field.info1
-rw-r--r--modules/field/field.info.class.inc668
-rw-r--r--modules/field/field.info.inc449
-rw-r--r--modules/field/field.install7
-rw-r--r--modules/field/field.module5
-rw-r--r--modules/field/modules/field_sql_storage/field_sql_storage.module7
-rw-r--r--modules/field/tests/field.test144
-rw-r--r--modules/field/tests/field_test.entity.inc6
-rw-r--r--modules/field_ui/field_ui.admin.inc4
-rw-r--r--modules/field_ui/field_ui.module23
-rw-r--r--modules/field_ui/field_ui.test6
-rw-r--r--modules/filter/filter.admin.inc65
-rw-r--r--modules/filter/filter.install2
-rw-r--r--modules/filter/filter.module225
-rw-r--r--modules/filter/filter.pages.inc14
-rw-r--r--modules/filter/filter.test118
-rw-r--r--modules/image/image.admin.inc2
-rw-r--r--modules/image/image.install3
-rw-r--r--modules/image/image.module92
-rw-r--r--modules/image/image.test24
-rw-r--r--modules/locale/locale.admin.inc4
-rw-r--r--modules/locale/locale.module66
-rw-r--r--modules/locale/locale.test42
-rw-r--r--modules/menu/menu.api.php8
-rw-r--r--modules/node/content_types.inc9
-rw-r--r--modules/node/node.admin.inc135
-rw-r--r--modules/node/node.api.php200
-rw-r--r--modules/node/node.install2
-rw-r--r--modules/node/node.module397
-rw-r--r--modules/node/node.pages.inc105
-rw-r--r--modules/node/node.test141
-rw-r--r--modules/node/tests/node_access_test.module6
-rw-r--r--modules/node/tests/node_test.module6
-rw-r--r--modules/node/tests/node_test_exception.module3
-rw-r--r--modules/overlay/overlay.module2
-rw-r--r--modules/simpletest/drupal_web_test_case.php43
-rw-r--r--modules/simpletest/tests/common.test16
-rw-r--r--modules/simpletest/tests/database_test.test962
-rw-r--r--modules/simpletest/tests/file.test9
-rw-r--r--modules/simpletest/tests/upgrade/upgrade.test14
-rw-r--r--modules/system/language.api.php86
-rw-r--r--modules/system/system.admin.inc6
-rw-r--r--modules/system/system.api.php64
-rw-r--r--modules/system/system.install18
-rw-r--r--modules/system/system.updater.inc4
-rw-r--r--modules/update/update.module6
-rw-r--r--modules/user/user.admin.inc15
-rw-r--r--modules/user/user.module20
-rw-r--r--sites/default/default.settings.php4
-rw-r--r--update.php36
105 files changed, 4290 insertions, 1807 deletions
diff --git a/.htaccess b/.htaccess
index 246edc2db..5ca1b08bd 100644
--- a/.htaccess
+++ b/.htaccess
@@ -56,6 +56,13 @@ DirectoryIndex index.php index.html index.htm
<IfModule mod_rewrite.c>
RewriteEngine on
+ # Set "protossl" to "s" if we were accessed via https://. This is used later
+ # if you enable "www." stripping or enforcement, in order to ensure that
+ # you don't bounce between http and https.
+ RewriteRule ^ - [E=protossl]
+ RewriteCond %{HTTPS} on
+ RewriteRule ^ - [E=protossl:s]
+
# Block access to "hidden" directories whose names begin with a period. This
# includes directories used by version control systems such as Subversion or
# Git to store control files. Files whose names begin with a period, as well
@@ -78,14 +85,15 @@ DirectoryIndex index.php index.html index.htm
# To redirect all users to access the site WITH the 'www.' prefix,
# (http://example.com/... will be redirected to http://www.example.com/...)
# uncomment the following:
+ # RewriteCond %{HTTP_HOST} .
# RewriteCond %{HTTP_HOST} !^www\. [NC]
- # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
+ # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#
# To redirect all users to access the site WITHOUT the 'www.' prefix,
# (http://www.example.com/... will be redirected to http://example.com/...)
# uncomment the following:
# RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
- # RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301]
+ # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 69d94de73..70ed4a4ea 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,4 +1,37 @@
+Drupal 7.22, xxxx-xx-xx (development version)
+-----------------------
+- Fixed a bug which caused the denial-of-service protection added in Drupal
+ 7.20 to break certain valid image URLs that had an extra slash in them.
+- Fixed a bug with update queries in the SQLite database driver that prevented
+ Drupal from being installed with SQLite on PHP 5.4.
+- Fixed enforced dependencies errors updating to recent versions of Drupal 7 on
+ certain non-MySQL databases.
+- Refactored the Field module's caching behavior to obtain large improvements
+ in memory usage for sites with many fields and instances (API addition:
+ http://drupal.org/node/1880666).
+- Fixed entity argument not being passed to implementations of
+ hook_file_download_access_alter(). The fix adds an additional context
+ parameter that can be passed when calling drupal_alter() for any hook (API
+ change: http://drupal.org/node/1882722).
+- Fixed broken support for translatable comment fields (API change:
+ http://drupal.org/node/1874724).
+- Added an assertThemeOutput() method to Simpletest to allow tests to check
+ that themed output matches an expected HTML string (API addition).
+- Added a link to "Install another module" after a module has been successfully
+ downloaded via the Update Manager (UI change).
+- Added an optional "exclusive" flag to installation profile .info files which
+ allows Drupal distributions to force a profile to be selected during
+ installation (API addition).
+- Fixed a bug which caused the database API to not properly close database
+ connections.
+- Added link to the URL for running cron from outside the site to the Cron
+ settings page (UI change).
+- Fixed a bug which prevented image styles from being reverted on PHP 5.4.
+- Made the default .htaccess rules protocol sensitive to improve security for
+ sites which use HTTPS and redirect between "www" and non-"www" versions of
+ the page.
+
Drupal 7.21, 2013-03-06
-----------------------
- Allowed sites using the 'image_allow_insecure_derivatives' variable to still
diff --git a/authorize.php b/authorize.php
index d14fa6e59..3ea2b20ac 100644
--- a/authorize.php
+++ b/authorize.php
@@ -4,16 +4,16 @@
* @file
* Administrative script for running authorized file operations.
*
- * Using this script, the site owner (the user actually owning the files on
- * the webserver) can authorize certain file-related operations to proceed
- * with elevated privileges, for example to deploy and upgrade modules or
- * themes. Users should not visit this page directly, but instead use an
- * administrative user interface which knows how to redirect the user to this
- * script as part of a multistep process. This script actually performs the
- * selected operations without loading all of Drupal, to be able to more
- * gracefully recover from errors. Access to the script is controlled by a
- * global killswitch in settings.php ('allow_authorize_operations') and via
- * the 'administer software updates' permission.
+ * Using this script, the site owner (the user actually owning the files on the
+ * webserver) can authorize certain file-related operations to proceed with
+ * elevated privileges, for example to deploy and upgrade modules or themes.
+ * Users should not visit this page directly, but instead use an administrative
+ * user interface which knows how to redirect the user to this script as part of
+ * a multistep process. This script actually performs the selected operations
+ * without loading all of Drupal, to be able to more gracefully recover from
+ * errors. Access to the script is controlled by a global killswitch in
+ * settings.php ('allow_authorize_operations') and via the 'administer software
+ * updates' permission.
*
* There are helper functions for setting up an operation to run via this
* system in modules/system/system.module. For more information, see:
@@ -21,16 +21,17 @@
*/
/**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
- * Global flag to identify update.php and authorize.php runs, and so
- * avoid various unwanted operations, such as hook_init() and
- * hook_exit() invokes, css/js preprocessing and translation, and
- * solve some theming issues. This flag is checked on several places
- * in Drupal code (not just authorize.php).
+ * Global flag to identify update.php and authorize.php runs.
+ *
+ * Identifies update.php and authorize.php runs, avoiding unwanted operations
+ * such as hook_init() and hook_exit() invokes, css/js preprocessing and
+ * translation, and solves some theming issues. The flag is checked in other
+ * places in Drupal code (not just authorize.php).
*/
define('MAINTENANCE_MODE', 'update');
@@ -51,7 +52,7 @@ function authorize_access_denied_page() {
* have access to the 'administer software updates' permission.
*
* @return
- * TRUE if the current user can run authorize.php, otherwise FALSE.
+ * TRUE if the current user can run authorize.php, and FALSE if not.
*/
function authorize_access_allowed() {
return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 4107029fe..d4082d2d8 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -836,7 +836,8 @@ function ajax_command_insert($selector, $html, $settings = NULL) {
* @return
* An array suitable for use with the ajax_render() function.
*
- * See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
+ * See
+ * @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
*/
function ajax_command_replace($selector, $html, $settings = NULL) {
return array(
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 93322de45..c6c98ecb6 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.21');
+define('VERSION', '7.22-dev');
/**
* Core API compatibility.
@@ -716,7 +716,6 @@ function drupal_settings_initialize() {
if (isset($base_url)) {
// Parse fixed base URL from settings.php.
$parts = parse_url($base_url);
- $http_protocol = $parts['scheme'];
if (!isset($parts['path'])) {
$parts['path'] = '';
}
@@ -811,7 +810,7 @@ function drupal_settings_initialize() {
* than by consulting the database.
*
* @return
- * The filename of the requested item.
+ * The filename of the requested item or NULL if the item is not found.
*/
function drupal_get_filename($type, $name, $filename = NULL) {
// The location of files will not change during the request, so do not use
@@ -1186,10 +1185,11 @@ function _drupal_set_preferred_header_name($name = NULL) {
* Headers are set in drupal_add_http_header(). Default headers are not set
* if they have been replaced or unset using drupal_add_http_header().
*
- * @param $default_headers
- * An array of headers as name/value pairs.
- * @param $single
- * If TRUE and headers have already be sent, send only the specified header.
+ * @param array $default_headers
+ * (optional) An array of headers as name/value pairs.
+ * @param bool $only_default
+ * (optional) If TRUE and headers have already been sent, send only the
+ * specified headers.
*/
function drupal_send_headers($default_headers = array(), $only_default = FALSE) {
$headers_sent = &drupal_static(__FUNCTION__, FALSE);
@@ -1420,8 +1420,9 @@ function drupal_unpack($obj, $field = 'data') {
* Basically, you can put variables like @name into your string, and t() will
* substitute their sanitized values at translation time. (See the
* Localization API pages referenced above and the documentation of
- * format_string() for details.) Translators can then rearrange the string as
- * necessary for the language (e.g., in Spanish, it might be "blog de @name").
+ * format_string() for details about how to define variables in your string.)
+ * Translators can then rearrange the string as necessary for the language
+ * (e.g., in Spanish, it might be "blog de @name").
*
* During the Drupal installation phase, some resources used by t() wil not be
* available to code that needs localization. See st() and get_t() for
@@ -1484,21 +1485,34 @@ function t($string, array $args = array(), array $options = array()) {
}
/**
- * Replaces placeholders with sanitized values in a string.
+ * Formats a string for HTML display by replacing variable placeholders.
+ *
+ * This function replaces variable placeholders in a string with the requested
+ * values and escapes the values so they can be safely displayed as HTML. It
+ * should be used on any unknown text that is intended to be printed to an HTML
+ * page (especially text that may have come from untrusted users, since in that
+ * case it prevents cross-site scripting and other security problems).
+ *
+ * In most cases, you should use t() rather than calling this function
+ * directly, since it will translate the text (on non-English-only sites) in
+ * addition to formatting it.
*
* @param $string
* A string containing placeholders.
* @param $args
* An associative array of replacements to make. Occurrences in $string of
- * any key in $args are replaced with the corresponding value, after
- * sanitization. The sanitization function depends on the first character of
- * the key:
- * - !variable: Inserted as is. Use this for text that has already been
- * sanitized.
- * - @variable: Escaped to HTML using check_plain(). Use this for anything
- * displayed on a page on the site.
- * - %variable: Escaped as a placeholder for user-submitted content using
- * drupal_placeholder(), which shows up as <em>emphasized</em> text.
+ * any key in $args are replaced with the corresponding value, after optional
+ * sanitization and formatting. The type of sanitization and formatting
+ * depends on the first character of the key:
+ * - @variable: Escaped to HTML using check_plain(). Use this as the default
+ * choice for anything displayed on a page on the site.
+ * - %variable: Escaped to HTML and formatted using drupal_placeholder(),
+ * which makes it display as <em>emphasized</em> text.
+ * - !variable: Inserted as is, with no sanitization or formatting. Only use
+ * this for text that has already been prepared for HTML display (for
+ * example, user-supplied text that has already been run through
+ * check_plain() previously, or is expected to contain some limited HTML
+ * tags and has already been run through filter_xss() previously).
*
* @see t()
* @ingroup sanitization
diff --git a/includes/cache.inc b/includes/cache.inc
index a19d3c38c..f76164b91 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -80,43 +80,15 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* same name. Other implementations might want to store several bins in data
* structures that get flushed together. While it is not a problem for most
* cache bins if the entries in them are flushed before their expire time, some
- * might break functionality or are extremely expensive to recalculate. These
- * will be marked with a (*). The other bins expired automatically by core.
- * Contributed modules can add additional bins and get them expired
- * automatically by implementing hook_flush_caches().
- *
- * - cache: Generic cache storage bin (used for variables, theme registry,
- * locale date, list of simpletest tests etc).
- *
- * - cache_block: Stores the content of various blocks.
- *
- * - cache field: Stores the field data belonging to a given object.
- *
- * - cache_filter: Stores filtered pieces of content.
- *
- * - cache_form(*): Stores multistep forms. Flushing this bin means that some
- * forms displayed to users lose their state and the data already submitted
- * to them.
- *
- * - cache_menu: Stores the structure of visible navigation menus per page.
- *
- * - cache_page: Stores generated pages for anonymous users. It is flushed
- * very often, whenever a page changes, at least for every ode and comment
- * submission. This is the only bin affected by the page cache setting on
- * the administrator panel.
- *
- * - cache path: Stores the system paths that have an alias.
- *
- * - cache update(*): Stores available releases. The update server (for
- * example, drupal.org) needs to produce the relevant XML for every project
- * installed on the current site. As this is different for (almost) every
- * site, it's very expensive to recalculate for the update server.
+ * might break functionality or are extremely expensive to recalculate. The
+ * other bins are expired automatically by core. Contributed modules can add
+ * additional bins and get them expired automatically by implementing
+ * hook_flush_caches().
*
* The reasons for having several bins are as follows:
- *
- * - smaller bins mean smaller database tables and allow for faster selects and
- * inserts
- * - we try to put fast changing cache items and rather static ones into
+ * - Smaller bins mean smaller database tables and allow for faster selects and
+ * inserts.
+ * - We try to put fast changing cache items and rather static ones into
* different bins. The effect is that only the fast changing bins will need a
* lot of writes to disk. The more static bins will also be better cacheable
* with MySQL's query cache.
@@ -125,13 +97,27 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* The cache ID of the data to store.
* @param $data
* The data to store in the cache. Complex data types will be automatically
- * serialized before insertion.
- * Strings will be stored as plain text and not serialized.
+ * serialized before insertion. Strings will be stored as plain text and are
+ * not serialized.
* @param $bin
- * The cache bin to store the data in. Valid core values are 'cache_block',
- * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
- * 'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default
- * cache.
+ * The cache bin to store the data in. Valid core values are:
+ * - cache: (default) Generic cache storage bin (used for theme registry,
+ * locale date, list of simpletest tests, etc.).
+ * - cache_block: Stores the content of various blocks.
+ * - cache_bootstrap: Stores the class registry, the system list of modules,
+ * the list of which modules implement which hooks, and the Drupal variable
+ * list.
+ * - cache_field: Stores the field data belonging to a given object.
+ * - cache_filter: Stores filtered pieces of content.
+ * - cache_form: Stores multistep forms. Flushing this bin means that some
+ * forms displayed to users lose their state and the data already submitted
+ * to them. This bin should not be flushed before its expired time.
+ * - cache_menu: Stores the structure of visible navigation menus per page.
+ * - cache_page: Stores generated pages for anonymous users. It is flushed
+ * very often, whenever a page changes, at least for every node and comment
+ * submission. This is the only bin affected by the page cache setting on
+ * the administrator panel.
+ * - cache_path: Stores the system paths that have an alias.
* @param $expire
* One of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
@@ -141,6 +127,7 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like CACHE_TEMPORARY.
*
+ * @see _update_cache_set()
* @see cache_get()
*/
function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
diff --git a/includes/common.inc b/includes/common.inc
index 8276576e0..f6171cfd9 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1167,7 +1167,8 @@ function fix_gpc_magic() {
/**
* Verifies the syntax of the given e-mail address.
*
- * See @link http://tools.ietf.org/html/rfc5321 RFC 5321 @endlink for details.
+ * This uses the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
*
* @param $mail
* A string containing an e-mail address.
@@ -2379,6 +2380,14 @@ function drupal_attributes(array $attributes = array()) {
* internal links output by modules should be generated by this function if
* possible.
*
+ * However, for links enclosed in translatable text you should use t() and
+ * embed the HTML anchor tag directly in the translated string. For example:
+ * @code
+ * t('Visit the <a href="@url">settings</a> page', array('@url' => url('admin')));
+ * @endcode
+ * This keeps the context of the link title ('settings' in the example) for
+ * translators.
+ *
* @param string $text
* The translated link text for the anchor tag.
* @param string $path
@@ -2779,7 +2788,7 @@ function drupal_set_time_limit($time_limit) {
* The name of the item for which the path is requested.
*
* @return
- * The path to the requested item.
+ * The path to the requested item or an empty string if the item is not found.
*/
function drupal_get_path($type, $name) {
return dirname(drupal_get_filename($type, $name));
@@ -5038,6 +5047,11 @@ function drupal_get_private_key() {
*
* @param $value
* An additional value to base the token on.
+ *
+ * @return string
+ * A 43-character URL-safe token for validation, based on the user session ID,
+ * the global $drupal_hash_salt variable from settings.php, and the
+ * 'drupal_private_key' configuration variable.
*/
function drupal_get_token($value = '') {
return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
@@ -5568,7 +5582,7 @@ function drupal_pre_render_link($element) {
* @code
* $node->content['links'] = array(
* '#theme' => 'links__node',
- * '#pre_render' = array('drupal_pre_render_links'),
+ * '#pre_render' => array('drupal_pre_render_links'),
* 'comment' => array(
* '#theme' => 'links__node__comment',
* '#links' => array(
diff --git a/includes/database/database.inc b/includes/database/database.inc
index cae50fb87..339c9b03e 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -167,7 +167,7 @@
* }
* @endcode
*
- * @link http://drupal.org/developing/api/database @endlink
+ * @see http://drupal.org/developing/api/database
*/
@@ -194,7 +194,7 @@ abstract class DatabaseConnection extends PDO {
/**
* The key representing this connection.
- *
+ *
* The key is a unique string which identifies a database connection. A
* connection can be a single server or a cluster of master and slaves (use
* target to pick between master and slave).
@@ -303,13 +303,29 @@ abstract class DatabaseConnection extends PDO {
// Call PDO::__construct and PDO::setAttribute.
parent::__construct($dsn, $username, $password, $driver_options);
- // Set a specific PDOStatement class if the driver requires that.
+ // Set a Statement class, unless the driver opted out.
if (!empty($this->statementClass)) {
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
}
}
/**
+ * Destroys this Connection object.
+ *
+ * PHP does not destruct an object if it is still referenced in other
+ * variables. In case of PDO database connection objects, PHP only closes the
+ * connection when the PDO object is destructed, so any references to this
+ * object may cause the number of maximum allowed connections to be exceeded.
+ */
+ public function destroy() {
+ // Destroy all references to this connection by setting them to NULL.
+ // The Statement class attribute only accepts a new value that presents a
+ // proper callable, so we reset it to PDOStatement.
+ $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
+ $this->schema = NULL;
+ }
+
+ /**
* Returns the default query options for any given query.
*
* A given query can be customized with a number of option flags in an
@@ -1627,8 +1643,8 @@ abstract class Database {
*/
final public static function removeConnection($key) {
if (isset(self::$databaseInfo[$key])) {
+ self::closeConnection(NULL, $key);
unset(self::$databaseInfo[$key]);
- unset(self::$connections[$key]);
return TRUE;
}
else {
@@ -1694,11 +1710,24 @@ abstract class Database {
if (!isset($key)) {
$key = self::$activeKey;
}
- // To close the connection, we need to unset the static variable.
+ // To close a connection, it needs to be set to NULL and removed from the
+ // static variable. In all cases, closeConnection() might be called for a
+ // connection that was not opened yet, in which case the key is not defined
+ // yet and we just ensure that the connection key is undefined.
if (isset($target)) {
+ if (isset(self::$connections[$key][$target])) {
+ self::$connections[$key][$target]->destroy();
+ self::$connections[$key][$target] = NULL;
+ }
unset(self::$connections[$key][$target]);
}
else {
+ if (isset(self::$connections[$key])) {
+ foreach (self::$connections[$key] as $target => $connection) {
+ self::$connections[$key][$target]->destroy();
+ self::$connections[$key][$target] = NULL;
+ }
+ }
unset(self::$connections[$key]);
}
}
@@ -1852,8 +1881,8 @@ class DatabaseTransaction {
*/
protected $name;
- public function __construct(DatabaseConnection &$connection, $name = NULL) {
- $this->connection = &$connection;
+ public function __construct(DatabaseConnection $connection, $name = NULL) {
+ $this->connection = $connection;
// If there is no transaction depth, then no transaction has started. Name
// the transaction 'drupal_transaction'.
if (!$depth = $connection->transactionDepth()) {
diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc
index 7ad019e58..00d81f473 100644
--- a/includes/database/mysql/database.inc
+++ b/includes/database/mysql/database.inc
@@ -13,11 +13,11 @@
class DatabaseConnection_mysql extends DatabaseConnection {
/**
- * Flag to indicate if we have registered the nextID cleanup function.
+ * Flag to indicate if the cleanup function in __destruct() should run.
*
* @var boolean
*/
- protected $shutdownRegistered = FALSE;
+ protected $needsCleanup = FALSE;
public function __construct(array $connection_options = array()) {
// This driver defaults to transaction support, except if explicitly passed FALSE.
@@ -78,6 +78,12 @@ class DatabaseConnection_mysql extends DatabaseConnection {
$this->exec(implode('; ', $connection_options['init_commands']));
}
+ public function __destruct() {
+ if ($this->needsCleanup) {
+ $this->nextIdDelete();
+ }
+ }
+
public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
}
@@ -115,12 +121,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
$this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
$new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
}
- if (!$this->shutdownRegistered) {
- // Use register_shutdown_function() here to keep the database system
- // independent of Drupal.
- register_shutdown_function(array($this, 'nextIdDelete'));
- $shutdownRegistered = TRUE;
- }
+ $this->needsCleanup = TRUE;
return $new_id;
}
diff --git a/includes/database/query.inc b/includes/database/query.inc
index 612985e02..8beeef1e8 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -1898,8 +1898,13 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
function __clone() {
$this->changed = TRUE;
foreach ($this->conditions as $key => $condition) {
- if ($key !== '#conjunction' && $condition['field'] instanceOf QueryConditionInterface) {
- $this->conditions[$key]['field'] = clone($condition['field']);
+ if ($key !== '#conjunction') {
+ if ($condition['field'] instanceOf QueryConditionInterface) {
+ $this->conditions[$key]['field'] = clone($condition['field']);
+ }
+ if ($condition['value'] instanceOf SelectQueryInterface) {
+ $this->conditions[$key]['value'] = clone($condition['value']);
+ }
}
}
}
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index 74ff9ba20..1bf609db1 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -57,39 +57,18 @@ class InsertQuery_sqlite extends InsertQuery {
* we don't select those rows.
*
* A query like this one:
- * UPDATE test SET name = 'newname' WHERE tid = 1
+ * UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1
* will become:
- * UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
+ * UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1 AND (col1 <> 'newcol1' OR col2 <> 'newcol2')
*/
class UpdateQuery_sqlite extends UpdateQuery {
- /**
- * Helper function that removes the fields that are already in a condition.
- *
- * @param $fields
- * The fields.
- * @param QueryConditionInterface $condition
- * A database condition.
- */
- protected function removeFieldsInCondition(&$fields, QueryConditionInterface $condition) {
- foreach ($condition->conditions() as $child_condition) {
- if ($child_condition['field'] instanceof QueryConditionInterface) {
- $this->removeFieldsInCondition($fields, $child_condition['field']);
- }
- else {
- unset($fields[$child_condition['field']]);
- }
- }
- }
-
public function execute() {
if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
return parent::execute();
}
- // Get the fields used in the update query, and remove those that are already
- // in the condition.
+ // Get the fields used in the update query.
$fields = $this->expressionFields + $this->fields;
- $this->removeFieldsInCondition($fields, $this->condition);
// Add the inverse of the fields to the condition.
$condition = new DatabaseCondition('OR');
diff --git a/includes/file.inc b/includes/file.inc
index 278be3ddc..09a442435 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -89,7 +89,7 @@ define('FILE_STATUS_PERMANENT', 1);
* wrappers that are appropriate for particular usage. For example, this returns
* only stream wrappers that use local file storage:
* @code
- * $local_stream_wrappers = file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL);
+ * $local_stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
* @endcode
*
* The $filter parameter can only filter to types containing a particular flag.
@@ -99,7 +99,7 @@ define('FILE_STATUS_PERMANENT', 1);
* array_diff_key() function can be used to help with this. For example, this
* returns only stream wrappers that do not use local file storage:
* @code
- * $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL));
+ * $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL));
* @endcode
*
* @param $filter
@@ -892,7 +892,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
$destination = file_destination($destination, $replace);
if ($destination === FALSE) {
drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error');
- watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => $destination));
+ watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%directory' => $destination));
return FALSE;
}
diff --git a/includes/form.inc b/includes/form.inc
index aa90eca69..babd18b49 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -3662,35 +3662,6 @@ function form_pre_render_fieldset($element) {
/**
* Creates a group formatted as vertical tabs.
*
- * Note that autocomplete callbacks should include special handling as the
- * user's input may contain forward slashes. If the user-submitted string has a
- * '/' in the text that is sent in the autocomplete request, the menu system
- * will split the text and pass it to the callback as multiple arguments.
- *
- * Suppose your autocomplete path in the menu system is 'mymodule_autocomplete.'
- * In your form you have:
- * @code
- * '#autocomplete_path' => 'mymodule_autocomplete/' . $some_key . '/' . $some_id,
- * @endcode
- * The user types in "keywords" so the full path called is:
- * 'mymodule_autocomplete/$some_key/$some_id/keywords'
- *
- * You should include code similar to the following to handle slashes in the
- * input:
- * @code
- * function mymodule_autocomplete_callback($arg1, $arg2, $keywords) {
- * $args = func_get_args();
- * // We need to remove $arg1 and $arg2 from the beginning of the array so we
- * // are left with the keywords.
- * array_shift($args);
- * array_shift($args);
- * // We store the user's original input in $keywords, including any slashes.
- * $keywords = implode('/', $args);
- *
- * // Your code here.
- * }
- * @endcode
- *
* @param $element
* An associative array containing the properties and children of the
* fieldset.
diff --git a/includes/image.inc b/includes/image.inc
index ee5a086de..e30a33855 100644
--- a/includes/image.inc
+++ b/includes/image.inc
@@ -233,11 +233,11 @@ function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NUL
* @param $image
* An image object returned by image_load().
* @param $width
- * The target width, in pixels. This value is omitted then the scaling will
- * based only on the height value.
+ * The target width, in pixels. If this value is NULL then the scaling will
+ * be based only on the height value.
* @param $height
- * The target height, in pixels. This value is omitted then the scaling will
- * based only on the width value.
+ * The target height, in pixels. If this value is NULL then the scaling will
+ * be based only on the width value.
* @param $upscale
* Boolean indicating that files smaller than the dimensions will be scaled
* up. This generally results in a low quality image.
diff --git a/includes/install.core.inc b/includes/install.core.inc
index 9805e1c88..7a694e9bb 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -1041,7 +1041,21 @@ function install_select_profile(&$install_state) {
}
/**
- * Selects an installation profile from a list or from a $_POST submission.
+ * Selects an installation profile.
+ *
+ * A profile will be selected if:
+ * - Only one profile is available,
+ * - A profile was submitted through $_POST,
+ * - Exactly one of the profiles is marked as "exclusive".
+ * If multiple profiles are marked as "exclusive" then no profile will be
+ * selected.
+ *
+ * @param array $profiles
+ * An associative array of profiles with the machine-readable names as keys.
+ *
+ * @return
+ * The machine-readable name of the selected profile or NULL if no profile was
+ * selected.
*/
function _install_select_profile($profiles) {
if (sizeof($profiles) == 0) {
@@ -1061,6 +1075,23 @@ function _install_select_profile($profiles) {
}
}
}
+ // Check for a profile marked as "exclusive" and ensure that only one
+ // profile is marked as such.
+ $exclusive_profile = NULL;
+ foreach ($profiles as $profile) {
+ $profile_info = install_profile_info($profile->name);
+ if (!empty($profile_info['exclusive'])) {
+ if (empty($exclusive_profile)) {
+ $exclusive_profile = $profile->name;
+ }
+ else {
+ // We found a second "exclusive" profile. There's no way to choose
+ // between them, so we ignore the property.
+ return;
+ }
+ }
+ }
+ return $exclusive_profile;
}
/**
diff --git a/includes/install.inc b/includes/install.inc
index 0372483b6..c4bcb88b2 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -1244,6 +1244,12 @@ function drupal_check_module($module) {
* - distribution_name: The name of the Drupal distribution that is being
* installed, to be shown throughout the installation process. Defaults to
* 'Drupal'.
+ * - exclusive: If the install profile is intended to be the only eligible
+ * choice in a distribution, setting exclusive = TRUE will auto-select it
+ * during installation, and the install profile selection screen will be
+ * skipped. If more than one profile is found where exclusive = TRUE then
+ * this property will have no effect and the profile selection screen will
+ * be shown as normal with all available profiles shown.
*
* Note that this function does an expensive file system scan to get info file
* information for dependencies. If you only need information from the info
diff --git a/includes/language.inc b/includes/language.inc
index d0ea83113..ea63948d9 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -2,7 +2,9 @@
/**
* @file
- * Multiple language handling functionality.
+ * Language Negotiation API.
+ *
+ * @see http://drupal.org/node/1497272
*/
/**
@@ -11,7 +13,96 @@
define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default');
/**
- * Return all the defined language types.
+ * @defgroup language_negotiation Language Negotiation API functionality
+ * @{
+ * Functions to customize the language types and the negotiation process.
+ *
+ * The language negotiation API is based on two major concepts:
+ * - Language types: types of translatable data (the types of data that a user
+ * can view or request).
+ * - Language negotiation providers: functions for determining which language to
+ * use to present a particular piece of data to the user.
+ * Both language types and language negotiation providers are customizable.
+ *
+ * Drupal defines three built-in language types:
+ * - Interface language: The page's main language, used to present translated
+ * user interface elements such as titles, labels, help text, and messages.
+ * - Content language: The language used to present content that is available
+ * in more than one language (see
+ * @link field_language Field Language API @endlink for details).
+ * - URL language: The language associated with URLs. When generating a URL,
+ * this value will be used by url() as a default if no explicit preference is
+ * provided.
+ * Modules can define additional language types through
+ * hook_language_types_info(), and alter existing language type definitions
+ * through hook_language_types_info_alter().
+ *
+ * Language types may be configurable or fixed. The language negotiation
+ * providers associated with a configurable language type can be explicitly
+ * set through the user interface. A fixed language type has predetermined
+ * (module-defined) language negotiation settings and, thus, does not appear in
+ * the configuration page. Here is a code snippet that makes the content
+ * language (which by default inherits the interface language's values)
+ * configurable:
+ * @code
+ * function mymodule_language_types_info_alter(&$language_types) {
+ * unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+ * }
+ * @endcode
+ *
+ * Every language type can have a different set of language negotiation
+ * providers assigned to it. Different language types often share the same
+ * language negotiation settings, but they can have independent settings if
+ * needed. If two language types are configured the same way, their language
+ * switcher configuration will be functionally identical and the same settings
+ * will act on both language types.
+ *
+ * Drupal defines the following built-in language negotiation providers:
+ * - URL: Determine the language from the URL (path prefix or domain).
+ * - Session: Determine the language from a request/session parameter.
+ * - User: Follow the user's language preference.
+ * - Browser: Determine the language from the browser's language settings.
+ * - Default language: Use the default site language.
+ * Language negotiation providers are simple callback functions that implement a
+ * particular logic to return a language code. For instance, the URL provider
+ * searches for a valid path prefix or domain name in the current request URL.
+ * If a language negotiation provider does not return a valid language code, the
+ * next provider associated to the language type (based on provider weight) is
+ * invoked.
+ *
+ * Modules can define additional language negotiation providers through
+ * hook_language_negotiation_info(), and alter existing providers through
+ * hook_language_negotiation_info_alter(). Here is an example snippet that lets
+ * path prefixes be ignored for administrative paths:
+ * @code
+ * function mymodule_language_negotiation_info_alter(&$negotiation_info) {
+ * // Replace the core function with our own function.
+ * module_load_include('language', 'inc', 'language.negotiation');
+ * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['negotiation'] = 'mymodule_from_url';
+ * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module';
+ * }
+ *
+ * function mymodule_from_url($languages) {
+ * // Use the core URL language negotiation provider to get a valid language
+ * // code.
+ * module_load_include('language', 'inc', 'language.negotiation');
+ * $langcode = language_from_url($languages);
+ *
+ * // If we are on an administrative path, override with the default language.
+ * if (isset($_GET['q']) && strtok($_GET['q'], '/') == 'admin') {
+ * return language_default()->langcode;
+ * }
+ * return $langcode;
+ * }
+ * ?>
+ * @endcode
+ *
+ * For more information, see
+ * @link http://drupal.org/node/1497272 Language Negotiation API @endlink
+ */
+
+/**
+ * Returns all the defined language types.
*
* @return
* An array of language type names. The name will be used as the global
@@ -30,11 +121,11 @@ function language_types_info() {
}
/**
- * Return only the configurable language types.
+ * Returns only the configurable language types.
*
* A language type maybe configurable or fixed. A fixed language type is a type
- * whose negotiation values are unchangeable and defined while defining the
- * language type itself.
+ * whose language negotiation providers are module-defined and not altered
+ * through the user interface.
*
* @param $stored
* Optional. By default retrieves values from the 'language_types' variable to
@@ -68,7 +159,7 @@ function language_types_configurable($stored = TRUE) {
}
/**
- * Disable the given language types.
+ * Disables the given language types.
*
* @param $types
* An array of language types.
@@ -122,16 +213,17 @@ function language_types_set() {
}
/**
- * Check if a language provider is enabled.
+ * Checks whether a language negotiation provider is enabled for a language type.
*
* This has two possible behaviors:
* - If $provider_id is given return its ID if enabled, FALSE otherwise.
- * - If no ID is passed the first enabled language provider is returned.
+ * - If no ID is passed the first enabled language negotiation provider is
+ * returned.
*
* @param $type
- * The language negotiation type.
+ * The language negotiation provider type.
* @param $provider_id
- * The language provider ID.
+ * The language negotiation provider ID.
*
* @return
* The provider ID if it is enabled, FALSE otherwise.
@@ -155,14 +247,13 @@ function language_negotiation_get($type, $provider_id = NULL) {
}
/**
- * Check if the given language provider is enabled for any configurable language
- * type.
+ * Checks if the language negotiation provider is enabled for any language type.
*
* @param $provider_id
- * The language provider ID.
+ * The language negotiation provider ID.
*
* @return
- * TRUE if there is at least one language type for which the give language
+ * TRUE if there is at least one language type for which the given language
* provider is enabled, FALSE otherwise.
*/
function language_negotiation_get_any($provider_id) {
@@ -176,7 +267,7 @@ function language_negotiation_get_any($provider_id) {
}
/**
- * Return the language switch links for the given language.
+ * Returns the language switch links for the given language.
*
* @param $type
* The language negotiation type.
@@ -223,7 +314,7 @@ function language_negotiation_get_switch_links($type, $path) {
}
/**
- * Updates language configuration to remove any language provider that is no longer defined.
+ * Removes any unused language negotation providers from the configuration.
*/
function language_negotiation_purge() {
// Ensure that we are getting the defined language negotiation information. An
@@ -246,12 +337,12 @@ function language_negotiation_purge() {
}
/**
- * Save a list of language providers.
+ * Saves a list of language negotiation providers.
*
* @param $type
* The language negotiation type.
* @param $language_providers
- * An array of language provider weights keyed by id.
+ * An array of language negotiation provider weights keyed by provider ID.
* @see language_provider_weight()
*/
function language_negotiation_set($type, $language_providers) {
@@ -277,7 +368,7 @@ function language_negotiation_set($type, $language_providers) {
// If the provider does not express any preference about types, make it
// available for any configurable type.
$types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
- // Check if the provider is defined and has the right type.
+ // Check whether the provider is defined and has the right type.
if (isset($types[$type])) {
$provider_data = array();
foreach ($provider_fields as $field) {
@@ -294,10 +385,10 @@ function language_negotiation_set($type, $language_providers) {
}
/**
- * Return all the defined language providers.
+ * Returns all the defined language negotiation providers.
*
* @return
- * An array of language providers.
+ * An array of language negotiation providers.
*/
function language_negotiation_info() {
$language_providers = &drupal_static(__FUNCTION__);
@@ -306,7 +397,7 @@ function language_negotiation_info() {
// Collect all the module-defined language negotiation providers.
$language_providers = module_invoke_all('language_negotiation_info');
- // Add the default language provider.
+ // Add the default language negotiation provider.
$language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
'callbacks' => array('language' => 'language_from_default'),
'weight' => 10,
@@ -314,7 +405,7 @@ function language_negotiation_info() {
'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
);
- // Let other modules alter the list of language providers.
+ // Let other modules alter the list of language negotiation providers.
drupal_alter('language_negotiation_info', $language_providers);
}
@@ -322,16 +413,17 @@ function language_negotiation_info() {
}
/**
- * Helper function used to cache the language providers results.
+ * Helper function used to cache the language negotiation providers results.
*
* @param $provider_id
- * The language provider ID.
+ * The language negotiation provider's identifier.
* @param $provider
- * The language provider to be invoked. If not passed it will be explicitly
- * loaded through language_negotiation_info().
+ * (optional) An associative array of information about the provider to be
+ * invoked (see hook_language_negotiation_info() for details). If not passed
+ * in, it will be loaded through language_negotiation_info().
*
* @return
- * The language provider's return value.
+ * A language object representing the language chosen by the provider.
*/
function language_provider_invoke($provider_id, $provider = NULL) {
$results = &drupal_static(__FUNCTION__);
@@ -352,25 +444,26 @@ function language_provider_invoke($provider_id, $provider = NULL) {
require_once DRUPAL_ROOT . '/' . $provider['file'];
}
- // If the language provider has no cache preference or this is satisfied
- // we can execute the callback.
+ // If the language negotiation provider has no cache preference or this is
+ // satisfied we can execute the callback.
$cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
$callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
$langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
$results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
}
- // Since objects are resources we need to return a clone to prevent the
- // provider cache to be unintentionally altered. The same providers might be
- // used with different language types based on configuration.
+ // Since objects are resources, we need to return a clone to prevent the
+ // language negotiation provider cache from being unintentionally altered. The
+ // same providers might be used with different language types based on
+ // configuration.
return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id];
}
/**
- * Return the passed language provider weight or a default value.
+ * Returns the passed language negotiation provider weight or a default value.
*
* @param $provider
- * A language provider data structure.
+ * A language negotiation provider data structure.
*
* @return
* A numeric weight.
@@ -381,16 +474,16 @@ function language_provider_weight($provider) {
}
/**
- * Choose a language for the given type based on language negotiation settings.
+ * Chooses a language based on language negotiation provider settings.
*
* @param $type
- * The language type.
+ * The language type key to find the language for.
*
* @return
* The negotiated language object.
*/
function language_initialize($type) {
- // Execute the language providers in the order they were set up and return the
+ // Execute the language negotiation providers in the order they were set up and return the
// first valid language found.
$negotiation = variable_get("language_negotiation_$type", array());
@@ -409,7 +502,7 @@ function language_initialize($type) {
}
/**
- * Default language provider.
+ * Returns the default language negotiation provider.
*
* @return
* The default language code.
@@ -421,8 +514,8 @@ function language_from_default() {
/**
* Splits the given path into prefix and actual path.
*
- * Parse the given path and return the language object identified by the
- * prefix and the actual path.
+ * Parse the given path and return the language object identified by the prefix
+ * and the actual path.
*
* @param $path
* The path to split.
@@ -482,3 +575,7 @@ function language_fallback_get_candidates($type = LANGUAGE_TYPE_CONTENT) {
return $fallback_candidates;
}
+
+/**
+ * @} End of "language_negotiation"
+ */
diff --git a/includes/mail.inc b/includes/mail.inc
index 8479d8e9b..bbb55357d 100644
--- a/includes/mail.inc
+++ b/includes/mail.inc
@@ -93,7 +93,9 @@ define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER
* will be {$module}_{$key}.
* @param $to
* The e-mail address or addresses where the message will be sent to. The
- * formatting of this string must comply with RFC 2822. Some examples are:
+ * formatting of this string will be validated with the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
+ * Some examples are:
* - user@example.com
* - user@example.com, anotheruser@example.com
* - User <user@example.com>
@@ -212,9 +214,9 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N
* 'mail_system', which is a keyed array. The default implementation
* is the class whose name is the value of 'default-system' key. A more specific
* match first to key and then to module will be used in preference to the
- * default. To specificy a different class for all mail sent by one module, set
+ * default. To specify a different class for all mail sent by one module, set
* the class name as the value for the key corresponding to the module name. To
- * specificy a class for a particular message sent by one module, set the class
+ * specify a class for a particular message sent by one module, set the class
* name as the value for the array key that is the message id, which is
* "${module}_${key}".
*
@@ -307,19 +309,21 @@ interface MailSystemInterface {
* - id: A unique identifier of the e-mail type. Examples: 'contact_user_copy',
* 'user_password_reset'.
* - to: The mail address or addresses where the message will be sent to.
- * The formatting of this string must comply with RFC 2822. Some examples:
+ * The formatting of this string will be validated with the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
+ * Some examples are:
* - user@example.com
* - user@example.com, anotheruser@example.com
* - User <user@example.com>
* - User <user@example.com>, Another User <anotheruser@example.com>
- * - subject: Subject of the e-mail to be sent. This must not contain any
- * newline characters, or the mail may not be sent properly.
- * - body: Message to be sent. Accepts both CRLF and LF line-endings.
- * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
- * smart plain text wrapping.
- * - headers: Associative array containing all additional mail headers not
- * defined by one of the other parameters. PHP's mail() looks for Cc
- * and Bcc headers and sends the mail to addresses in these headers too.
+ * - subject: Subject of the e-mail to be sent. This must not contain any
+ * newline characters, or the mail may not be sent properly.
+ * - body: Message to be sent. Accepts both CRLF and LF line-endings.
+ * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
+ * smart plain text wrapping.
+ * - headers: Associative array containing all additional mail headers not
+ * defined by one of the other parameters. PHP's mail() looks for Cc and
+ * Bcc headers and sends the mail to addresses in these headers too.
*
* @return
* TRUE if the mail was successfully accepted for delivery, otherwise FALSE.
diff --git a/includes/menu.inc b/includes/menu.inc
index 0cb9d23b8..2be090327 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -618,6 +618,7 @@ function _menu_load_objects(&$item, &$map) {
* $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
*/
function _menu_check_access(&$item, $map) {
+ $item['access'] = FALSE;
// Determine access callback, which will decide whether or not the current
// user has access to this path.
$callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
diff --git a/includes/module.inc b/includes/module.inc
index d932f07b9..341cd7911 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -898,9 +898,10 @@ function drupal_required_modules() {
* hook_TYPE_alter() implementations in modules. It ensures a consistent
* interface for all altering operations.
*
- * A maximum of 2 alterable arguments is supported. In case more arguments need
- * to be passed and alterable, modules provide additional variables assigned by
- * reference in the last $context argument:
+ * A maximum of 2 alterable arguments is supported (a third is supported for
+ * legacy reasons, but should not be used in new code). In case more arguments
+ * need to be passed and alterable, modules provide additional variables
+ * assigned by reference in the last $context argument:
* @code
* $context = array(
* 'alterable' => &$alterable,
@@ -939,8 +940,14 @@ function drupal_required_modules() {
* (optional) An additional variable that is passed by reference. If more
* context needs to be provided to implementations, then this should be an
* associative array as described above.
+ * @param $context3
+ * (optional) An additional variable that is passed by reference. This
+ * parameter is deprecated and will not exist in Drupal 8; consequently, it
+ * should not be used for new Drupal 7 code either. It is here only for
+ * backwards compatibility with older code that passed additional arguments
+ * to drupal_alter().
*/
-function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
+function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
@@ -1053,6 +1060,6 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
}
foreach ($functions[$cid] as $function) {
- $function($data, $context1, $context2);
+ $function($data, $context1, $context2, $context3);
}
}
diff --git a/includes/password.inc b/includes/password.inc
index d4f5f738a..3d5a400d2 100644
--- a/includes/password.inc
+++ b/includes/password.inc
@@ -43,7 +43,7 @@ function _password_itoa64() {
}
/**
- * Encode bytes into printable base 64 using the *nix standard from crypt().
+ * Encodes bytes into printable base 64 using the *nix standard from crypt().
*
* @param $input
* The string containing bytes to encode.
diff --git a/includes/path.inc b/includes/path.inc
index 411a7a71c..234430ea1 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -386,7 +386,7 @@ function drupal_path_alias_whitelist_rebuild($source = NULL) {
}
/**
- * Fetch a specific URL alias from the database.
+ * Fetches a specific URL alias from the database.
*
* @param $conditions
* A string representing the source, a number representing the pid, or an
@@ -475,11 +475,11 @@ function path_delete($criteria) {
}
/**
- * Determine whether a path is in the administrative section of the site.
+ * Determines whether a path is in the administrative section of the site.
*
- * By default, paths are considered to be non-administrative. If a path does not
- * match any of the patterns in path_get_admin_paths(), or if it matches both
- * administrative and non-administrative patterns, it is considered
+ * By default, paths are considered to be non-administrative. If a path does
+ * not match any of the patterns in path_get_admin_paths(), or if it matches
+ * both administrative and non-administrative patterns, it is considered
* non-administrative.
*
* @param $path
@@ -503,7 +503,7 @@ function path_is_admin($path) {
}
/**
- * Get a list of administrative and non-administrative paths.
+ * Gets a list of administrative and non-administrative paths.
*
* @return array
* An associative array containing the following keys:
diff --git a/includes/session.inc b/includes/session.inc
index b04c18eb3..16727df6d 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -274,7 +274,7 @@ function drupal_session_initialize() {
}
/**
- * Forcefully starts a session, preserving already set session data.
+ * Starts a session forcefully, preserving already set session data.
*
* @ingroup php_wrappers
*/
diff --git a/includes/tablesort.inc b/includes/tablesort.inc
index 121a1b909..e589526c6 100644
--- a/includes/tablesort.inc
+++ b/includes/tablesort.inc
@@ -55,7 +55,7 @@ class TableSort extends SelectQueryExtender {
}
/**
- * Initialize the table sort context.
+ * Initializes the table sort context.
*/
protected function init() {
$ts = $this->order();
@@ -115,7 +115,7 @@ function tablesort_init($header) {
}
/**
- * Format a column header.
+ * Formats a column header.
*
* If the cell in question is the column header for the current sort criterion,
* it gets special formatting. All possible sort criteria become links.
@@ -126,6 +126,7 @@ function tablesort_init($header) {
* An array of column headers in the format described in theme_table().
* @param $ts
* The current table sort context as returned from tablesort_init().
+ *
* @return
* A properly formatted cell, ready for _theme_table_cell().
*/
@@ -151,7 +152,7 @@ function tablesort_header($cell, $header, $ts) {
}
/**
- * Format a table cell.
+ * Formats a table cell.
*
* Adds a class attribute to all cells in the currently active column.
*
@@ -163,6 +164,7 @@ function tablesort_header($cell, $header, $ts) {
* The current table sort context as returned from tablesort_init().
* @param $i
* The index of the cell's table column.
+ *
* @return
* A properly formatted cell, ready for _theme_table_cell().
*/
@@ -179,7 +181,7 @@ function tablesort_cell($cell, $header, $ts, $i) {
}
/**
- * Compose a URL query parameter array for table sorting links.
+ * Composes a URL query parameter array for table sorting links.
*
* @return
* A URL query parameter array that consists of all components of the current
@@ -190,10 +192,11 @@ function tablesort_get_query_parameters() {
}
/**
- * Determine the current sort criterion.
+ * Determines the current sort criterion.
*
* @param $headers
* An array of column headers in the format described in theme_table().
+ *
* @return
* An associative array describing the criterion, containing the keys:
* - "name": The localized title of the table column.
@@ -226,10 +229,11 @@ function tablesort_get_order($headers) {
}
/**
- * Determine the current sort direction.
+ * Determines the current sort direction.
*
* @param $headers
* An array of column headers in the format described in theme_table().
+ *
* @return
* The current sort direction ("asc" or "desc").
*/
diff --git a/includes/theme.inc b/includes/theme.inc
index 777922f05..4c454ba40 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -65,7 +65,7 @@ function _drupal_theme_access($theme) {
}
/**
- * Initialize the theme system by loading the theme.
+ * Initializes the theme system by loading the theme.
*/
function drupal_theme_initialize() {
global $theme, $user, $theme_key;
@@ -113,8 +113,9 @@ function drupal_theme_initialize() {
}
/**
- * Initialize the theme system given already loaded information. This
- * function is useful to initialize a theme when no database is present.
+ * Initializes the theme system given already loaded information.
+ *
+ * This function is useful to initialize a theme when no database is present.
*
* @param $theme
* An object with the following information:
@@ -235,7 +236,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
}
/**
- * Get the theme registry.
+ * Gets the theme registry.
*
* @param $complete
* Optional boolean to indicate whether to return the complete theme registry
@@ -280,7 +281,7 @@ function theme_get_registry($complete = TRUE) {
}
/**
- * Set the callback that will be used by theme_get_registry() to fetch the registry.
+ * Sets the callback that will be used by theme_get_registry().
*
* @param $callback
* The name of the callback function.
@@ -296,7 +297,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array())
}
/**
- * Get the theme_registry cache; if it doesn't exist, build it.
+ * Gets the theme_registry cache; if it doesn't exist, builds it.
*
* @param $theme
* The loaded $theme object as returned by list_themes().
@@ -336,16 +337,17 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL,
}
/**
- * Write the theme_registry cache into the database.
+ * Writes the theme_registry cache into the database.
*/
function _theme_save_registry($theme, $registry) {
cache_set("theme_registry:$theme->name", $registry);
}
/**
- * Force the system to rebuild the theme registry; this should be called
- * when modules are added to the system, or when a dynamic system needs
- * to add more theme hooks.
+ * Forces the system to rebuild the theme registry.
+ *
+ * This function should be called when modules are added to the system, or when
+ * a dynamic system needs to add more theme hooks.
*/
function drupal_theme_rebuild() {
drupal_static_reset('theme_get_registry');
@@ -635,7 +637,8 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
$cache = $result + $cache;
}
- // Let themes have variable processors even if they didn't register a template.
+ // Let themes have variable processors even if they didn't register a
+ // template.
if ($type == 'theme' || $type == 'base_theme') {
foreach ($cache as $hook => $info) {
// Check only if not registered by the theme or engine.
@@ -662,7 +665,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
}
/**
- * Build the theme registry cache.
+ * Builds the theme registry cache.
*
* @param $theme
* The loaded $theme object as returned by list_themes().
@@ -724,7 +727,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
}
/**
- * Return a list of all currently available themes.
+ * Returns a list of all currently available themes.
*
* Retrieved from the database, if available and the site is not in maintenance
* mode; otherwise compiled freshly from the filesystem.
@@ -900,15 +903,15 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
* executed (if they exist), in the following order (note that in the following
* list, HOOK indicates the theme hook name, MODULE indicates a module name,
* THEME indicates a theme name, and ENGINE indicates a theme engine name):
- * - template_preprocess(&$variables, $hook): Creates a default set of variables
- * for all theme hooks with template implementations.
+ * - template_preprocess(&$variables, $hook): Creates a default set of
+ * variables for all theme hooks with template implementations.
* - template_preprocess_HOOK(&$variables): Should be implemented by the module
* that registers the theme hook, to set up default variables.
* - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
* implementing modules.
* - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
- * all implementing modules, so that modules that didn't define the theme hook
- * can alter the variables.
+ * all implementing modules, so that modules that didn't define the theme
+ * hook can alter the variables.
* - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
* set necessary variables for all theme hooks with template implementations.
* - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
@@ -963,10 +966,10 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
* @param $hook
* The name of the theme hook to call. If the name contains a
* double-underscore ('__') and there isn't an implementation for the full
- * name, the part before the '__' is checked. This allows a fallback to a more
- * generic implementation. For example, if theme('links__node', ...) is
- * called, but there is no implementation of that theme hook, then the 'links'
- * implementation is used. This process is iterative, so if
+ * name, the part before the '__' is checked. This allows a fallback to a
+ * more generic implementation. For example, if theme('links__node', ...) is
+ * called, but there is no implementation of that theme hook, then the
+ * 'links' implementation is used. This process is iterative, so if
* theme('links__contextual__node', ...) is called, theme() checks for the
* following implementations, and uses the first one that exists:
* - links__contextual__node
@@ -1042,7 +1045,8 @@ function theme($hook, $variables = array()) {
// point path_to_theme() to the currently used theme path:
$theme_path = $info['theme path'];
- // Include a file if the theme function or variable processor is held elsewhere.
+ // Include a file if the theme function or variable processor is held
+ // elsewhere.
if (!empty($info['includes'])) {
foreach ($info['includes'] as $include_file) {
include_once DRUPAL_ROOT . '/' . $include_file;
@@ -1191,14 +1195,14 @@ function theme($hook, $variables = array()) {
}
/**
- * Return the path to the current themed element.
- *
- * It can point to the active theme or the module handling a themed implementation.
- * For example, when invoked within the scope of a theming call it will depend
- * on where the theming function is handled. If implemented from a module, it
- * will point to the module. If implemented from the active theme, it will point
- * to the active theme. When called outside the scope of a theming call, it will
- * always point to the active theme.
+ * Returns the path to the current themed element.
+ *
+ * It can point to the active theme or the module handling a themed
+ * implementation. For example, when invoked within the scope of a theming call
+ * it will depend on where the theming function is handled. If implemented from
+ * a module, it will point to the module. If implemented from the active theme,
+ * it will point to the active theme. When called outside the scope of a
+ * theming call, it will always point to the active theme.
*/
function path_to_theme() {
global $theme_path;
@@ -1211,7 +1215,7 @@ function path_to_theme() {
}
/**
- * Allow themes and/or theme engines to easily discover overridden theme functions.
+ * Allows themes and/or theme engines to discover overridden theme functions.
*
* @param $cache
* The existing cache of theme hooks to test against.
@@ -1268,7 +1272,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
}
/**
- * Allow themes and/or theme engines to easily discover overridden templates.
+ * Allows themes and/or theme engines to easily discover overridden templates.
*
* @param $cache
* The existing cache of theme hooks to test against.
@@ -1345,7 +1349,8 @@ function drupal_find_theme_templates($cache, $extension, $path) {
if ($matches) {
foreach ($matches as $match) {
$file = substr($match, 0, strpos($match, '.'));
- // Put the underscores back in for the hook name and register this pattern.
+ // Put the underscores back in for the hook name and register this
+ // pattern.
$arg_name = isset($info['variables']) ? 'variables' : 'render element';
$implementations[strtr($file, '-', '_')] = array(
'template' => $file,
@@ -1361,7 +1366,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
}
/**
- * Retrieve a setting for the current theme or for a given theme.
+ * Retrieves a setting for the current theme or for a given theme.
*
* The final setting is obtained from the last value found in the following
* sources:
@@ -1479,7 +1484,7 @@ function theme_get_setting($setting_name, $theme = NULL) {
}
/**
- * Render a system default template, which is essentially a PHP template.
+ * Renders a system default template, which is essentially a PHP template.
*
* @param $template_file
* The filename of the template to render.
@@ -1490,14 +1495,21 @@ function theme_get_setting($setting_name, $theme = NULL) {
* The output generated by the template.
*/
function theme_render_template($template_file, $variables) {
- extract($variables, EXTR_SKIP); // Extract the variables to a local namespace
- ob_start(); // Start output buffering
- include DRUPAL_ROOT . '/' . $template_file; // Include the template file
- return ob_get_clean(); // End buffering and return its contents
+ // Extract the variables to a local namespace
+ extract($variables, EXTR_SKIP);
+
+ // Start output buffering
+ ob_start();
+
+ // Include the template file
+ include DRUPAL_ROOT . '/' . $template_file;
+
+ // End buffering and return its contents
+ return ob_get_clean();
}
/**
- * Enable a given list of themes.
+ * Enables a given list of themes.
*
* @param $theme_list
* An array of theme names.
@@ -1522,7 +1534,7 @@ function theme_enable($theme_list) {
}
/**
- * Disable a given list of themes.
+ * Disables a given list of themes.
*
* @param $theme_list
* An array of theme names.
@@ -1608,13 +1620,13 @@ function theme_status_messages($variables) {
* theme('link') for rendering the anchor tag.
*
* To optimize performance for sites that don't need custom theming of links,
- * the l() function includes an inline copy of this function, and uses that copy
- * if none of the enabled modules or the active theme implement any preprocess
- * or process functions or override this theme implementation.
+ * the l() function includes an inline copy of this function, and uses that
+ * copy if none of the enabled modules or the active theme implement any
+ * preprocess or process functions or override this theme implementation.
*
* @param $variables
- * An associative array containing the keys 'text', 'path', and 'options'. See
- * the l() function for information about these variables.
+ * An associative array containing the keys 'text', 'path', and 'options'.
+ * See the l() function for information about these variables.
*
* @see l()
*/
@@ -1635,15 +1647,16 @@ function theme_link($variables) {
* item in the links list.
* - html: (optional) Whether or not 'title' is HTML. If set, the title
* will not be passed through check_plain().
- * - attributes: (optional) Attributes for the anchor, or for the <span> tag
- * used in its place if no 'href' is supplied. If element 'class' is
+ * - attributes: (optional) Attributes for the anchor, or for the <span>
+ * tag used in its place if no 'href' is supplied. If element 'class' is
* included, it must be an array of one or more class names.
- * If the 'href' element is supplied, the entire link array is passed to l()
- * as its $options parameter.
+ * If the 'href' element is supplied, the entire link array is passed to
+ * l() as its $options parameter.
* - attributes: A keyed array of attributes for the UL containing the
* list of links.
- * - heading: (optional) A heading to precede the links. May be an associative
- * array or a string. If it's an array, it can have the following elements:
+ * - heading: (optional) A heading to precede the links. May be an
+ * associative array or a string. If it's an array, it can have the
+ * following elements:
* - text: The heading text.
* - level: The heading level (e.g. 'h2', 'h3').
* - class: (optional) An array of the CSS classes for the heading.
@@ -1747,8 +1760,8 @@ function theme_links($variables) {
* attribute to be omitted in some cases. Therefore, this variable defaults
* to an empty string, but can be set to NULL for the attribute to be
* omitted. Usually, neither omission nor an empty string satisfies
- * accessibility requirements, so it is strongly encouraged for code calling
- * theme('image') to pass a meaningful value for this variable.
+ * accessibility requirements, so it is strongly encouraged for code
+ * calling theme('image') to pass a meaningful value for this variable.
* - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
* - http://www.w3.org/TR/xhtml1/dtds.html
* - http://dev.w3.org/html5/spec/Overview.html#alt
@@ -2005,7 +2018,8 @@ function theme_table($variables) {
*
* @param $variables
* An associative array containing:
- * - style: Set to either 'asc' or 'desc', this determines which icon to show.
+ * - style: Set to either 'asc' or 'desc', this determines which icon to
+ * show.
*/
function theme_tablesort_indicator($variables) {
if ($variables['style'] == "asc") {
@@ -2148,7 +2162,8 @@ function theme_feed_icon($variables) {
* - script: To load JavaScript.
* - #attributes: (optional) An array of HTML attributes to apply to the
* tag.
- * - #value: (optional) A string containing tag content, such as inline CSS.
+ * - #value: (optional) A string containing tag content, such as inline
+ * CSS.
* - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
* wrapper prefix.
* - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
@@ -2316,8 +2331,9 @@ function template_preprocess(&$variables, $hook) {
global $user;
static $count = array();
- // Track run count for each hook to provide zebra striping.
- // See "template_preprocess_block()" which provides the same feature specific to blocks.
+ // Track run count for each hook to provide zebra striping. See
+ // "template_preprocess_block()" which provides the same feature specific to
+ // blocks.
$count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1;
$variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
$variables['id'] = $count[$hook]++;
@@ -2677,13 +2693,13 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
}
/**
- * The variables array generated here is a mirror of template_preprocess_page().
- * This preprocessor will run its course when theme_maintenance_page() is
- * invoked.
+ * Process variables for maintenance-page.tpl.php.
*
- * An alternate template file of "maintenance-page--offline.tpl.php" can be
- * used when the database is offline to hide errors and completely replace the
- * content.
+ * The variables array generated here is a mirror of
+ * template_preprocess_page(). This preprocessor will run its course when
+ * theme_maintenance_page() is invoked. An alternate template file of
+ * maintenance-page--offline.tpl.php can be used when the database is offline to
+ * hide errors and completely replace the content.
*
* The $variables array contains the following arguments:
* - $content
@@ -2777,10 +2793,13 @@ function template_preprocess_maintenance_page(&$variables) {
}
/**
+ * Theme process function for theme_maintenance_field().
+ *
* The variables array generated here is a mirror of template_process_html().
* This processor will run its course when theme_maintenance_page() is invoked.
*
* @see maintenance-page.tpl.php
+ * @see template_process_html()
*/
function template_process_maintenance_page(&$variables) {
$variables['head'] = drupal_get_html_head();
@@ -2792,7 +2811,7 @@ function template_process_maintenance_page(&$variables) {
/**
* Preprocess variables for region.tpl.php
*
- * Prepare the values passed to the theme_region function to be passed into a
+ * Prepares the values passed to the theme_region function to be passed into a
* pluggable template engine. Uses the region name to generate a template file
* suggestions. If none are found, the default region.tpl.php is used.
*
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index 218a8adaa..6baf219b0 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -10,9 +10,9 @@
*
* Used for site installs, updates and when the site is in maintenance mode.
* It also applies when the database is unavailable or bootstrap was not
- * complete. Seven is always used for the initial install and update operations.
- * In other cases, Bartik is used, but this can be overridden by setting a
- * "maintenance_theme" key in the $conf variable in settings.php.
+ * complete. Seven is always used for the initial install and update
+ * operations. In other cases, Bartik is used, but this can be overridden by
+ * setting a "maintenance_theme" key in the $conf variable in settings.php.
*/
function _drupal_maintenance_theme() {
global $theme, $theme_key, $conf;
@@ -85,7 +85,7 @@ function _drupal_maintenance_theme() {
}
/**
- * This builds the registry when the site needs to bypass any database calls.
+ * Builds the registry when the site needs to bypass any database calls.
*/
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
return _theme_build_registry($theme, $base_theme, $theme_engine);
@@ -160,7 +160,7 @@ function theme_update_page($variables) {
}
/**
- * Returns HTML for a report of the results from an operation run via authorize.php.
+ * Returns HTML for a results report of an operation run by authorize.php.
*
* @param $variables
* An associative array containing:
diff --git a/includes/token.inc b/includes/token.inc
index 0b05c68f4..402aeae01 100644
--- a/includes/token.inc
+++ b/includes/token.inc
@@ -190,10 +190,10 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
}
/**
- * Given a list of tokens, returns those that begin with a specific prefix.
+ * Returns a list of tokens that begin with a specific prefix.
*
- * Used to extract a group of 'chained' tokens (such as [node:author:name]) from
- * the full list of tokens found in text. For example:
+ * Used to extract a group of 'chained' tokens (such as [node:author:name])
+ * from the full list of tokens found in text. For example:
* @code
* $data = array(
* 'author:name' => '[node:author:name]',
@@ -230,8 +230,10 @@ function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
/**
* Returns metadata describing supported tokens.
*
- * The metadata array contains token type, name, and description data as well as
- * an optional pointer indicating that the token chains to another set of tokens.
+ * The metadata array contains token type, name, and description data as well
+ * as an optional pointer indicating that the token chains to another set of
+ * tokens.
+ *
* For example:
* @code
* $data['types']['node'] = array(
diff --git a/includes/unicode.inc b/includes/unicode.inc
index 81a0a4dfe..fd497cca7 100644
--- a/includes/unicode.inc
+++ b/includes/unicode.inc
@@ -1,6 +1,11 @@
<?php
/**
+* @file
+* Provides Unicode-related conversions and operations.
+*/
+
+/**
* Indicates an error during check for PHP unicode support.
*/
define('UNICODE_ERROR', -1);
@@ -19,8 +24,6 @@ define('UNICODE_MULTIBYTE', 1);
/**
* Matches Unicode characters that are word boundaries.
*
- * @see http://unicode.org/glossary
- *
* Characters with the following General_category (gc) property values are used
* as word boundaries. While this does not fully conform to the Word Boundaries
* algorithm described in http://unicode.org/reports/tr29, as PCRE does not
@@ -39,6 +42,8 @@ define('UNICODE_MULTIBYTE', 1);
* Note that the PCRE property matcher is not used because we wanted to be
* compatible with Unicode 5.2.0 regardless of the PCRE version used (and any
* bugs in PCRE property tables).
+ *
+ * @see http://unicode.org/glossary
*/
define('PREG_CLASS_UNICODE_WORD_BOUNDARY',
'\x{0}-\x{2F}\x{3A}-\x{40}\x{5B}-\x{60}\x{7B}-\x{A9}\x{AB}-\x{B1}\x{B4}' .
@@ -125,7 +130,7 @@ function _unicode_check() {
}
/**
- * Return Unicode library status and errors.
+ * Returns Unicode library status and errors.
*/
function unicode_requirements() {
// Ensure translations don't break during installation.
@@ -157,14 +162,14 @@ function unicode_requirements() {
}
/**
- * Prepare a new XML parser.
+ * Prepares a new XML parser.
*
- * This is a wrapper around xml_parser_create() which extracts the encoding from
- * the XML data first and sets the output encoding to UTF-8. This function should
- * be used instead of xml_parser_create(), because PHP 4's XML parser doesn't
- * check the input encoding itself. "Starting from PHP 5, the input encoding is
- * automatically detected, so that the encoding parameter specifies only the
- * output encoding."
+ * This is a wrapper around xml_parser_create() which extracts the encoding
+ * from the XML data first and sets the output encoding to UTF-8. This function
+ * should be used instead of xml_parser_create(), because PHP 4's XML parser
+ * doesn't check the input encoding itself. "Starting from PHP 5, the input
+ * encoding is automatically detected, so that the encoding parameter specifies
+ * only the output encoding."
*
* This is also where unsupported encodings will be converted. Callers should
* take this into account: $data might have been changed after the call.
@@ -213,7 +218,7 @@ function drupal_xml_parser_create(&$data) {
}
/**
- * Convert data to UTF-8
+ * Converts data to UTF-8.
*
* Requires the iconv, GNU recode or mbstring PHP extension.
*
@@ -244,15 +249,15 @@ function drupal_convert_to_utf8($data, $encoding) {
}
/**
- * Truncate a UTF-8-encoded string safely to a number of bytes.
+ * Truncates a UTF-8-encoded string safely to a number of bytes.
*
* If the end position is in the middle of a UTF-8 sequence, it scans backwards
* until the beginning of the byte sequence.
*
* Use this function whenever you want to chop off a string at an unsure
* location. On the other hand, if you're sure that you're splitting on a
- * character boundary (e.g. after using strpos() or similar), you can safely use
- * substr() instead.
+ * character boundary (e.g. after using strpos() or similar), you can safely
+ * use substr() instead.
*
* @param $string
* The string to truncate.
@@ -306,7 +311,7 @@ function drupal_truncate_bytes($string, $len) {
* boundaries, giving you "See myverylongurl..." (assuming you had set
* $add_ellipses to TRUE).
*
- * @return
+ * @return string
* The truncated string.
*/
function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1) {
@@ -356,8 +361,7 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
}
/**
- * Encodes MIME/HTTP header values that contain non-ASCII, UTF-8 encoded
- * characters.
+ * Encodes MIME/HTTP header values that contain incorrectly encoded characters.
*
* For example, mime_header_encode('tést.txt') returns "=?UTF-8?B?dMOpc3QudHh0?=".
*
@@ -369,6 +373,14 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
* each chunk starts and ends on a character boundary.
* - Using \n as the chunk separator may cause problems on some systems and may
* have to be changed to \r\n or \r.
+ *
+ * @param $string
+ * The header to encode.
+ *
+ * @return string
+ * The mime-encoded header.
+ *
+ * @see mime_header_decode()
*/
function mime_header_encode($string) {
if (preg_match('/[^\x20-\x7E]/', $string)) {
@@ -388,7 +400,15 @@ function mime_header_encode($string) {
}
/**
- * Complement to mime_header_encode
+ * Decodes MIME/HTTP encoded header values.
+ *
+ * @param $header
+ * The header to decode.
+ *
+ * @return string
+ * The mime-decoded header.
+ *
+ * @see mime_header_encode()
*/
function mime_header_decode($header) {
// First step: encoded chunks followed by other encoded chunks (need to collapse whitespace)
@@ -398,7 +418,17 @@ function mime_header_decode($header) {
}
/**
- * Helper function to mime_header_decode
+ * Decodes encoded header data passed from mime_header_decode().
+ *
+ * Callback for preg_replace_callback() within mime_header_decode().
+ *
+ * @param $matches
+ * The array of matches from preg_replace_callback().
+ *
+ * @return string
+ * The mime-decoded string.
+ *
+ * @see mime_header_decode()
*/
function _mime_header_decode($matches) {
// Regexp groups:
@@ -415,9 +445,9 @@ function _mime_header_decode($matches) {
/**
* Decodes all HTML entities (including numerical ones) to regular UTF-8 bytes.
*
- * Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;",
- * not "<"). Be careful when using this function, as decode_entities can revert
- * previous sanitization efforts (&lt;script&gt; will become <script>).
+ * Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;"
+ * , not "<"). Be careful when using this function, as decode_entities can
+ * revert previous sanitization efforts (&lt;script&gt; will become <script>).
*
* @param $text
* The text to decode entities in.
@@ -430,8 +460,15 @@ function decode_entities($text) {
}
/**
- * Count the amount of characters in a UTF-8 string. This is less than or
- * equal to the byte count.
+ * Counts the number of characters in a UTF-8 string.
+ *
+ * This is less than or equal to the byte count.
+ *
+ * @param $text
+ * The string to run the operation on.
+ *
+ * @return integer
+ * The length of the string.
*
* @ingroup php_wrappers
*/
@@ -449,6 +486,12 @@ function drupal_strlen($text) {
/**
* Uppercase a UTF-8 string.
*
+ * @param $text
+ * The string to run the operation on.
+ *
+ * @return string
+ * The string in uppercase.
+ *
* @ingroup php_wrappers
*/
function drupal_strtoupper($text) {
@@ -468,6 +511,12 @@ function drupal_strtoupper($text) {
/**
* Lowercase a UTF-8 string.
*
+ * @param $text
+ * The string to run the operation on.
+ *
+ * @return string
+ * The string in lowercase.
+ *
* @ingroup php_wrappers
*/
function drupal_strtolower($text) {
@@ -485,15 +534,28 @@ function drupal_strtolower($text) {
}
/**
- * Helper function for case conversion of Latin-1.
- * Used for flipping U+C0-U+DE to U+E0-U+FD and back.
+ * Flips U+C0-U+DE to U+E0-U+FD and back.
+ *
+ * @param $matches
+ * An array of matches.
+ *
+ * @return array
+ * The Latin-1 version of the array of matches.
+ *
+ * @see drupal_strtolower()
*/
function _unicode_caseflip($matches) {
return $matches[0][0] . chr(ord($matches[0][1]) ^ 32);
}
/**
- * Capitalize the first letter of a UTF-8 string.
+ * Capitalizes the first letter of a UTF-8 string.
+ *
+ * @param $text
+ * The string to convert.
+ *
+ * @return
+ * The string with the first letter as uppercase.
*
* @ingroup php_wrappers
*/
@@ -503,12 +565,21 @@ function drupal_ucfirst($text) {
}
/**
- * Cut off a piece of a string based on character indices and counts. Follows
- * the same behavior as PHP's own substr() function.
+ * Cuts off a piece of a string based on character indices and counts.
*
- * Note that for cutting off a string at a known character/substring
- * location, the usage of PHP's normal strpos/substr is safe and
- * much faster.
+ * Follows the same behavior as PHP's own substr() function. Note that for
+ * cutting off a string at a known character/substring location, the usage of
+ * PHP's normal strpos/substr is safe and much faster.
+ *
+ * @param $text
+ * The input string.
+ * @param $start
+ * The position at which to start reading.
+ * @param $length
+ * The number of characters to read.
+ *
+ * @return
+ * The shortened string.
*
* @ingroup php_wrappers
*/
diff --git a/includes/update.inc b/includes/update.inc
index 5f1c2331c..a17161c9e 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -38,7 +38,7 @@ function update_fix_compatibility() {
}
/**
- * Helper function to test compatibility of a module or theme.
+ * Tests the compatibility of a module or theme.
*/
function update_check_incompatibility($name, $type = 'module') {
static $themes, $modules;
@@ -908,7 +908,7 @@ function update_get_d6_session_name() {
}
/**
- * Perform one update and store the results for display on finished page.
+ * Performs one update and stores the results for display on the results page.
*
* If an update function completes successfully, it should return a message
* as a string indicating success, for example:
@@ -1008,7 +1008,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
class DrupalUpdateException extends Exception { }
/**
- * Start the database update batch process.
+ * Starts the database update batch process.
*
* @param $start
* An array whose keys contain the names of modules to be updated during the
@@ -1078,7 +1078,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
}
/**
- * Finish the update process and store results for eventual display.
+ * Finishes the update process and stores the results for eventual display.
*
* After the updates run, all caches are flushed. The update results are
* stored into the session (for example, to be displayed on the update results
@@ -1115,7 +1115,7 @@ function update_finished($success, $results, $operations) {
}
/**
- * Return a list of all the pending database updates.
+ * Returns a list of all the pending database updates.
*
* @return
* An associative array keyed by module name which contains all information
@@ -1409,7 +1409,7 @@ function update_already_performed($module, $number) {
}
/**
- * Invoke hook_update_dependencies() in all installed modules.
+ * Invokes hook_update_dependencies() in all installed modules.
*
* This function is similar to module_invoke_all(), with the main difference
* that it does not require that a module be enabled to invoke its hook, only
diff --git a/includes/utility.inc b/includes/utility.inc
index 5019852c7..f651fd631 100644
--- a/includes/utility.inc
+++ b/includes/utility.inc
@@ -12,6 +12,7 @@
* The variable to export.
* @param $prefix
* A prefix that will be added at the beginning of every lines of the output.
+ *
* @return
* The variable exported in a way compatible to Drupal's coding standards.
*/
diff --git a/install.php b/install.php
index 881ca5a82..685d3b4ee 100644
--- a/install.php
+++ b/install.php
@@ -6,12 +6,12 @@
*/
/**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
- * Global flag to indicate that site is in installation mode.
+ * Global flag to indicate the site is in installation mode.
*/
define('MAINTENANCE_MODE', 'install');
diff --git a/modules/aggregator/aggregator-rtl.css b/modules/aggregator/aggregator-rtl.css
index ea59ca3a1..057d01565 100644
--- a/modules/aggregator/aggregator-rtl.css
+++ b/modules/aggregator/aggregator-rtl.css
@@ -1,3 +1,6 @@
+/**
+ * Right-to-Left styles for theme in the Aggregator module.
+ */
#aggregator .feed-source .feed-icon {
float: left;
diff --git a/modules/aggregator/aggregator.admin.inc b/modules/aggregator/aggregator.admin.inc
index 8b817c0fa..443facb12 100644
--- a/modules/aggregator/aggregator.admin.inc
+++ b/modules/aggregator/aggregator.admin.inc
@@ -2,11 +2,11 @@
/**
* @file
- * Admin page callbacks for the aggregator module.
+ * Administration page callbacks for the Aggregator module.
*/
/**
- * Menu callback; displays the aggregator administration page.
+ * Page callback: Displays the Aggregator module administration page.
*/
function aggregator_admin_overview() {
return aggregator_view();
@@ -16,7 +16,7 @@ function aggregator_admin_overview() {
* Displays the aggregator administration page.
*
* @return
- * The page HTML.
+ * A HTML-formatted string with administration page content.
*/
function aggregator_view() {
$result = db_query('SELECT f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block ORDER BY f.title');
@@ -56,8 +56,8 @@ function aggregator_view() {
* Form constructor for adding and editing feed sources.
*
* @param $feed
- * If editing a feed, the feed to edit as a PHP stdClass value; if adding a
- * new feed, NULL.
+ * (optional) If editing a feed, the feed to edit as a PHP stdClass value; if
+ * adding a new feed, NULL. Defaults to NULL.
*
* @ingroup forms
* @see aggregator_form_feed_validate()
@@ -165,6 +165,7 @@ function aggregator_form_feed_validate($form, &$form_state) {
* Form submission handler for aggregator_form_feed().
*
* @see aggregator_form_feed_validate()
+ *
* @todo Add delete confirmation dialog.
*/
function aggregator_form_feed_submit($form, &$form_state) {
@@ -398,7 +399,7 @@ function _aggregator_parse_opml($opml) {
}
/**
- * Menu callback; refreshes a feed, then redirects to the overview page.
+ * Page callback: Refreshes a feed, then redirects to the overview page.
*
* @param $feed
* An object describing the feed to be refreshed.
@@ -590,6 +591,7 @@ function aggregator_form_category_validate($form, &$form_state) {
* Form submission handler for aggregator_form_category().
*
* @see aggregator_form_category_validate()
+ *
* @todo Add delete confirmation dialog.
*/
function aggregator_form_category_submit($form, &$form_state) {
diff --git a/modules/aggregator/aggregator.css b/modules/aggregator/aggregator.css
index 13c58ffe7..4285631e8 100644
--- a/modules/aggregator/aggregator.css
+++ b/modules/aggregator/aggregator.css
@@ -1,3 +1,6 @@
+/**
+ * Styles for theme in the Aggregator module.
+ */
#aggregator .feed-source .feed-title {
margin-top: 0;
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index 93457c68d..70f8c5cd8 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -266,13 +266,13 @@ function aggregator_menu() {
}
/**
- * Title callback: Returns a title for aggregatory category pages.
+ * Title callback: Returns a title for aggregator category pages.
*
* @param $category
* An aggregator category.
*
* @return
- * An aggregator category title.
+ * A string with the aggregator category title.
*/
function _aggregator_category_title($category) {
return $category['title'];
@@ -723,7 +723,7 @@ function theme_aggregator_block_item($variables) {
}
/**
- * Safely renders HTML content, as allowed.
+ * Renders the HTML content safely, as allowed.
*
* @param $value
* The content to be filtered.
@@ -739,7 +739,7 @@ function aggregator_filter_xss($value) {
* Checks and sanitizes the aggregator configuration.
*
* Goes through all fetchers, parsers and processors and checks whether they
- * are available. If one is missing resets to standard configuration.
+ * are available. If one is missing, resets to standard configuration.
*
* @return
* TRUE if this function resets the configuration; FALSE if not.
@@ -775,7 +775,7 @@ function aggregator_sanitize_configuration() {
* Items count.
*
* @return
- * Plural-formatted "@count items"
+ * A string that is plural-formatted as "@count items".
*/
function _aggregator_items($count) {
return format_plural($count, '1 item', '@count items');
diff --git a/modules/aggregator/aggregator.pages.inc b/modules/aggregator/aggregator.pages.inc
index cd1c4cb2c..bfba3fffb 100644
--- a/modules/aggregator/aggregator.pages.inc
+++ b/modules/aggregator/aggregator.pages.inc
@@ -2,14 +2,14 @@
/**
* @file
- * User page callbacks for the aggregator module.
+ * User page callbacks for the Aggregator module.
*/
/**
- * Menu callback; displays the most recent items gathered from any feed.
+ * Page callback: Displays the most recent items gathered from any feed.
*
* @return
- * The items HTML.
+ * The rendered list of items for the feed.
*/
function aggregator_page_last() {
drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
@@ -20,13 +20,15 @@ function aggregator_page_last() {
}
/**
- * Menu callback; displays all the items captured from a particular feed.
+ * Page callback: Displays all the items captured from the particular feed.
*
* @param $feed
* The feed for which to display all items.
*
* @return
* The rendered list of items for a feed.
+ *
+ * @see aggregator_menu()
*/
function aggregator_page_source($feed) {
drupal_set_title($feed->title);
@@ -40,13 +42,13 @@ function aggregator_page_source($feed) {
}
/**
- * Menu callback; displays a form with all items captured from a feed.
+ * Page callback: Displays a form with all items captured from a feed.
*
* @param $feed
- * The feed for which to list all the aggregated items.
+ * The feed for which to list all of the aggregated items.
*
* @return
- * The rendered list of items for a feed.
+ * The rendered list of items for the feed.
*
* @see aggregator_page_source()
*/
@@ -55,13 +57,13 @@ function aggregator_page_source_form($form, $form_state, $feed) {
}
/**
- * Menu callback; displays all the items aggregated in a particular category.
+ * Page callback: Displays all the items aggregated in a particular category.
*
* @param $category
- * The category for which to list all the aggregated items.
+ * The category for which to list all of the aggregated items.
*
* @return
-* The rendered list of items for a category.
+ * The rendered list of items for the feed.
*/
function aggregator_page_category($category) {
drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
@@ -74,13 +76,13 @@ function aggregator_page_category($category) {
}
/**
- * Menu callback; displays a form containing items aggregated in a category.
+ * Page callback: Displays a form containing items aggregated in a category.
*
* @param $category
- * The category for which to list all the aggregated items.
+ * The category for which to list all of the aggregated items.
*
* @return
-* The rendered list of items for a category.
+ * The rendered list of items for the feed.
*
* @see aggregator_page_category()
*/
@@ -166,7 +168,7 @@ function aggregator_feed_items_load($type, $data = NULL) {
* The feed source URL.
*
* @return
- * The rendered list of items for a feed.
+ * The rendered list of items for the feed.
*/
function _aggregator_page_list($items, $op, $feed_source = '') {
if (user_access('administer news feeds') && ($op == 'categorize')) {
@@ -191,10 +193,14 @@ function _aggregator_page_list($items, $op, $feed_source = '') {
* @param $items
* An array of the feed items.
* @param $feed_source
- * The feed source URL.
+ * (optional) The feed source URL. Defaults to an empty string.
+ *
+ * @return array
+ * An array of FAPI elements.
*
- * @ingroup forms
* @see aggregator_categorize_items_submit()
+ * @see theme_aggregator_categorize_items()
+ * @ingroup forms
*/
function aggregator_categorize_items($items, $feed_source = '') {
$form['#submit'][] = 'aggregator_categorize_items_submit';
@@ -334,7 +340,12 @@ function template_preprocess_aggregator_item(&$variables) {
}
/**
- * Menu callback; displays all the feeds used by the aggregator.
+ * Page callback: Displays all the feeds used by the aggregator.
+ *
+ * @return
+ * An HTML-formatted string.
+ *
+ * @see aggregator_menu()
*/
function aggregator_page_sources() {
$result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');
@@ -358,7 +369,12 @@ function aggregator_page_sources() {
}
/**
- * Menu callback; displays all the categories used by the aggregator.
+ * Page callback: Displays all the categories used by the Aggregator module.
+ *
+ * @return string
+ * An HTML formatted string.
+ *
+ * @see aggregator_menu()
*/
function aggregator_page_categories() {
$result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');
@@ -380,7 +396,10 @@ function aggregator_page_categories() {
}
/**
- * Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
+ * Page callback: Generates an RSS 0.92 feed of aggregator items or categories.
+ *
+ * @return string
+ * An HTML formatted string.
*/
function aggregator_page_rss() {
$result = NULL;
@@ -448,12 +467,14 @@ function theme_aggregator_page_rss($variables) {
}
/**
- * Menu callback; generates an OPML representation of all feeds.
+ * Page callback: Generates an OPML representation of all feeds.
*
* @param $cid
- * If set, feeds are exported only from a category with this ID. Otherwise, all feeds are exported.
+ * (optional) If set, feeds are exported only from a category with this ID.
+ * Otherwise, all feeds are exported. Defaults to NULL.
+ *
* @return
- * The output XML.
+ * An OPML formatted string.
*/
function aggregator_page_opml($cid = NULL) {
if ($cid) {
@@ -468,14 +489,12 @@ function aggregator_page_opml($cid = NULL) {
}
/**
- * Prints the OPML page for a feed.
+ * Prints the OPML page for the feed.
*
* @param $variables
* An associative array containing:
* - feeds: An array of the feeds to theme.
*
- * @return void
- *
* @ingroup themeable
*/
function theme_aggregator_page_opml($variables) {
diff --git a/modules/aggregator/aggregator.processor.inc b/modules/aggregator/aggregator.processor.inc
index 3f1319c8c..44ed54996 100644
--- a/modules/aggregator/aggregator.processor.inc
+++ b/modules/aggregator/aggregator.processor.inc
@@ -131,6 +131,12 @@ function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
*
* Callback for drupal_map_assoc() within
* aggregator_form_aggregator_admin_form_alter().
+ *
+ * @param $length
+ * The desired length of teaser text, in bytes.
+ *
+ * @return
+ * A translated string explaining the teaser string length.
*/
function _aggregator_characters($length) {
return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test
index eff31020f..8b95d6e37 100644
--- a/modules/aggregator/aggregator.test
+++ b/modules/aggregator/aggregator.test
@@ -5,6 +5,9 @@
* Tests for aggregator.module.
*/
+/**
+ * Defines a base class for testing the Aggregator module.
+ */
class AggregatorTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('aggregator', 'aggregator_test');
@@ -13,10 +16,15 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Create an aggregator feed (simulate form submission on admin/config/services/aggregator/add/feed).
+ * Creates an aggregator feed.
+ *
+ * This method simulates the form submission on path
+ * admin/config/services/aggregator/add/feed.
*
* @param $feed_url
- * If given, feed will be created with this URL, otherwise /rss.xml will be used.
+ * (optional) If given, feed will be created with this URL, otherwise
+ * /rss.xml will be used. Defaults to NULL.
+ *
* @return $feed
* Full feed object if possible.
*
@@ -33,7 +41,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Delete an aggregator feed.
+ * Deletes an aggregator feed.
*
* @param $feed
* Feed object representing the feed.
@@ -44,10 +52,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Return a randomly generated feed edit array.
+ * Returns a randomly generated feed edit array.
*
* @param $feed_url
- * If given, feed will be created with this URL, otherwise /rss.xml will be used.
+ * (optional) If given, feed will be created with this URL, otherwise
+ * /rss.xml will be used. Defaults to NULL.
* @return
* A feed array.
*/
@@ -68,7 +77,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Return the count of the randomly created feed array.
+ * Returns the count of the randomly created feed array.
*
* @return
* Number of feed items on default feed created by createFeed().
@@ -80,10 +89,13 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Update feed items (simulate click to admin/config/services/aggregator/update/$fid).
+ * Updates the feed items.
+ *
+ * This method simulates a click to
+ * admin/config/services/aggregator/update/$fid.
*
* @param $feed
- * Feed object representing the feed.
+ * Feed object representing the feed, passed by reference.
* @param $expected_count
* Expected number of feed items.
*/
@@ -112,7 +124,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Confirm item removal from a feed.
+ * Confirms an item removal from a feed.
*
* @param $feed
* Feed object representing the feed.
@@ -123,7 +135,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Add and remove feed items and ensure that the count is zero.
+ * Adds and removes feed items and ensure that the count is zero.
*
* @param $feed
* Feed object representing the feed.
@@ -140,7 +152,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Pull feed categories from aggregator_category_feed table.
+ * Pulls feed categories from {aggregator_category_feed} table.
*
* @param $feed
* Feed object representing the feed.
@@ -154,7 +166,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Pull categories from aggregator_category table.
+ * Pulls categories from {aggregator_category} table.
+ *
+ * @return
+ * An associative array keyed by category ID and values are set to the
+ * category names.
*/
function getCategories() {
$categories = array();
@@ -165,14 +181,14 @@ class AggregatorTestCase extends DrupalWebTestCase {
return $categories;
}
-
/**
- * Check if the feed name and URL is unique.
+ * Checks whether the feed name and URL are unique.
*
* @param $feed_name
* String containing the feed name to check.
* @param $feed_url
* String containing the feed URL to check.
+ *
* @return
* TRUE if feed is unique.
*/
@@ -182,10 +198,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
- * Create a valid OPML file from an array of feeds.
+ * Creates a valid OPML file from an array of feeds.
*
* @param $feeds
* An array of feeds.
+ *
* @return
* Path to valid OPML file.
*/
@@ -223,7 +240,7 @@ EOF;
}
/**
- * Create an invalid OPML file.
+ * Creates an invalid OPML file.
*
* @return
* Path to invalid OPML file.
@@ -240,7 +257,7 @@ EOF;
}
/**
- * Create a valid but empty OPML file.
+ * Creates a valid but empty OPML file.
*
* @return
* Path to empty OPML file.
@@ -275,7 +292,7 @@ EOF;
* Creates sample article nodes.
*
* @param $count
- * (optional) The number of nodes to generate.
+ * (optional) The number of nodes to generate. Defaults to five.
*/
function createSampleNodes($count = 5) {
$langcode = LANGUAGE_NONE;
@@ -290,7 +307,7 @@ EOF;
}
/**
- * Tests aggregator configuration settings.
+ * Tests functionality of the configuration settings in the Aggregator module.
*/
class AggregatorConfigurationTestCase extends AggregatorTestCase {
public static function getInfo() {
@@ -321,6 +338,9 @@ class AggregatorConfigurationTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests adding aggregator feeds.
+ */
class AddFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -331,7 +351,7 @@ class AddFeedTestCase extends AggregatorTestCase {
}
/**
- * Create a feed, ensure that it is unique, check the source, and delete the feed.
+ * Creates and ensures that a feed is unique, checks source, and deletes feed.
*/
function testAddFeed() {
$feed = $this->createFeed();
@@ -381,6 +401,9 @@ class AddFeedTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests the categorize feed functionality in the Aggregator module.
+ */
class CategorizeFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -391,7 +414,7 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
}
/**
- * Create a feed and make sure you can add more than one category to it.
+ * Creates a feed and makes sure you can add more than one category to it.
*/
function testCategorizeFeed() {
@@ -424,6 +447,9 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests functionality of updating the feed in the Aggregator module.
+ */
class UpdateFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -434,7 +460,7 @@ class UpdateFeedTestCase extends AggregatorTestCase {
}
/**
- * Create a feed and attempt to update it.
+ * Creates a feed and attempts to update it.
*/
function testUpdateFeed() {
$remamining_fields = array('title', 'url', '');
@@ -466,6 +492,9 @@ class UpdateFeedTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests functionality for removing feeds in the Aggregator module.
+ */
class RemoveFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -476,7 +505,7 @@ class RemoveFeedTestCase extends AggregatorTestCase {
}
/**
- * Remove a feed and ensure that all it services are removed.
+ * Removes a feed and ensures that all of its services are removed.
*/
function testRemoveFeed() {
$feed = $this->createFeed();
@@ -494,6 +523,9 @@ class RemoveFeedTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests functionality of updating a feed item in the Aggregator module.
+ */
class UpdateFeedItemTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -504,7 +536,7 @@ class UpdateFeedItemTestCase extends AggregatorTestCase {
}
/**
- * Test running "update items" from the 'admin/config/services/aggregator' page.
+ * Tests running "update items" from 'admin/config/services/aggregator' page.
*/
function testUpdateFeedItem() {
$this->createSampleNodes();
@@ -564,7 +596,7 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
}
/**
- * Test running "remove items" from the 'admin/config/services/aggregator' page.
+ * Tests running "remove items" from 'admin/config/services/aggregator' page.
*/
function testRemoveFeedItem() {
// Create a bunch of test feeds.
@@ -592,6 +624,9 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests categorization functionality in the Aggregator module.
+ */
class CategorizeFeedItemTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -602,6 +637,8 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
}
/**
+ * Checks that children of a feed inherit a defined category.
+ *
* If a feed has a category, make sure that the children inherit that
* categorization.
*/
@@ -649,6 +686,9 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests importing feeds from OPML functionality for the Aggregator module.
+ */
class ImportOPMLTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -659,7 +699,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
/**
- * Open OPML import form.
+ * Opens OPML import form.
*/
function openImportForm() {
db_delete('aggregator_category')->execute();
@@ -681,7 +721,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
/**
- * Submit form filled with invalid fields.
+ * Submits form filled with invalid fields.
*/
function validateImportFormFields() {
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
@@ -707,7 +747,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
/**
- * Submit form with invalid, empty and valid OPML files.
+ * Submits form with invalid, empty, and valid OPML files.
*/
function submitImportForm() {
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
@@ -766,6 +806,9 @@ class ImportOPMLTestCase extends AggregatorTestCase {
$this->assertTrue($category, 'Categories are correct.');
}
+ /**
+ * Tests the import of an OPML file.
+ */
function testOPMLImport() {
$this->openImportForm();
$this->validateImportFormFields();
@@ -773,6 +816,9 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests functionality of the cron process in the Aggregator module.
+ */
class AggregatorCronTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -783,7 +829,7 @@ class AggregatorCronTestCase extends AggregatorTestCase {
}
/**
- * Add feeds update them on cron.
+ * Adds feeds and updates them via cron process.
*/
public function testCron() {
// Create feed and test basic updating on cron.
@@ -819,6 +865,9 @@ class AggregatorCronTestCase extends AggregatorTestCase {
}
}
+/**
+ * Tests rendering functionality in the Aggregator module.
+ */
class AggregatorRenderingTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -829,9 +878,9 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
- * Add a feed block to the page and checks its links.
+ * Adds a feed block to the page and checks its links.
*
- * TODO: Test the category block as well.
+ * @todo Test the category block as well.
*/
public function testBlockLinks() {
// Create feed.
@@ -890,7 +939,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
- * Create a feed and check that feed's page.
+ * Creates a feed and checks that feed's page.
*/
public function testFeedPage() {
// Increase the number of items published in the rss.xml feed so we have
@@ -913,7 +962,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
- * Tests for feed parsing.
+ * Tests feed parsing in the Aggregator module.
*/
class FeedParserTestCase extends AggregatorTestCase {
public static function getInfo() {
@@ -933,7 +982,7 @@ class FeedParserTestCase extends AggregatorTestCase {
}
/**
- * Test a feed that uses the RSS 0.91 format.
+ * Tests a feed that uses the RSS 0.91 format.
*/
function testRSS091Sample() {
$feed = $this->createFeed($this->getRSS091Sample());
@@ -955,7 +1004,7 @@ class FeedParserTestCase extends AggregatorTestCase {
}
/**
- * Test a feed that uses the Atom format.
+ * Tests a feed that uses the Atom format.
*/
function testAtomSample() {
$feed = $this->createFeed($this->getAtomSample());
diff --git a/modules/book/book-rtl.css b/modules/book/book-rtl.css
index f3a84c20e..40dff0e53 100644
--- a/modules/book/book-rtl.css
+++ b/modules/book/book-rtl.css
@@ -1,3 +1,7 @@
+/**
+ * @file
+ * Right-to-Left styling for the Book module.
+ */
.book-navigation .menu {
padding: 1em 3em 0 0;
diff --git a/modules/book/book.admin.inc b/modules/book/book.admin.inc
index 62c6e841a..cc3f08fc8 100644
--- a/modules/book/book.admin.inc
+++ b/modules/book/book.admin.inc
@@ -2,11 +2,16 @@
/**
* @file
- * Admin page callbacks for the book module.
+ * Administration page callbacks for the Book module.
*/
/**
* Returns an administrative overview of all books.
+ *
+ * @return string
+ * A HTML-formatted string with the administrative page content.
+ *
+ * @see book_menu()
*/
function book_admin_overview() {
$rows = array();
@@ -53,6 +58,8 @@ function book_admin_settings() {
/**
* Form validation handler for book_admin_settings().
+ *
+ * @see book_admin_settings_submit()
*/
function book_admin_settings_validate($form, &$form_state) {
$child_type = $form_state['values']['book_child_type'];
@@ -149,7 +156,7 @@ function book_admin_edit_submit($form, &$form_state) {
* @param $node
* The node of the top-level page in the book.
* @param $form
- * The form that is being modified.
+ * The form that is being modified, passed by reference.
*
* @see book_admin_edit()
*/
@@ -184,10 +191,10 @@ function _book_admin_table($node, &$form) {
* @param $tree
* A subtree of the book menu hierarchy.
* @param $form
- * The form that is being modified.
+ * The form that is being modified, passed by reference.
*
* @return
- * The form that is being modified.
+ * The modified form array.
*
* @see book_admin_edit()
*/
diff --git a/modules/book/book.css b/modules/book/book.css
index a8d2136df..00e379ee0 100644
--- a/modules/book/book.css
+++ b/modules/book/book.css
@@ -1,3 +1,7 @@
+ /**
+ * @file
+ * Styling for the Book module.
+ */
.book-navigation .menu {
border-top: 1px solid #888;
diff --git a/modules/book/book.js b/modules/book/book.js
index 0853e8ecb..64f4aee68 100644
--- a/modules/book/book.js
+++ b/modules/book/book.js
@@ -3,7 +3,6 @@
* Javascript behaviors for the Book module.
*/
-
(function ($) {
Drupal.behaviors.bookFieldsetSummaries = {
diff --git a/modules/book/book.module b/modules/book/book.module
index 1fb0c0b11..71b89945e 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -221,6 +221,9 @@ function _book_outline_remove_access($node) {
*
* A node can be removed from a book if it is actually in a book and it either
* is not a top-level page or is a top-level page with no children.
+ *
+ * @param $node
+ * The node to remove from the outline.
*/
function _book_node_is_removable($node) {
return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children']));
@@ -734,7 +737,7 @@ function book_get_flat_menu($book_link) {
* @param $tree
* A tree of menu links in an array.
* @param $flat
- * A flat array of the menu links from $tree.
+ * A flat array of the menu links from $tree, passed by reference.
*
* @see book_get_flat_menu().
*/
@@ -1062,8 +1065,9 @@ function _book_link_defaults($nid) {
* to the structured data but can also simply iterate over all elements and
* render them (as in the default template).
*
- * The $variables array contains the following elements:
- * - book_menus
+ * @param $variables
+ * An associative array containing the following key:
+ * - book_menus
*
* @see book-all-books-block.tpl.php
*/
@@ -1079,8 +1083,9 @@ function template_preprocess_book_all_books_block(&$variables) {
/**
* Processes variables for book-navigation.tpl.php.
*
- * The $variables array contains the following elements:
- * - book_link
+ * @param $variables
+ * An associative array containing the following key:
+ * - book_link
*
* @see book-navigation.tpl.php
*/
@@ -1151,8 +1156,9 @@ function template_preprocess_book_navigation(&$variables) {
* Reference to the table of contents array. This is modified in place, so the
* function does not have a return value.
* @param $exclude
- * Optional array of menu link ID values. Any link whose menu link ID is in
- * this array will be excluded (along with its children).
+ * (optional) An array of menu link ID values. Any link whose menu link ID is
+ * in this array will be excluded (along with its children). Defaults to an
+ * empty array.
* @param $depth_limit
* Any link deeper than this value will be excluded (along with its children).
*/
@@ -1198,10 +1204,11 @@ function book_toc($bid, $depth_limit, $exclude = array()) {
/**
* Processes variables for book-export-html.tpl.php.
*
- * The $variables array contains the following elements:
- * - title
- * - contents
- * - depth
+ * @param $variables
+ * An associative array containing the following keys:
+ * - title
+ * - contents
+ * - depth
*
* @see book-export-html.tpl.php
*/
@@ -1261,7 +1268,8 @@ function book_export_traverse($tree, $visit_func) {
* @param $node
* The node that will be output.
* @param $children
- * All the rendered child nodes within the current node.
+ * (optional) All the rendered child nodes within the current node. Defaults
+ * to an empty string.
*
* @return
* The HTML generated for the given node.
@@ -1280,9 +1288,10 @@ function book_node_export($node, $children = '') {
/**
* Processes variables for book-node-export-html.tpl.php.
*
- * The $variables array contains the following elements:
- * - node
- * - children
+ * @param $variables
+ * An associative array containing the following keys:
+ * - node
+ * - children
*
* @see book-node-export-html.tpl.php
*/
@@ -1294,6 +1303,12 @@ function template_preprocess_book_node_export_html(&$variables) {
/**
* Determine if a given node type is in the list of types allowed for books.
+ *
+ * @param $type
+ * A node type.
+ *
+ * @return
+ * A Boolean TRUE if the node type can be included in books; otherwise, FALSE.
*/
function book_type_is_allowed($type) {
return in_array($type, variable_get('book_allowed_types', array('book')));
@@ -1336,7 +1351,7 @@ function book_node_type_update($type) {
*
* @return
* A menu link, with the link translated for rendering and data added from the
- * {book} table.
+ * {book} table. FALSE if there is an error.
*/
function book_link_load($mlid) {
if ($item = db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(
diff --git a/modules/book/book.pages.inc b/modules/book/book.pages.inc
index 63a1d15a4..e5a04c5a2 100644
--- a/modules/book/book.pages.inc
+++ b/modules/book/book.pages.inc
@@ -7,6 +7,11 @@
/**
* Menu callback: Prints a listing of all books.
+ *
+ * @return string
+ * A HTML-formatted string with the listing of all books content.
+ *
+ * @see book_menu()
*/
function book_render() {
$book_list = array();
@@ -36,6 +41,8 @@ function book_render() {
* @return
* A string representing the node and its children in the book hierarchy in a
* format determined by the $type parameter.
+ *
+ * @see book_menu()
*/
function book_export($type, $nid) {
// Check that the node exists and that the current user has access to it.
@@ -100,6 +107,11 @@ function book_export_html($nid) {
*
* @param $node
* The book node for which to show the outline.
+ *
+ * @return string
+ * A HTML-formatted string with the outline form for a single node.
+ *
+ * @see book_menu()
*/
function book_outline($node) {
drupal_set_title($node->title);
diff --git a/modules/book/book.test b/modules/book/book.test
index 2708e3674..81f4524ac 100644
--- a/modules/book/book.test
+++ b/modules/book/book.test
@@ -5,14 +5,37 @@
* Tests for book.module.
*/
+/**
+ * Tests the functionality of the Book module.
+ */
class BookTestCase extends DrupalWebTestCase {
+
+ /**
+ * A book node.
+ *
+ * @var object
+ */
protected $book;
- // $book_author is a user with permission to create and edit books.
+
+ /**
+ * A user with permission to create and edit books.
+ *
+ * @var object
+ */
protected $book_author;
- // $web_user is a user with permission to view a book
- // and access the printer-friendly version.
+
+ /**
+ * A user with permission to view a book and access printer-friendly version.
+ *
+ * @var object
+ */
protected $web_user;
- // $admin_user is a user with permission to create and edit books and to administer blocks.
+
+ /**
+ * A user with permission to create and edit books and to administer blocks.
+ *
+ * @var object
+ */
protected $admin_user;
public static function getInfo() {
@@ -36,7 +59,7 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
- * Create a new book with a page hierarchy.
+ * Creates a new book with a page hierarchy.
*/
function createBook() {
// Create new book.
@@ -67,7 +90,7 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
- * Test book functionality through node interfaces.
+ * Tests book functionality through node interfaces.
*/
function testBook() {
// Create new book.
@@ -106,18 +129,20 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
- * Check the outline of sub-pages; previous, up, and next; and printer friendly version.
+ * Checks the outline of sub-pages; previous, up, and next.
+ *
+ * Also checks the printer friendly version of the outline.
*
* @param $node
* Node to check.
* @param $nodes
* Nodes that should be in outline.
* @param $previous
- * Previous link node.
+ * (optional) Previous link node. Defaults to FALSE.
* @param $up
- * Up link node.
+ * (optional) Up link node. Defaults to FALSE.
* @param $next
- * Next link node.
+ * (optional) Next link node. Defaults to FALSE.
* @param $breadcrumb
* The nodes that should be displayed in the breadcrumb.
*/
@@ -129,23 +154,23 @@ class BookTestCase extends DrupalWebTestCase {
// Check outline structure.
if ($nodes !== NULL) {
- $this->assertPattern($this->generateOutlinePattern($nodes), t('Node ' . $number . ' outline confirmed.'));
+ $this->assertPattern($this->generateOutlinePattern($nodes), format_string('Node %number outline confirmed.', array('%number' => $number)));
}
else {
- $this->pass(t('Node ' . $number . ' doesn\'t have outline.'));
+ $this->pass(format_string('Node %number does not have outline.', array('%number' => $number)));
}
// Check previous, up, and next links.
if ($previous) {
- $this->assertRaw(l('‹ ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => array('page-previous'), 'title' => t('Go to previous page')))), t('Previous page link found.'));
+ $this->assertRaw(l('‹ ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => array('page-previous'), 'title' => t('Go to previous page')))), 'Previous page link found.');
}
if ($up) {
- $this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => array('page-up'), 'title' => t('Go to parent page')))), t('Up page link found.'));
+ $this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => array('page-up'), 'title' => t('Go to parent page')))), 'Up page link found.');
}
if ($next) {
- $this->assertRaw(l($next->title . ' ›', 'node/' . $next->nid, array('attributes' => array('class' => array('page-next'), 'title' => t('Go to next page')))), t('Next page link found.'));
+ $this->assertRaw(l($next->title . ' ›', 'node/' . $next->nid, array('attributes' => array('class' => array('page-next'), 'title' => t('Go to next page')))), 'Next page link found.');
}
// Compute the expected breadcrumb.
@@ -163,20 +188,24 @@ class BookTestCase extends DrupalWebTestCase {
}
// Compare expected and got breadcrumbs.
- $this->assertIdentical($expected_breadcrumb, $got_breadcrumb, t('The breadcrumb is correctly displayed on the page.'));
+ $this->assertIdentical($expected_breadcrumb, $got_breadcrumb, 'The breadcrumb is correctly displayed on the page.');
// Check printer friendly version.
$this->drupalGet('book/export/html/' . $node->nid);
- $this->assertText($node->title, t('Printer friendly title found.'));
- $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Printer friendly body found.'));
+ $this->assertText($node->title, 'Printer friendly title found.');
+ $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Printer friendly body found.');
$number++;
}
/**
- * Create a regular expression to check for the sub-nodes in the outline.
+ * Creates a regular expression to check for the sub-nodes in the outline.
+ *
+ * @param array $nodes
+ * An array of nodes to check in outline.
*
- * @param array $nodes Nodes to check in outline.
+ * @return
+ * A regular expression that locates sub-nodes of the outline.
*/
function generateOutlinePattern($nodes) {
$outline = '';
@@ -188,10 +217,12 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
- * Create book node.
+ * Creates a book node.
*
- * @param integer $book_nid Book node id or set to 'new' to create new book.
- * @param integer $parent Parent book reference id.
+ * @param $book_nid
+ * A book node ID or set to 'new' to create a new book.
+ * @param $parent
+ * (optional) Parent book reference ID. Defaults to NULL.
*/
function createBookNode($book_nid, $parent = NULL) {
// $number does not use drupal_static as it should not be reset
@@ -216,7 +247,7 @@ class BookTestCase extends DrupalWebTestCase {
// Check to make sure the book node was created.
$node = $this->drupalGetNodeByTitle($edit['title']);
- $this->assertNotNull(($node === FALSE ? NULL : $node), t('Book node found in database.'));
+ $this->assertNotNull(($node === FALSE ? NULL : $node), 'Book node found in database.');
$number++;
return $node;
@@ -236,28 +267,28 @@ class BookTestCase extends DrupalWebTestCase {
// Make sure each part of the book is there.
foreach ($nodes as $node) {
- $this->assertText($node->title, t('Node title found in printer friendly version.'));
- $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Node body found in printer friendly version.'));
+ $this->assertText($node->title, 'Node title found in printer friendly version.');
+ $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Node body found in printer friendly version.');
}
// Make sure we can't export an unsupported format.
$this->drupalGet('book/export/foobar/' . $this->book->nid);
- $this->assertResponse('404', t('Unsupported export format returned "not found".'));
+ $this->assertResponse('404', 'Unsupported export format returned "not found".');
// Make sure we get a 404 on a not existing book node.
$this->drupalGet('book/export/html/123');
- $this->assertResponse('404', t('Not existing book node returned "not found".'));
+ $this->assertResponse('404', 'Not existing book node returned "not found".');
// Make sure an anonymous user cannot view printer-friendly version.
$this->drupalLogout();
// Load the book and verify there is no printer-friendly version link.
$this->drupalGet('node/' . $this->book->nid);
- $this->assertNoLink(t('Printer-friendly version'), t('Anonymous user is not shown link to printer-friendly version.'));
+ $this->assertNoLink(t('Printer-friendly version'), 'Anonymous user is not shown link to printer-friendly version.');
// Try getting the URL directly, and verify it fails.
$this->drupalGet('book/export/html/' . $this->book->nid);
- $this->assertResponse('403', t('Anonymous user properly forbidden.'));
+ $this->assertResponse('403', 'Anonymous user properly forbidden.');
// Now grant anonymous users permission to view the printer-friendly
// version and verify that node access restrictions still prevent them from
@@ -276,30 +307,30 @@ class BookTestCase extends DrupalWebTestCase {
// Set block title to confirm that the interface is available.
$block_title = $this->randomName(16);
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', array('title' => $block_title), t('Save block'));
- $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
+ $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
// Set the block to a region to confirm block is available.
$edit = array();
$edit['blocks[book_navigation][region]'] = 'footer';
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
- $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
+ $this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
// Give anonymous users the permission 'node test view'.
$edit = array();
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), t("Permission 'node test view' successfully assigned to anonymous users."));
+ $this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
// Test correct display of the block.
$nodes = $this->createBook();
$this->drupalGet('<front>');
- $this->assertText($block_title, t('Book navigation block is displayed.'));
- $this->assertText($this->book->title, t('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
- $this->assertNoText($nodes[0]->title, t('No links to individual book pages are displayed.'));
+ $this->assertText($block_title, 'Book navigation block is displayed.');
+ $this->assertText($this->book->title, format_string('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
+ $this->assertNoText($nodes[0]->title, 'No links to individual book pages are displayed.');
}
/**
- * Test the book navigation block when an access module is enabled.
+ * Tests the book navigation block when an access module is enabled.
*/
function testNavigationBlockOnAccessModuleEnabled() {
$this->drupalLogin($this->admin_user);
@@ -312,19 +343,19 @@ class BookTestCase extends DrupalWebTestCase {
// Set block display to 'Show block only on book pages'.
$edit['book_block_mode'] = 'book pages';
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', $edit, t('Save block'));
- $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
+ $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
// Set the block to a region to confirm block is available.
$edit = array();
$edit['blocks[book_navigation][region]'] = 'footer';
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
- $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
+ $this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
// Give anonymous users the permission 'node test view'.
$edit = array();
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), t('Permission \'node test view\' successfully assigned to anonymous users.'));
+ $this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
// Create a book.
$this->createBook();
@@ -332,12 +363,12 @@ class BookTestCase extends DrupalWebTestCase {
// Test correct display of the block to registered users.
$this->drupalLogin($this->web_user);
$this->drupalGet('node/' . $this->book->nid);
- $this->assertText($block_title, t('Book navigation block is displayed to registered users.'));
+ $this->assertText($block_title, 'Book navigation block is displayed to registered users.');
$this->drupalLogout();
// Test correct display of the block to anonymous users.
$this->drupalGet('node/' . $this->book->nid);
- $this->assertText($block_title, t('Book navigation block is displayed to anonymous users.'));
+ $this->assertText($block_title, 'Book navigation block is displayed to anonymous users.');
}
/**
@@ -350,10 +381,10 @@ class BookTestCase extends DrupalWebTestCase {
// Test access to delete top-level and child book nodes.
$this->drupalGet('node/' . $this->book->nid . '/outline/remove');
- $this->assertResponse('403', t('Deleting top-level book node properly forbidden.'));
+ $this->assertResponse('403', 'Deleting top-level book node properly forbidden.');
$this->drupalPost('node/' . $nodes[4]->nid . '/outline/remove', $edit, t('Remove'));
$node4 = node_load($nodes[4]->nid, NULL, TRUE);
- $this->assertTrue(empty($node4->book), t('Deleting child book node properly allowed.'));
+ $this->assertTrue(empty($node4->book), 'Deleting child book node properly allowed.');
// Delete all child book nodes and retest top-level node deletion.
foreach ($nodes as $node) {
@@ -362,6 +393,6 @@ class BookTestCase extends DrupalWebTestCase {
node_delete_multiple($nids);
$this->drupalPost('node/' . $this->book->nid . '/outline/remove', $edit, t('Remove'));
$node = node_load($this->book->nid, NULL, TRUE);
- $this->assertTrue(empty($node->book), t('Deleting childless top-level book node properly allowed.'));
+ $this->assertTrue(empty($node->book), 'Deleting childless top-level book node properly allowed.');
}
}
diff --git a/modules/comment/comment.admin.inc b/modules/comment/comment.admin.inc
index 4f3d35071..43b53e27a 100644
--- a/modules/comment/comment.admin.inc
+++ b/modules/comment/comment.admin.inc
@@ -98,13 +98,14 @@ function comment_admin_overview($form, &$form_state, $arg) {
// Remove the first node title from the node_titles array and attach to
// the comment.
$comment->node_title = array_shift($node_titles);
+ $comment_body = field_get_items('comment', $comment, 'comment_body');
$options[$comment->cid] = array(
'subject' => array(
'data' => array(
'#type' => 'link',
'#title' => $comment->subject,
'#href' => 'comment/' . $comment->cid,
- '#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body[LANGUAGE_NONE][0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
+ '#options' => array('attributes' => array('title' => truncate_utf8($comment_body[0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
),
),
'author' => theme('username', array('account' => $comment)),
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 4241538a0..46115be04 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -2041,7 +2041,8 @@ function comment_form($form, &$form_state, $comment) {
// Attach fields.
$comment->node_type = 'comment_node_' . $node->type;
- field_attach_form('comment', $comment, $form, $form_state);
+ $langcode = entity_language('comment', $comment);
+ field_attach_form('comment', $comment, $form, $form_state, $langcode);
return $form;
}
@@ -2066,7 +2067,8 @@ function comment_preview($comment) {
$node = node_load($comment->nid);
if (!form_get_errors()) {
- $comment->format = $comment->comment_body[LANGUAGE_NONE][0]['format'];
+ $comment_body = field_get_items('comment', $comment, 'comment_body');
+ $comment->format = $comment_body[0]['format'];
// Attach the user and time information.
if (!empty($comment->name)) {
$account = user_load_by_name($comment->name);
@@ -2190,7 +2192,9 @@ function comment_submit($comment) {
// 1) Filter it into HTML
// 2) Strip out all HTML tags
// 3) Convert entities back to plain-text.
- $comment_body = $comment->comment_body[LANGUAGE_NONE][0];
+ $field = field_info_field('comment_body');
+ $langcode = field_is_translatable('comment', $field) ? entity_language('comment', $comment) : LANGUAGE_NONE;
+ $comment_body = $comment->comment_body[$langcode][0];
if (isset($comment_body['format'])) {
$comment_text = check_markup($comment_body['value'], $comment_body['format']);
}
@@ -2284,8 +2288,16 @@ function template_preprocess_comment(&$variables) {
$variables['comment'] = $comment;
$variables['node'] = $node;
$variables['author'] = theme('username', array('account' => $comment));
+
$variables['created'] = format_date($comment->created);
- $variables['changed'] = format_date($comment->changed);
+
+ // Avoid calling format_date() twice on the same timestamp.
+ if ($comment->changed == $comment->created) {
+ $variables['changed'] = $variables['created'];
+ }
+ else {
+ $variables['changed'] = format_date($comment->changed);
+ }
$variables['new'] = !empty($comment->new) ? t('new') : '';
$variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $comment)) : '';
diff --git a/modules/dblog/dblog-rtl.css b/modules/dblog/dblog-rtl.css
index 282fe971d..0fab8d065 100644
--- a/modules/dblog/dblog-rtl.css
+++ b/modules/dblog/dblog-rtl.css
@@ -1,3 +1,7 @@
+/**
+ * @file
+ * Right-to-Left styling for the Database Logging module.
+ */
.form-item-type,
.form-item-severity {
diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc
index 0655e7564..7c1c0e20f 100644
--- a/modules/dblog/dblog.admin.inc
+++ b/modules/dblog/dblog.admin.inc
@@ -2,14 +2,19 @@
/**
* @file
- * Administrative page callbacks for the dblog module.
+ * Administrative page callbacks for the Database Logging module.
*/
/**
- * Menu callback; displays a listing of log messages.
+ * Page callback: Displays a listing of database log messages.
*
- * Messages are truncated at 56 chars. Full-length message could be viewed at
- * the message details page.
+ * Messages are truncated at 56 chars. Full-length messages can be viewed on the
+ * message details page.
+ *
+ * @see dblog_clear_log_form()
+ * @see dblog_event()
+ * @see dblog_filter_form()
+ * @see dblog_menu()
*
* @ingroup logging_severity_levels
*/
@@ -81,12 +86,18 @@ function dblog_overview() {
}
/**
- * Menu callback; generic function to display a page of the most frequent events.
+ * Page callback: Shows the most frequent log messages of a given event type.
+ *
+ * Messages are not truncated on this page because events detailed herein do not
+ * have links to a detailed view.
+ *
+ * @param string $type
+ * Type of database log events to display (e.g., 'search').
*
- * Messages are not truncated because events from this page have no detail view.
+ * @return array
+ * A build array in the format expected by drupal_render().
*
- * @param $type
- * type of dblog events to display.
+ * @see dblog_menu()
*/
function dblog_top($type) {
@@ -127,7 +138,16 @@ function dblog_top($type) {
}
/**
- * Menu callback; displays details about a log message.
+ * Page callback: Displays details about a specific database log message.
+ *
+ * @param int $id
+ * Unique ID of the database log message.
+ *
+ * @return array|string
+ * If the ID is located in the Database Logging table, a build array in the
+ * format expected by drupal_render(); otherwise, an empty string.
+ *
+ * @see dblog_menu()
*/
function dblog_event($id) {
$severity = watchdog_severity_levels();
@@ -184,7 +204,10 @@ function dblog_event($id) {
}
/**
- * Build query for dblog administration filters based on session.
+ * Builds a query for database log administration filters based on session.
+ *
+ * @return array
+ * An associative array with keys 'where' and 'args'.
*/
function dblog_build_filter_query() {
if (empty($_SESSION['dblog_overview_filter'])) {
@@ -213,9 +236,16 @@ function dblog_build_filter_query() {
);
}
-
/**
- * List dblog administration filters that can be applied.
+ * Creates a list of database log administration filters that can be applied.
+ *
+ * @return array
+ * Associative array of filters. The top-level keys are used as the form
+ * element names for the filters, and the values are arrays with the following
+ * elements:
+ * - title: Title of the filter.
+ * - where: The filter condition.
+ * - options: Array of options for the select list for the filter.
*/
function dblog_filters() {
$filters = array();
@@ -244,7 +274,7 @@ function dblog_filters() {
/**
* Returns HTML for a log message.
*
- * @param $variables
+ * @param array $variables
* An associative array containing:
* - event: An object with at least the message and variables properties.
* - link: (optional) Format message as link, event->wid is required.
@@ -274,11 +304,13 @@ function theme_dblog_message($variables) {
}
/**
- * Return form for dblog administration filters.
+ * Form constructor for the database logging filter form.
*
- * @ingroup forms
- * @see dblog_filter_form_submit()
* @see dblog_filter_form_validate()
+ * @see dblog_filter_form_submit()
+ * @see dblog_overview()
+ *
+ * @ingroup forms
*/
function dblog_filter_form($form) {
$filters = dblog_filters();
@@ -316,12 +348,13 @@ function dblog_filter_form($form) {
'#value' => t('Reset')
);
}
-
return $form;
}
/**
- * Validate result from dblog administration filter form.
+ * Form validation handler for dblog_filter_form().
+ *
+ * @see dblog_filter_form_submit()
*/
function dblog_filter_form_validate($form, &$form_state) {
if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
@@ -330,7 +363,9 @@ function dblog_filter_form_validate($form, &$form_state) {
}
/**
- * Process result from dblog administration filter form.
+ * Form submission handler for dblog_filter_form().
+ *
+ * @see dblog_filter_form_validate()
*/
function dblog_filter_form_submit($form, &$form_state) {
$op = $form_state['values']['op'];
@@ -351,10 +386,10 @@ function dblog_filter_form_submit($form, &$form_state) {
}
/**
- * Return form for dblog clear button.
+ * Form constructor for the form that clears out the log.
*
- * @ingroup forms
* @see dblog_clear_log_submit()
+ * @ingroup forms
*/
function dblog_clear_log_form($form) {
$form['dblog_clear'] = array(
@@ -374,7 +409,7 @@ function dblog_clear_log_form($form) {
}
/**
- * Submit callback: clear database with log messages.
+ * Form submission handler for dblog_clear_log_form().
*/
function dblog_clear_log_submit() {
$_SESSION['dblog_overview_filter'] = array();
diff --git a/modules/dblog/dblog.css b/modules/dblog/dblog.css
index 88f4ba01b..b1278862a 100644
--- a/modules/dblog/dblog.css
+++ b/modules/dblog/dblog.css
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Admin styles for the Database Logging module.
+ */
+
.form-item-type,
.form-item-severity {
float: left; /* LTR */
diff --git a/modules/dblog/dblog.module b/modules/dblog/dblog.module
index d831548c9..9183eed69 100644
--- a/modules/dblog/dblog.module
+++ b/modules/dblog/dblog.module
@@ -4,9 +4,9 @@
* @file
* System monitoring and logging for administrators.
*
- * The dblog module monitors your site and keeps a list of
- * recorded events containing usage and performance data, errors,
- * warnings, and similar operational information.
+ * The Database Logging module monitors your site and keeps a list of recorded
+ * events containing usage and performance data, errors, warnings, and similar
+ * operational information.
*
* @see watchdog()
*/
@@ -96,7 +96,7 @@ function dblog_init() {
/**
* Implements hook_cron().
*
- * Remove expired log messages.
+ * Controls the size of the log table, paring it to 'dblog_row_limit' messages.
*/
function dblog_cron() {
// Cleanup the watchdog table.
@@ -121,6 +121,12 @@ function dblog_cron() {
}
}
+/**
+ * Gathers a list of uniquely defined database log message types.
+ *
+ * @return array
+ * List of uniquely defined database log message types.
+ */
function _dblog_get_message_types() {
$types = array();
@@ -135,7 +141,7 @@ function _dblog_get_message_types() {
/**
* Implements hook_watchdog().
*
- * Note some values may be truncated for database column size restrictions.
+ * Note: Some values may be truncated to meet database column size restrictions.
*/
function dblog_watchdog(array $log_entry) {
Database::getConnection('default', 'default')->insert('watchdog')
@@ -155,7 +161,7 @@ function dblog_watchdog(array $log_entry) {
}
/**
- * Implements hook_form_FORM_ID_alter().
+ * Implements hook_form_FORM_ID_alter() for system_logging_settings().
*/
function dblog_form_system_logging_settings_alter(&$form, $form_state) {
$form['dblog_row_limit'] = array(
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
index ad01e97f5..cd101930d 100644
--- a/modules/dblog/dblog.test
+++ b/modules/dblog/dblog.test
@@ -5,8 +5,23 @@
* Tests for dblog.module.
*/
+/**
+ * Tests logging messages to the database.
+ */
class DBLogTestCase extends DrupalWebTestCase {
+
+ /**
+ * A user with some relevent administrative permissions.
+ *
+ * @var object
+ */
protected $big_user;
+
+ /**
+ * A user without any permissions.
+ *
+ * @var object
+ */
protected $any_user;
public static function getInfo() {
@@ -28,7 +43,11 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
+ * Tests Database Logging module functionality through interfaces.
+ *
+ * First logs in users, then creates database log events, and finally tests
+ * Database Logging module functionality through both the admin and user
+ * interfaces.
*/
function testDBLog() {
// Login the admin user.
@@ -46,12 +65,13 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Verify setting of the dblog row limit.
+ * Verifies setting of the database log row limit.
*
- * @param integer $count Log row limit.
+ * @param int $row_limit
+ * The row limit.
*/
private function verifyRowLimit($row_limit) {
- // Change the dblog row limit.
+ // Change the database log row limit.
$edit = array();
$edit['dblog_row_limit'] = $row_limit;
$this->drupalPost('admin/config/development/logging', $edit, t('Save configuration'));
@@ -66,33 +86,35 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Verify cron applies the dblog row limit.
+ * Verifies that cron correctly applies the database log row limit.
*
- * @param integer $count Log row limit.
+ * @param int $row_limit
+ * The row limit.
*/
private function verifyCron($row_limit) {
// Generate additional log entries.
$this->generateLogEntries($row_limit + 10);
- // Verify dblog row count exceeds row limit.
+ // Verify that the database log row count exceeds the row limit.
$count = db_query('SELECT COUNT(wid) FROM {watchdog}')->fetchField();
$this->assertTrue($count > $row_limit, t('Dblog row count of @count exceeds row limit of @limit', array('@count' => $count, '@limit' => $row_limit)));
- // Run cron job.
+ // Run a cron job.
$this->cronRun();
- // Verify dblog row count equals row limit plus one because cron adds a record after it runs.
+ // Verify that the database log row count equals the row limit plus one
+ // because cron adds a record after it runs.
$count = db_query('SELECT COUNT(wid) FROM {watchdog}')->fetchField();
$this->assertTrue($count == $row_limit + 1, t('Dblog row count of @count equals row limit of @limit plus one', array('@count' => $count, '@limit' => $row_limit)));
}
/**
- * Generate dblog entries.
+ * Generates a number of random database log events.
*
- * @param integer $count
- * Number of log entries to generate.
- * @param $type
- * The type of watchdog entry.
- * @param $severity
- * The severity of the watchdog entry.
+ * @param int $count
+ * Number of watchdog entries to generate.
+ * @param string $type
+ * (optional) The type of watchdog entry. Defaults to 'custom'.
+ * @param int $severity
+ * (optional) The severity of the watchdog entry. Defaults to WATCHDOG_NOTICE.
*/
private function generateLogEntries($count, $type = 'custom', $severity = WATCHDOG_NOTICE) {
global $base_root;
@@ -119,42 +141,43 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Verify the logged in user has the desired access to the various dblog nodes.
+ * Confirms that database log reports are displayed at the correct paths.
*
- * @param integer $response HTTP response code.
+ * @param int $response
+ * (optional) HTTP response code. Defaults to 200.
*/
private function verifyReports($response = 200) {
$quote = '&#039;';
- // View dblog help node.
+ // View the database log help page.
$this->drupalGet('admin/help/dblog');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Database logging'), t('DBLog help was displayed'));
}
- // View dblog report node.
+ // View the database log report page.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Recent log messages'), t('DBLog report was displayed'));
}
- // View dblog page-not-found report node.
+ // View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Top ' . $quote . 'page not found' . $quote . ' errors'), t('DBLog page-not-found report was displayed'));
}
- // View dblog access-denied report node.
+ // View the database log access-denied report page.
$this->drupalGet('admin/reports/access-denied');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Top ' . $quote . 'access denied' . $quote . ' errors'), t('DBLog access-denied report was displayed'));
}
- // View dblog event node.
+ // View the database log event page.
$this->drupalGet('admin/reports/event/1');
$this->assertResponse($response);
if ($response == 200) {
@@ -163,7 +186,7 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Verify events.
+ * Generates and then verifies various types of events.
*/
private function verifyEvents() {
// Invoke events.
@@ -179,14 +202,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Generate and verify user events.
- *
+ * Generates and then verifies some user events.
*/
private function doUser() {
// Set user variables.
$name = $this->randomName();
$pass = user_password();
- // Add user using form to generate add user event (which is not triggered by drupalCreateUser).
+ // Add a user using the form to generate an add user event (which is not
+ // triggered by drupalCreateUser).
$edit = array();
$edit['name'] = $name;
$edit['mail'] = $name . '@example.com';
@@ -195,15 +218,16 @@ class DBLogTestCase extends DrupalWebTestCase {
$edit['status'] = 1;
$this->drupalPost('admin/people/create', $edit, t('Create new account'));
$this->assertResponse(200);
- // Retrieve user object.
+ // Retrieve the user object.
$user = user_load_by_name($name);
$this->assertTrue($user != NULL, t('User @name was loaded', array('@name' => $name)));
- $user->pass_raw = $pass; // Needed by drupalLogin.
+ // pass_raw property is needed by drupalLogin.
+ $user->pass_raw = $pass;
// Login user.
$this->drupalLogin($user);
// Logout user.
$this->drupalLogout();
- // Fetch row ids in watchdog that relate to the user.
+ // Fetch the row IDs in watchdog that relate to the user.
$result = db_query('SELECT wid FROM {watchdog} WHERE uid = :uid', array(':uid' => $user->uid));
foreach ($result as $row) {
$ids[] = $row->wid;
@@ -213,17 +237,18 @@ class DBLogTestCase extends DrupalWebTestCase {
// Login the admin user.
$this->drupalLogin($this->big_user);
- // Delete user.
+ // Delete the user created at the start of this test.
// We need to POST here to invoke batch_process() in the internal browser.
$this->drupalPost('user/' . $user->uid . '/cancel', array('user_cancel_method' => 'user_cancel_reassign'), t('Cancel account'));
- // View the dblog report.
+ // View the database log report.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(200);
- // Verify events were recorded.
+ // Verify that the expected events were recorded.
// Add user.
- // Default display includes name and email address; if too long then email is replaced by three periods.
+ // Default display includes name and email address; if too long, the email
+ // address is replaced by three periods.
$this->assertLogMessage(t('New user: %name (%email).', array('%name' => $name, '%email' => $user->mail)), t('DBLog event was recorded: [add user]'));
// Login user.
$this->assertLogMessage(t('Session opened for %name.', array('%name' => $name)), t('DBLog event was recorded: [login user]'));
@@ -232,7 +257,7 @@ class DBLogTestCase extends DrupalWebTestCase {
// Delete user.
$message = t('Deleted user: %name %email.', array('%name' => $name, '%email' => '<' . $user->mail . '>'));
$message_text = truncate_utf8(filter_xss($message, array()), 56, TRUE, TRUE);
- // Verify full message on details page.
+ // Verify that the full message displays on the details page.
$link = FALSE;
if ($links = $this->xpath('//a[text()="' . html_entity_decode($message_text) . '"]')) {
// Found link with the message text.
@@ -253,7 +278,7 @@ class DBLogTestCase extends DrupalWebTestCase {
$not_found_url = $this->randomName(60);
$this->drupalGet($not_found_url);
$this->assertResponse(404);
- // View dblog page-not-found report page.
+ // View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse(200);
// Check that full-length URL displayed.
@@ -261,9 +286,10 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Generate and verify node events.
+ * Generates and then verifies some node events.
*
- * @param string $type Content type.
+ * @param string $type
+ * A node type (e.g., 'article', 'page' or 'poll').
*/
private function doNode($type) {
// Create user.
@@ -272,61 +298,65 @@ class DBLogTestCase extends DrupalWebTestCase {
// Login user.
$this->drupalLogin($user);
- // Create node using form to generate add content event (which is not triggered by drupalCreateNode).
+ // Create a node using the form in order to generate an add content event
+ // (which is not triggered by drupalCreateNode).
$edit = $this->getContent($type);
$langcode = LANGUAGE_NONE;
$title = $edit["title"];
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
$this->assertResponse(200);
- // Retrieve node object.
+ // Retrieve the node object.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node != NULL, t('Node @title was loaded', array('@title' => $title)));
- // Edit node.
+ // Edit the node.
$edit = $this->getContentUpdate($type);
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->assertResponse(200);
- // Delete node.
+ // Delete the node.
$this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
$this->assertResponse(200);
- // View node (to generate page not found event).
+ // View the node (to generate page not found event).
$this->drupalGet('node/' . $node->nid);
$this->assertResponse(404);
- // View the dblog report (to generate access denied event).
+ // View the database log report (to generate access denied event).
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(403);
// Login the admin user.
$this->drupalLogin($this->big_user);
- // View the dblog report.
+ // View the database log report.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(200);
- // Verify events were recorded.
- // Content added.
+ // Verify that node events were recorded.
+ // Was node content added?
$this->assertLogMessage(t('@type: added %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content added]'));
- // Content updated.
+ // Was node content updated?
$this->assertLogMessage(t('@type: updated %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content updated]'));
- // Content deleted.
+ // Was node content deleted?
$this->assertLogMessage(t('@type: deleted %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content deleted]'));
- // View dblog access-denied report node.
+ // View the database log access-denied report page.
$this->drupalGet('admin/reports/access-denied');
$this->assertResponse(200);
- // Access denied.
+ // Verify that the 'access denied' event was recorded.
$this->assertText(t('admin/reports/dblog'), t('DBLog event was recorded: [access denied]'));
- // View dblog page-not-found report node.
+ // View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse(200);
- // Page not found.
+ // Verify that the 'page not found' event was recorded.
$this->assertText(t('node/@nid', array('@nid' => $node->nid)), t('DBLog event was recorded: [page not found]'));
}
/**
- * Create content based on content type.
+ * Creates random content based on node content type.
*
- * @param string $type Content type.
- * @return array Content.
+ * @param string $type
+ * Node content type (e.g., 'article').
+ *
+ * @return array
+ * Random content needed by various node types.
*/
private function getContent($type) {
$langcode = LANGUAGE_NONE;
@@ -350,10 +380,13 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Create content update based on content type.
+ * Creates random content as an update based on node content type.
+ *
+ * @param string $type
+ * Node content type (e.g., 'article').
*
- * @param string $type Content type.
- * @return array Content.
+ * @return array
+ * Random content needed by various node types.
*/
private function getContentUpdate($type) {
switch ($type) {
@@ -375,11 +408,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Login an admin user, create dblog event, and test clearing dblog functionality through the admin interface.
+ * Tests the addition and clearing of log events through the admin interface.
+ *
+ * Logs in the admin user, creates a database log event, and tests the
+ * functionality of clearing the database log through the admin interface.
*/
protected function testDBLogAddAndClear() {
global $base_root;
- // Get a count of how many watchdog entries there are.
+ // Get a count of how many watchdog entries already exist.
$count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
$log = array(
'type' => 'custom',
@@ -396,27 +432,27 @@ class DBLogTestCase extends DrupalWebTestCase {
);
// Add a watchdog entry.
dblog_watchdog($log);
- // Make sure the table count has actually incremented.
+ // Make sure the table count has actually been incremented.
$this->assertEqual($count + 1, db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), t('dblog_watchdog() added an entry to the dblog :count', array(':count' => $count)));
// Login the admin user.
$this->drupalLogin($this->big_user);
- // Now post to clear the db table.
+ // Post in order to clear the database table.
$this->drupalPost('admin/reports/dblog', array(), t('Clear log messages'));
- // Count rows in watchdog that previously related to the deleted user.
+ // Count the rows in watchdog that previously related to the deleted user.
$count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
$this->assertEqual($count, 0, t('DBLog contains :count records after a clear.', array(':count' => $count)));
}
/**
- * Test the dblog filter on admin/reports/dblog.
+ * Tests the database log filter functionality at admin/reports/dblog.
*/
protected function testFilter() {
$this->drupalLogin($this->big_user);
- // Clear log to ensure that only generated entries are found.
+ // Clear the log to ensure that only generated entries will be found.
db_delete('watchdog')->execute();
- // Generate watchdog entries.
+ // Generate 9 random watchdog entries.
$type_names = array();
$types = array();
for ($i = 0; $i < 3; $i++) {
@@ -432,10 +468,10 @@ class DBLogTestCase extends DrupalWebTestCase {
}
}
- // View the dblog.
+ // View the database log page.
$this->drupalGet('admin/reports/dblog');
- // Confirm all the entries are displayed.
+ // Confirm that all the entries are displayed.
$count = $this->getTypeCount($types);
foreach ($types as $key => $type) {
$this->assertEqual($count[$key], $type['count'], 'Count matched');
@@ -461,8 +497,8 @@ class DBLogTestCase extends DrupalWebTestCase {
$this->assertEqual(array_sum($count), $type_count, 'Count matched');
}
- // Set filter to match each of the three type attributes and confirm the
- // number of entries displayed.
+ // Set the filter to match each of the two filter-type attributes and
+ // confirm the correct number of entries are displayed.
foreach ($types as $key => $type) {
$edit = array(
'type[]' => array($type['type']),
@@ -480,10 +516,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Get the log entry information form the page.
+ * Gets the database log event information from the browser page.
*
- * @return
- * List of entries and their information.
+ * @return array
+ * List of log events where each event is an array with following keys:
+ * - severity: (int) A database log severity constant.
+ * - type: (string) The type of database log event.
+ * - message: (string) The message for this database log event.
+ * - user: (string) The user associated with this database log event.
*/
protected function getLogEntries() {
$entries = array();
@@ -502,11 +542,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Get the count of entries per type.
+ * Gets the count of database log entries by database log event type.
*
- * @param $types
+ * @param array $types
* The type information to compare against.
- * @return
+ *
+ * @return array
* The count of each type keyed by the key of the $types array.
*/
protected function getTypeCount(array $types) {
@@ -524,11 +565,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Get the watchdog severity constant corresponding to the CSS class.
+ * Gets the watchdog severity constant corresponding to the CSS class.
*
- * @param $class
+ * @param string $class
* CSS class attribute.
- * @return
+ *
+ * @return int|null
* The watchdog severity constant or NULL if not found.
*
* @ingroup logging_severity_levels
@@ -557,11 +599,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Extract the text contained by the element.
+ * Extracts the text contained by the XHTML element.
*
- * @param $element
+ * @param SimpleXMLElement $element
* Element to extract text from.
- * @return
+ *
+ * @return string
* Extracted text.
*/
protected function asText(SimpleXMLElement $element) {
@@ -572,21 +615,22 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
- * Assert messages appear on the log overview screen.
+ * Confirms that a log message appears on the database log overview screen.
*
- * This function should be used only for admin/reports/dblog page, because it
- * check for the message link text truncated to 56 characters. Other dblog
- * pages have no detail links so contains a full message text.
+ * This function should only be used for the admin/reports/dblog page, because
+ * it checks for the message link text truncated to 56 characters. Other log
+ * pages have no detail links so they contain the full message text.
*
- * @param $log_message
- * The message to check.
- * @param $message
+ * @param string $log_message
+ * The database log message to check.
+ * @param string $message
* The message to pass to simpletest.
*/
protected function assertLogMessage($log_message, $message) {
$message_text = truncate_utf8(filter_xss($log_message, array()), 56, TRUE, TRUE);
- // After filter_xss() HTML entities should be converted to their characters
- // because assertLink() uses this string in xpath() to query DOM.
+ // After filter_xss(), HTML entities should be converted to their character
+ // equivalents because assertLink() uses this string in xpath() to query the
+ // Document Object Model (DOM).
$this->assertLink(html_entity_decode($message_text), 0, $message);
}
}
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 5f641173e..822f537bc 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -873,7 +873,7 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
- return $element;
+ return array('value' => $element);
}
/**
@@ -1735,11 +1735,14 @@ function hook_field_storage_details_alter(&$details, $field) {
* loaded.
*/
function hook_field_storage_load($entity_type, $entities, $age, $fields, $options) {
- $field_info = field_info_field_by_ids();
$load_current = $age == FIELD_LOAD_CURRENT;
foreach ($fields as $field_id => $ids) {
- $field = $field_info[$field_id];
+ // By the time this hook runs, the relevant field definitions have been
+ // populated and cached in FieldInfo, so calling field_info_field_by_id()
+ // on each field individually is more efficient than loading all fields in
+ // memory upfront with field_info_field_by_ids().
+ $field = field_info_field_by_id($field_id);
$field_name = $field['field_name'];
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 868d7bd75..dec5c20aa 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -283,7 +283,6 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
'language' => NULL,
);
$options += $default_options;
- $field_info = field_info_field_by_ids();
$fields = array();
$grouped_instances = array();
@@ -307,7 +306,7 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
foreach ($instances as $instance) {
$field_id = $instance['field_id'];
$field_name = $instance['field_name'];
- $field = $field_info[$field_id];
+ $field = field_info_field_by_id($field_id);
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Add the field to the list of fields to invoke the hook on.
@@ -614,7 +613,6 @@ function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcod
* non-deleted fields are operated on.
*/
function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) {
- $field_info = field_info_field_by_ids();
$load_current = $age == FIELD_LOAD_CURRENT;
// Merge default options.
@@ -692,7 +690,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
}
// Collect the storage backend if the field has not been loaded yet.
if (!isset($skip_fields[$field_id])) {
- $field = $field_info[$field_id];
+ $field = field_info_field_by_id($field_id);
$storages[$field['storage']['type']][$field_id][] = $load_current ? $id : $vid;
}
}
@@ -709,7 +707,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
_field_invoke_multiple('load', $entity_type, $queried_entities, $age, $null, $options);
// Invoke hook_field_attach_load(): let other modules act on loading the
- // entitiy.
+ // entity.
module_invoke_all('field_attach_load', $entity_type, $queried_entities, $age, $options);
// Build cache data.
diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc
index f9c96c92b..e1acdd53b 100644
--- a/modules/field/field.crud.inc
+++ b/modules/field/field.crud.inc
@@ -319,7 +319,11 @@ function field_read_field($field_name, $include_additional = array()) {
* Reads in fields that match an array of conditions.
*
* @param array $params
- * An array of conditions to match against.
+ * An array of conditions to match against. Keys are columns from the
+ * 'field_config' table, values are conditions to match. Additionally,
+ * conditions on the 'entity_type' and 'bundle' columns from the
+ * 'field_config_instance' table are supported (select fields having an
+ * instance on a given bundle).
* @param array $include_additional
* The default behavior of this function is to not return fields that
* are inactive or have been deleted. Setting
@@ -337,8 +341,21 @@ function field_read_fields($params = array(), $include_additional = array()) {
// Turn the conditions into a query.
foreach ($params as $key => $value) {
+ // Allow filtering on the 'entity_type' and 'bundle' columns of the
+ // field_config_instance table.
+ if ($key == 'entity_type' || $key == 'bundle') {
+ if (empty($fci_join)) {
+ $fci_join = $query->join('field_config_instance', 'fci', 'fc.id = fci.field_id');
+ }
+ $key = 'fci.' . $key;
+ }
+ else {
+ $key = 'fc.' . $key;
+ }
+
$query->condition($key, $value);
}
+
if (!isset($include_additional['include_inactive']) || !$include_additional['include_inactive']) {
$query
->condition('fc.active', 1)
diff --git a/modules/field/field.info b/modules/field/field.info
index f8a331a00..fcdca88e6 100644
--- a/modules/field/field.info
+++ b/modules/field/field.info
@@ -5,6 +5,7 @@ version = VERSION
core = 7.x
files[] = field.module
files[] = field.attach.inc
+files[] = field.info.class.inc
files[] = tests/field.test
dependencies[] = field_sql_storage
required = TRUE
diff --git a/modules/field/field.info.class.inc b/modules/field/field.info.class.inc
new file mode 100644
index 000000000..de50a1bf0
--- /dev/null
+++ b/modules/field/field.info.class.inc
@@ -0,0 +1,668 @@
+<?php
+
+/*
+ * @file
+ * Definition of the FieldInfo class.
+ */
+
+/**
+ * Provides field and instance definitions for the current runtime environment.
+ *
+ * A FieldInfo object is created and statically persisted through the request
+ * by the _field_info_field_cache() function. The object properties act as a
+ * "static cache" of fields and instances definitions.
+ *
+ * The preferred way to access definitions is through the getBundleInstances()
+ * method, which keeps cache entries per bundle, storing both fields and
+ * instances for a given bundle. Fields used in multiple bundles are duplicated
+ * in several cache entries, and are merged into a single list in the memory
+ * cache. Cache entries are loaded for bundles as a whole, optimizing memory
+ * and CPU usage for the most common pattern of iterating over all instances of
+ * a bundle rather than accessing a single instance.
+ *
+ * The getFields() and getInstances() methods, which return all existing field
+ * and instance definitions, are kept mainly for backwards compatibility, and
+ * should be avoided when possible, since they load and persist in memory a
+ * potentially large array of information. In many cases, the lightweight
+ * getFieldMap() method should be preferred.
+ */
+class FieldInfo {
+
+ /**
+ * Lightweight map of fields across entity types and bundles.
+ *
+ * @var array
+ */
+ protected $fieldMap;
+
+ /**
+ * List of $field structures keyed by ID. Includes deleted fields.
+ *
+ * @var array
+ */
+ protected $fieldsById = array();
+
+ /**
+ * Mapping of field names to the ID of the corresponding non-deleted field.
+ *
+ * @var array
+ */
+ protected $fieldIdsByName = array();
+
+ /**
+ * Whether $fieldsById contains all field definitions or a subset.
+ *
+ * @var bool
+ */
+ protected $loadedAllFields = FALSE;
+
+ /**
+ * Separately tracks requested field names or IDs that do not exist.
+ *
+ * @var array
+ */
+ protected $unknownFields = array();
+
+ /**
+ * Instance definitions by bundle.
+ *
+ * @var array
+ */
+ protected $bundleInstances = array();
+
+ /**
+ * Whether $bundleInstances contains all instances definitions or a subset.
+ *
+ * @var bool
+ */
+ protected $loadedAllInstances = FALSE;
+
+ /**
+ * Separately tracks requested bundles that are empty (or do not exist).
+ *
+ * @var array
+ */
+ protected $emptyBundles = array();
+
+ /**
+ * Extra fields by bundle.
+ *
+ * @var array
+ */
+ protected $bundleExtraFields = array();
+
+ /**
+ * Clears the "static" and persistent caches.
+ */
+ public function flush() {
+ $this->fieldMap = NULL;
+
+ $this->fieldsById = array();
+ $this->fieldIdsByName = array();
+ $this->loadedAllFields = FALSE;
+ $this->unknownFields = array();
+
+ $this->bundleInstances = array();
+ $this->loadedAllInstances = FALSE;
+ $this->emptyBundles = array();
+
+ $this->bundleExtraFields = array();
+
+ cache_clear_all('field_info:', 'cache_field', TRUE);
+ }
+
+ /**
+ * Collects a lightweight map of fields across bundles.
+ *
+ * @return
+ * An array keyed by field name. Each value is an array with two entries:
+ * - type: The field type.
+ * - bundles: The bundles in which the field appears, as an array with
+ * entity types as keys and the array of bundle names as values.
+ */
+ public function getFieldMap() {
+ // Read from the "static" cache.
+ if ($this->fieldMap !== NULL) {
+ return $this->fieldMap;
+ }
+
+ // Read from persistent cache.
+ if ($cached = cache_get('field_info:field_map', 'cache_field')) {
+ $map = $cached->data;
+
+ // Save in "static" cache.
+ $this->fieldMap = $map;
+
+ return $map;
+ }
+
+ $map = array();
+
+ $query = db_query('SELECT fc.type, fci.field_name, fci.entity_type, fci.bundle FROM {field_config_instance} fci INNER JOIN {field_config} fc ON fc.id = fci.field_id WHERE fc.active = 1 AND fc.storage_active = 1 AND fc.deleted = 0 AND fci.deleted = 0');
+ foreach ($query as $row) {
+ $map[$row->field_name]['bundles'][$row->entity_type][] = $row->bundle;
+ $map[$row->field_name]['type'] = $row->type;
+ }
+
+ // Save in "static" and persistent caches.
+ $this->fieldMap = $map;
+ cache_set('field_info:field_map', $map, 'cache_field');
+
+ return $map;
+ }
+
+ /**
+ * Returns all active fields, including deleted ones.
+ *
+ * @return
+ * An array of field definitions, keyed by field ID.
+ */
+ public function getFields() {
+ // Read from the "static" cache.
+ if ($this->loadedAllFields) {
+ return $this->fieldsById;
+ }
+
+ // Read from persistent cache.
+ if ($cached = cache_get('field_info:fields', 'cache_field')) {
+ $this->fieldsById = $cached->data;
+ }
+ else {
+ // Collect and prepare fields.
+ foreach (field_read_fields(array(), array('include_deleted' => TRUE)) as $field) {
+ $this->fieldsById[$field['id']] = $this->prepareField($field);
+ }
+
+ // Store in persistent cache.
+ cache_set('field_info:fields', $this->fieldsById, 'cache_field');
+ }
+
+ // Fill the name/ID map.
+ foreach ($this->fieldsById as $field) {
+ if (!$field['deleted']) {
+ $this->fieldIdsByName[$field['field_name']] = $field['id'];
+ }
+ }
+
+ $this->loadedAllFields = TRUE;
+
+ return $this->fieldsById;
+ }
+
+ /**
+ * Retrieves all active, non-deleted instances definitions.
+ *
+ * @param $entity_type
+ * (optional) The entity type.
+ *
+ * @return
+ * If $entity_type is not set, all instances keyed by entity type and bundle
+ * name. If $entity_type is set, all instances for that entity type, keyed
+ * by bundle name.
+ */
+ public function getInstances($entity_type = NULL) {
+ // If the full list is not present in "static" cache yet.
+ if (!$this->loadedAllInstances) {
+
+ // Read from persistent cache.
+ if ($cached = cache_get('field_info:instances', 'cache_field')) {
+ $this->bundleInstances = $cached->data;
+ }
+ else {
+ // Collect and prepare instances.
+
+ // We also need to populate the static field cache, since it will not
+ // be set by subsequent getBundleInstances() calls.
+ $this->getFields();
+
+ // Initialize empty arrays for all existing entity types and bundles.
+ // This is not strictly needed, but is done to preserve the behavior of
+ // field_info_instances() before http://drupal.org/node/1880666.
+ foreach (field_info_bundles() as $existing_entity_type => $bundles) {
+ foreach ($bundles as $bundle => $bundle_info) {
+ $this->bundleInstances[$existing_entity_type][$bundle] = array();
+ }
+ }
+
+ foreach (field_read_instances() as $instance) {
+ $field = $this->getField($instance['field_name']);
+ $instance = $this->prepareInstance($instance, $field['type']);
+ $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
+ }
+
+ // Store in persistent cache.
+ cache_set('field_info:instances', $this->bundleInstances, 'cache_field');
+ }
+
+ $this->loadedAllInstances = TRUE;
+ }
+
+ if (isset($entity_type)) {
+ return isset($this->bundleInstances[$entity_type]) ? $this->bundleInstances[$entity_type] : array();
+ }
+ else {
+ return $this->bundleInstances;
+ }
+ }
+
+ /**
+ * Returns a field definition from a field name.
+ *
+ * This method only retrieves active, non-deleted fields.
+ *
+ * @param $field_name
+ * The field name.
+ *
+ * @return
+ * The field definition, or NULL if no field was found.
+ */
+ public function getField($field_name) {
+ // Read from the "static" cache.
+ if (isset($this->fieldIdsByName[$field_name])) {
+ $field_id = $this->fieldIdsByName[$field_name];
+ return $this->fieldsById[$field_id];
+ }
+ if (isset($this->unknownFields[$field_name])) {
+ return;
+ }
+
+ // Do not check the (large) persistent cache, but read the definition.
+
+ // Cache miss: read from definition.
+ if ($field = field_read_field($field_name)) {
+ $field = $this->prepareField($field);
+
+ // Save in the "static" cache.
+ $this->fieldsById[$field['id']] = $field;
+ $this->fieldIdsByName[$field['field_name']] = $field['id'];
+
+ return $field;
+ }
+ else {
+ $this->unknownFields[$field_name] = TRUE;
+ }
+ }
+
+ /**
+ * Returns a field definition from a field ID.
+ *
+ * This method only retrieves active fields, deleted or not.
+ *
+ * @param $field_id
+ * The field ID.
+ *
+ * @return
+ * The field definition, or NULL if no field was found.
+ */
+ public function getFieldById($field_id) {
+ // Read from the "static" cache.
+ if (isset($this->fieldsById[$field_id])) {
+ return $this->fieldsById[$field_id];
+ }
+ if (isset($this->unknownFields[$field_id])) {
+ return;
+ }
+
+ // No persistent cache, fields are only persistently cached as part of a
+ // bundle.
+
+ // Cache miss: read from definition.
+ if ($fields = field_read_fields(array('id' => $field_id), array('include_deleted' => TRUE))) {
+ $field = current($fields);
+ $field = $this->prepareField($field);
+
+ // Store in the static cache.
+ $this->fieldsById[$field['id']] = $field;
+ if (!$field['deleted']) {
+ $this->fieldIdsByName[$field['field_name']] = $field['id'];
+ }
+
+ return $field;
+ }
+ else {
+ $this->unknownFields[$field_id] = TRUE;
+ }
+ }
+
+ /**
+ * Retrieves the instances for a bundle.
+ *
+ * The function also populates the corresponding field definitions in the
+ * "static" cache.
+ *
+ * @param $entity_type
+ * The entity type.
+ * @param $bundle
+ * The bundle name.
+ *
+ * @return
+ * The array of instance definitions, keyed by field name.
+ */
+ public function getBundleInstances($entity_type, $bundle) {
+ // Read from the "static" cache.
+ if (isset($this->bundleInstances[$entity_type][$bundle])) {
+ return $this->bundleInstances[$entity_type][$bundle];
+ }
+ if (isset($this->emptyBundles[$entity_type][$bundle])) {
+ return array();
+ }
+
+ // Read from the persistent cache.
+ if ($cached = cache_get("field_info:bundle:$entity_type:$bundle", 'cache_field')) {
+ $info = $cached->data;
+
+ // Extract the field definitions and save them in the "static" cache.
+ foreach ($info['fields'] as $field) {
+ if (!isset($this->fieldsById[$field['id']])) {
+ $this->fieldsById[$field['id']] = $field;
+ if (!$field['deleted']) {
+ $this->fieldIdsByName[$field['field_name']] = $field['id'];
+ }
+ }
+ }
+ unset($info['fields']);
+
+ // Store the instance definitions in the "static" cache'. Empty (or
+ // non-existent) bundles are stored separately, so that they do not
+ // pollute the global list returned by getInstances().
+ if ($info['instances']) {
+ $this->bundleInstances[$entity_type][$bundle] = $info['instances'];
+ }
+ else {
+ $this->emptyBundles[$entity_type][$bundle] = TRUE;
+ }
+
+ return $info['instances'];
+ }
+
+ // Cache miss: collect from the definitions.
+
+ $instances = array();
+
+ // Collect the fields in the bundle.
+ $params = array('entity_type' => $entity_type, 'bundle' => $bundle);
+ $fields = field_read_fields($params);
+
+ // This iterates on non-deleted instances, so deleted fields are kept out of
+ // the persistent caches.
+ foreach (field_read_instances($params) as $instance) {
+ $field = $fields[$instance['field_name']];
+
+ $instance = $this->prepareInstance($instance, $field['type']);
+ $instances[$field['field_name']] = $instance;
+
+ // If the field is not in our global "static" list yet, add it.
+ if (!isset($this->fieldsById[$field['id']])) {
+ $field = $this->prepareField($field);
+
+ $this->fieldsById[$field['id']] = $field;
+ $this->fieldIdsByName[$field['field_name']] = $field['id'];
+ }
+ }
+
+ // Store in the 'static' cache'. Empty (or non-existent) bundles are stored
+ // separately, so that they do not pollute the global list returned by
+ // getInstances().
+ if ($instances) {
+ $this->bundleInstances[$entity_type][$bundle] = $instances;
+ }
+ else {
+ $this->emptyBundles[$entity_type][$bundle] = TRUE;
+ }
+
+ // The persistent cache additionally contains the definitions of the fields
+ // involved in the bundle.
+ $cache = array(
+ 'instances' => $instances,
+ 'fields' => array()
+ );
+ foreach ($instances as $instance) {
+ $cache['fields'][] = $this->fieldsById[$instance['field_id']];
+ }
+ cache_set("field_info:bundle:$entity_type:$bundle", $cache, 'cache_field');
+
+ return $instances;
+ }
+
+ /**
+ * Retrieves the "extra fields" for a bundle.
+ *
+ * @param $entity_type
+ * The entity type.
+ * @param $bundle
+ * The bundle name.
+ *
+ * @return
+ * The array of extra fields.
+ */
+ public function getBundleExtraFields($entity_type, $bundle) {
+ // Read from the "static" cache.
+ if (isset($this->bundleExtraFields[$entity_type][$bundle])) {
+ return $this->bundleExtraFields[$entity_type][$bundle];
+ }
+
+ // Read from the persistent cache.
+ if ($cached = cache_get("field_info:bundle_extra:$entity_type:$bundle", 'cache_field')) {
+ $this->bundleExtraFields[$entity_type][$bundle] = $cached->data;
+ return $this->bundleExtraFields[$entity_type][$bundle];
+ }
+
+ // Cache miss: read from hook_field_extra_fields(). Note: given the current
+ // shape of the hook, we have no other way than collecting extra fields on
+ // all bundles.
+ $info = array();
+ $extra = module_invoke_all('field_extra_fields');
+ drupal_alter('field_extra_fields', $extra);
+ // Merge in saved settings.
+ if (isset($extra[$entity_type][$bundle])) {
+ $info = $this->prepareExtraFields($extra[$entity_type][$bundle], $entity_type, $bundle);
+ }
+
+ // Store in the 'static' and persistent caches.
+ $this->bundleExtraFields[$entity_type][$bundle] = $info;
+ cache_set("field_info:bundle_extra:$entity_type:$bundle", $info, 'cache_field');
+
+ return $this->bundleExtraFields[$entity_type][$bundle];
+ }
+
+ /**
+ * Prepares a field definition for the current run-time context.
+ *
+ * @param $field
+ * The raw field structure as read from the database.
+ *
+ * @return
+ * The field definition completed for the current runtime context.
+ */
+ public function prepareField($field) {
+ // Make sure all expected field settings are present.
+ $field['settings'] += field_info_field_settings($field['type']);
+ $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
+
+ // Add storage details.
+ $details = (array) module_invoke($field['storage']['module'], 'field_storage_details', $field);
+ drupal_alter('field_storage_details', $details, $field);
+ $field['storage']['details'] = $details;
+
+ // Populate the list of bundles using the field.
+ $field['bundles'] = array();
+ if (!$field['deleted']) {
+ $map = $this->getFieldMap();
+ if (isset($map[$field['field_name']])) {
+ $field['bundles'] = $map[$field['field_name']]['bundles'];
+ }
+ }
+
+ return $field;
+ }
+
+ /**
+ * Prepares an instance definition for the current run-time context.
+ *
+ * @param $instance
+ * The raw instance structure as read from the database.
+ * @param $field_type
+ * The field type.
+ *
+ * @return
+ * The field instance array completed for the current runtime context.
+ */
+ public function prepareInstance($instance, $field_type) {
+ // Make sure all expected instance settings are present.
+ $instance['settings'] += field_info_instance_settings($field_type);
+
+ // Set a default value for the instance.
+ if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance['default_value'])) {
+ $instance['default_value'] = NULL;
+ }
+
+ // Prepare widget settings.
+ $instance['widget'] = $this->prepareInstanceWidget($instance['widget'], $field_type);
+
+ // Prepare display settings.
+ foreach ($instance['display'] as $view_mode => $display) {
+ $instance['display'][$view_mode] = $this->prepareInstanceDisplay($display, $field_type);
+ }
+
+ // Fall back to 'hidden' for view modes configured to use custom display
+ // settings, and for which the instance has no explicit settings.
+ $entity_info = entity_get_info($instance['entity_type']);
+ $view_modes = array_merge(array('default'), array_keys($entity_info['view modes']));
+ $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
+ foreach ($view_modes as $view_mode) {
+ if ($view_mode == 'default' || !empty($view_mode_settings[$view_mode]['custom_settings'])) {
+ if (!isset($instance['display'][$view_mode])) {
+ $instance['display'][$view_mode] = array(
+ 'type' => 'hidden',
+ 'label' => 'above',
+ 'settings' => array(),
+ 'weight' => 0,
+ );
+ }
+ }
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Prepares widget properties for the current run-time context.
+ *
+ * @param $widget
+ * Widget specifications as found in $instance['widget'].
+ * @param $field_type
+ * The field type.
+ *
+ * @return
+ * The widget properties completed for the current runtime context.
+ */
+ public function prepareInstanceWidget($widget, $field_type) {
+ $field_type_info = field_info_field_types($field_type);
+
+ // Fill in default values.
+ $widget += array(
+ 'type' => $field_type_info['default_widget'],
+ 'settings' => array(),
+ 'weight' => 0,
+ );
+
+ $widget_type_info = field_info_widget_types($widget['type']);
+ // Fall back to default formatter if formatter type is not available.
+ if (!$widget_type_info) {
+ $widget['type'] = $field_type_info['default_widget'];
+ $widget_type_info = field_info_widget_types($widget['type']);
+ }
+ $widget['module'] = $widget_type_info['module'];
+ // Fill in default settings for the widget.
+ $widget['settings'] += field_info_widget_settings($widget['type']);
+
+ return $widget;
+ }
+
+ /**
+ * Adapts display specifications to the current run-time context.
+ *
+ * @param $display
+ * Display specifications as found in $instance['display']['a_view_mode'].
+ * @param $field_type
+ * The field type.
+ *
+ * @return
+ * The display properties completed for the current runtime context.
+ */
+ public function prepareInstanceDisplay($display, $field_type) {
+ $field_type_info = field_info_field_types($field_type);
+
+ // Fill in default values.
+ $display += array(
+ 'label' => 'above',
+ 'type' => $field_type_info['default_formatter'],
+ 'settings' => array(),
+ 'weight' => 0,
+ );
+ if ($display['type'] != 'hidden') {
+ $formatter_type_info = field_info_formatter_types($display['type']);
+ // Fall back to default formatter if formatter type is not available.
+ if (!$formatter_type_info) {
+ $display['type'] = $field_type_info['default_formatter'];
+ $formatter_type_info = field_info_formatter_types($display['type']);
+ }
+ $display['module'] = $formatter_type_info['module'];
+ // Fill in default settings for the formatter.
+ $display['settings'] += field_info_formatter_settings($display['type']);
+ }
+
+ return $display;
+ }
+
+ /**
+ * Prepares 'extra fields' for the current run-time context.
+ *
+ * @param $extra_fields
+ * The array of extra fields, as collected in hook_field_extra_fields().
+ * @param $entity_type
+ * The entity type.
+ * @param $bundle
+ * The bundle name.
+ *
+ * @return
+ * The list of extra fields completed for the current runtime context.
+ */
+ public function prepareExtraFields($extra_fields, $entity_type, $bundle) {
+ $entity_type_info = entity_get_info($entity_type);
+ $bundle_settings = field_bundle_settings($entity_type, $bundle);
+ $extra_fields += array('form' => array(), 'display' => array());
+
+ $result = array();
+ // Extra fields in forms.
+ foreach ($extra_fields['form'] as $name => $field_data) {
+ $settings = isset($bundle_settings['extra_fields']['form'][$name]) ? $bundle_settings['extra_fields']['form'][$name] : array();
+ if (isset($settings['weight'])) {
+ $field_data['weight'] = $settings['weight'];
+ }
+ $result['form'][$name] = $field_data;
+ }
+
+ // Extra fields in displayed entities.
+ $data = $extra_fields['display'];
+ foreach ($extra_fields['display'] as $name => $field_data) {
+ $settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
+ $view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
+ foreach ($view_modes as $view_mode) {
+ if (isset($settings[$view_mode])) {
+ $field_data['display'][$view_mode] = $settings[$view_mode];
+ }
+ else {
+ $field_data['display'][$view_mode] = array(
+ 'weight' => $field_data['weight'],
+ 'visible' => TRUE,
+ );
+ }
+ }
+ unset($field_data['weight']);
+ $result['display'][$name] = $field_data;
+ }
+
+ return $result;
+ }
+}
diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc
index 9e7ab938d..77113957d 100644
--- a/modules/field/field.info.inc
+++ b/modules/field/field.info.inc
@@ -6,6 +6,32 @@
*/
/**
+ * Retrieves the FieldInfo object for the current request.
+ *
+ * @return FieldInfo
+ * An instance of the FieldInfo class.
+ */
+function _field_info_field_cache() {
+ // Use the advanced drupal_static() pattern, since this is called very often.
+ static $drupal_static_fast;
+
+ if (!isset($drupal_static_fast)) {
+ $drupal_static_fast['field_info_field_cache'] = &drupal_static(__FUNCTION__);
+ }
+ $field_info = &$drupal_static_fast['field_info_field_cache'];
+
+ if (!isset($field_info)) {
+ // @todo The registry should save the need for an explicit include, but not
+ // a couple upgrade tests (DisabledNodeTypeTestCase,
+ // FilterFormatUpgradePathTestCase...) break in a strange way without it.
+ include_once dirname(__FILE__) . '/field.info.class.inc';
+ $field_info = new FieldInfo();
+ }
+
+ return $field_info;
+}
+
+/**
* @defgroup field_info Field Info API
* @{
* Obtain information about Field API configuration.
@@ -34,7 +60,50 @@ function field_info_cache_clear() {
entity_info_cache_clear();
_field_info_collate_types(TRUE);
- _field_info_collate_fields(TRUE);
+ _field_info_field_cache()->flush();
+}
+
+/**
+ * Collates all information on existing fields and instances.
+ *
+ * Deprecated. This function is kept to ensure backwards compatibility, but has
+ * a serious performance impact, and should be absolutely avoided.
+ * See http://drupal.org/node/1880666.
+ *
+ * Use the regular field_info_*() API functions to access the information, or
+ * field_info_cache_clear() to clear the cached data.
+ */
+function _field_info_collate_fields($reset = FALSE) {
+ if ($reset) {
+ _field_info_field_cache()->flush();
+ return;
+ }
+
+ $cache = _field_info_field_cache();
+
+ // Collect fields, and build the array of IDs keyed by field_name.
+ $fields = $cache->getFields();
+ $field_ids = array();
+ foreach ($fields as $id => $field) {
+ if (!$field['deleted']) {
+ $field_ids[$field['field_name']] = $id;
+ }
+ }
+
+ // Collect extra fields for all entity types.
+ $extra_fields = array();
+ foreach (field_info_bundles() as $entity_type => $bundles) {
+ foreach ($bundles as $bundle => $info) {
+ $extra_fields[$entity_type][$bundle] = $cache->getBundleExtraFields($entity_type, $bundle);
+ }
+ }
+
+ return array(
+ 'fields' => $fields,
+ 'field_ids' => $field_ids,
+ 'instances' => $cache->getInstances(),
+ 'extra_fields' => $extra_fields,
+ );
}
/**
@@ -162,281 +231,68 @@ function _field_info_collate_types($reset = FALSE) {
}
/**
- * Collates all information on existing fields and instances.
- *
- * @param $reset
- * If TRUE, clear the cache. The information will be rebuilt from the
- * database next time it is needed. Defaults to FALSE.
- *
- * @return
- * If $reset is TRUE, nothing.
- * If $reset is FALSE, an array containing the following elements:
- * - fields: Array of existing fields, keyed by field ID. This element
- * lists deleted and non-deleted fields, but not inactive ones.
- * Each field has an additional element, 'bundles', which is an array
- * of all non-deleted instances of that field.
- * - field_ids: Array of field IDs, keyed by field name. This element
- * only lists non-deleted, active fields.
- * - instances: Array of existing instances, keyed by entity type, bundle
- * name and field name. This element only lists non-deleted instances
- * whose field is active.
- */
-function _field_info_collate_fields($reset = FALSE) {
- static $info;
-
- if ($reset) {
- $info = NULL;
- cache_clear_all('field_info_fields', 'cache_field');
- return;
- }
-
- if (!isset($info)) {
- if ($cached = cache_get('field_info_fields', 'cache_field')) {
- $info = $cached->data;
- }
- else {
- $definitions = array(
- 'field_ids' => field_read_fields(array(), array('include_deleted' => 1)),
- 'instances' => field_read_instances(),
- );
-
- // Populate 'fields' with all fields, keyed by ID.
- $info['fields'] = array();
- foreach ($definitions['field_ids'] as $key => $field) {
- $info['fields'][$key] = $definitions['field_ids'][$key] = _field_info_prepare_field($field);
- }
-
- // Build an array of field IDs for non-deleted fields, keyed by name.
- $info['field_ids'] = array();
- foreach ($info['fields'] as $key => $field) {
- if (!$field['deleted']) {
- $info['field_ids'][$field['field_name']] = $key;
- }
- }
-
- // Populate 'instances'. Only non-deleted instances are considered.
- $info['instances'] = array();
- foreach (field_info_bundles() as $entity_type => $bundles) {
- foreach ($bundles as $bundle => $bundle_info) {
- $info['instances'][$entity_type][$bundle] = array();
- }
- }
- foreach ($definitions['instances'] as $instance) {
- $field = $info['fields'][$instance['field_id']];
- $instance = _field_info_prepare_instance($instance, $field);
- $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
- // Enrich field definitions with the list of bundles where they have
- // instances. NOTE: Deleted fields in $info['field_ids'] are not
- // enriched because all of their instances are deleted, too, and
- // are thus not in $definitions['instances'].
- $info['fields'][$instance['field_id']]['bundles'][$instance['entity_type']][] = $instance['bundle'];
- }
-
- // Populate 'extra_fields'.
- $extra = module_invoke_all('field_extra_fields');
- drupal_alter('field_extra_fields', $extra);
- // Merge in saved settings.
- foreach ($extra as $entity_type => $bundles) {
- foreach ($bundles as $bundle => $extra_fields) {
- $extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
- $info['extra_fields'][$entity_type][$bundle] = $extra_fields;
- }
- }
-
- cache_set('field_info_fields', $info, 'cache_field');
- }
- }
-
- return $info;
-}
-
-/**
* Prepares a field definition for the current run-time context.
*
- * Since the field was last saved or updated, new field settings can be
- * expected.
+ * The functionality has moved to the FieldInfo class. This function is kept as
+ * a backwards-compatibility layer. See http://drupal.org/node/1880666.
*
- * @param $field
- * The raw field structure as read from the database.
+ * @see FieldInfo::prepareField()
*/
function _field_info_prepare_field($field) {
- // Make sure all expected field settings are present.
- $field['settings'] += field_info_field_settings($field['type']);
- $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
-
- // Add storage details.
- $details = (array) module_invoke($field['storage']['module'], 'field_storage_details', $field);
- drupal_alter('field_storage_details', $details, $field, $instance);
- $field['storage']['details'] = $details;
-
- // Initialize the 'bundles' list.
- $field['bundles'] = array();
-
- return $field;
+ $cache = _field_info_field_cache();
+ return $cache->prepareField($field);
}
/**
* Prepares an instance definition for the current run-time context.
*
- * Since the instance was last saved or updated, a number of things might have
- * changed: widgets or formatters disabled, new settings expected, new view
- * modes added...
- *
- * @param $instance
- * The raw instance structure as read from the database.
- * @param $field
- * The field structure for the instance.
+ * The functionality has moved to the FieldInfo class. This function is kept as
+ * a backwards-compatibility layer. See http://drupal.org/node/1880666.
*
- * @return
- * Field instance array.
+ * @see FieldInfo::prepareInstance()
*/
function _field_info_prepare_instance($instance, $field) {
- // Make sure all expected instance settings are present.
- $instance['settings'] += field_info_instance_settings($field['type']);
-
- // Set a default value for the instance.
- if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance['default_value'])) {
- $instance['default_value'] = NULL;
- }
-
- $instance['widget'] = _field_info_prepare_instance_widget($field, $instance['widget']);
-
- foreach ($instance['display'] as $view_mode => $display) {
- $instance['display'][$view_mode] = _field_info_prepare_instance_display($field, $display);
- }
-
- // Fallback to 'hidden' for view modes configured to use custom display
- // settings, and for which the instance has no explicit settings.
- $entity_info = entity_get_info($instance['entity_type']);
- $view_modes = array_merge(array('default'), array_keys($entity_info['view modes']));
- $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
- foreach ($view_modes as $view_mode) {
- if ($view_mode == 'default' || !empty($view_mode_settings[$view_mode]['custom_settings'])) {
- if (!isset($instance['display'][$view_mode])) {
- $instance['display'][$view_mode] = array(
- 'type' => 'hidden',
- 'label' => 'above',
- 'settings' => array(),
- 'weight' => 0,
- );
- }
- }
- }
-
- return $instance;
+ $cache = _field_info_field_cache();
+ return $cache->prepareInstance($instance, $field['type']);
}
/**
* Adapts display specifications to the current run-time context.
*
- * @param $field
- * The field structure for the instance.
- * @param $display
- * Display specifications as found in
- * $instance['display']['some_view_mode'].
+ * The functionality has moved to the FieldInfo class. This function is kept as
+ * a backwards-compatibility layer. See http://drupal.org/node/1880666.
+ *
+ * @see FieldInfo::prepareInstanceDisplay()
*/
function _field_info_prepare_instance_display($field, $display) {
- $field_type = field_info_field_types($field['type']);
-
- // Fill in default values.
- $display += array(
- 'label' => 'above',
- 'type' => $field_type['default_formatter'],
- 'settings' => array(),
- 'weight' => 0,
- );
- if ($display['type'] != 'hidden') {
- $formatter_type = field_info_formatter_types($display['type']);
- // Fallback to default formatter if formatter type is not available.
- if (!$formatter_type) {
- $display['type'] = $field_type['default_formatter'];
- $formatter_type = field_info_formatter_types($display['type']);
- }
- $display['module'] = $formatter_type['module'];
- // Fill in default settings for the formatter.
- $display['settings'] += field_info_formatter_settings($display['type']);
- }
-
- return $display;
+ $cache = _field_info_field_cache();
+ return $cache->prepareInstanceDisplay($display, $field['type']);
}
/**
* Prepares widget specifications for the current run-time context.
*
- * @param $field
- * The field structure for the instance.
- * @param $widget
- * Widget specifications as found in $instance['widget'].
+ * The functionality has moved to the FieldInfo class. This function is kept as
+ * a backwards-compatibility layer. See http://drupal.org/node/1880666.
+ *
+ * @see FieldInfo::prepareInstanceWidget()
*/
function _field_info_prepare_instance_widget($field, $widget) {
- $field_type = field_info_field_types($field['type']);
-
- // Fill in default values.
- $widget += array(
- 'type' => $field_type['default_widget'],
- 'settings' => array(),
- 'weight' => 0,
- );
-
- $widget_type = field_info_widget_types($widget['type']);
- // Fallback to default formatter if formatter type is not available.
- if (!$widget_type) {
- $widget['type'] = $field_type['default_widget'];
- $widget_type = field_info_widget_types($widget['type']);
- }
- $widget['module'] = $widget_type['module'];
- // Fill in default settings for the widget.
- $widget['settings'] += field_info_widget_settings($widget['type']);
-
- return $widget;
+ $cache = _field_info_field_cache();
+ return $cache->prepareInstanceWidget($widget, $field['type']);
}
/**
* Prepares 'extra fields' for the current run-time context.
*
- * @param $extra_fields
- * The array of extra fields, as collected in hook_field_extra_fields().
- * @param $entity_type
- * The entity type.
- * @param $bundle
- * The bundle name.
+ * The functionality has moved to the FieldInfo class. This function is kept as
+ * a backwards-compatibility layer. See http://drupal.org/node/1880666.
+ *
+ * @see FieldInfo::prepareExtraFields()
*/
function _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle) {
- $entity_type_info = entity_get_info($entity_type);
- $bundle_settings = field_bundle_settings($entity_type, $bundle);
- $extra_fields += array('form' => array(), 'display' => array());
-
- $result = array();
- // Extra fields in forms.
- foreach ($extra_fields['form'] as $name => $field_data) {
- $settings = isset($bundle_settings['extra_fields']['form'][$name]) ? $bundle_settings['extra_fields']['form'][$name] : array();
- if (isset($settings['weight'])) {
- $field_data['weight'] = $settings['weight'];
- }
- $result['form'][$name] = $field_data;
- }
-
- // Extra fields in displayed entities.
- $data = $extra_fields['display'];
- foreach ($extra_fields['display'] as $name => $field_data) {
- $settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
- $view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
- foreach ($view_modes as $view_mode) {
- if (isset($settings[$view_mode])) {
- $field_data['display'][$view_mode] = $settings[$view_mode];
- }
- else {
- $field_data['display'][$view_mode] = array(
- 'weight' => $field_data['weight'],
- 'visible' => TRUE,
- );
- }
- }
- unset($field_data['weight']);
- $result['display'][$name] = $field_data;
- }
-
- return $result;
+ $cache = _field_info_field_cache();
+ return $cache->prepareExtraFields($extra_fields, $entity_type, $bundle);
}
/**
@@ -584,21 +440,50 @@ function field_info_bundles($entity_type = NULL) {
}
/**
+ * Returns a lightweight map of fields across bundles.
+ *
+ * The function only returns active, non deleted fields.
+ *
+ * @return
+ * An array keyed by field name. Each value is an array with two entries:
+ * - type: The field type.
+ * - bundles: The bundles in which the field appears, as an array with entity
+ * types as keys and the array of bundle names as values.
+ */
+function field_info_field_map() {
+ $cache = _field_info_field_cache();
+ return $cache->getFieldMap();
+}
+
+/**
* Returns all field definitions.
*
+ * Use of this function should be avoided when possible, since it loads and
+ * statically caches a potentially large array of information. Use
+ * field_info_field_map() instead.
+ *
+ * When iterating over the fields present in a given bundle after a call to
+ * field_info_instances($entity_type, $bundle), it is recommended to use
+ * field_info_field() on each individual field instead.
+ *
* @return
* An array of field definitions, keyed by field name. Each field has an
* additional property, 'bundles', which is an array of all the bundles to
* which this field belongs keyed by entity type.
+ *
+ * @see field_info_field_map()
*/
function field_info_fields() {
+ $cache = _field_info_field_cache();
+ $info = $cache->getFields();
+
$fields = array();
- $info = _field_info_collate_fields();
- foreach ($info['fields'] as $key => $field) {
+ foreach ($info as $key => $field) {
if (!$field['deleted']) {
$fields[$field['field_name']] = $field;
}
}
+
return $fields;
}
@@ -620,10 +505,8 @@ function field_info_fields() {
* @see field_info_field_by_id()
*/
function field_info_field($field_name) {
- $info = _field_info_collate_fields();
- if (isset($info['field_ids'][$field_name])) {
- return $info['fields'][$info['field_ids'][$field_name]];
- }
+ $cache = _field_info_field_cache();
+ return $cache->getField($field_name);
}
/**
@@ -641,17 +524,19 @@ function field_info_field($field_name) {
* @see field_info_field()
*/
function field_info_field_by_id($field_id) {
- $info = _field_info_collate_fields();
- if (isset($info['fields'][$field_id])) {
- return $info['fields'][$field_id];
- }
+ $cache = _field_info_field_cache();
+ return $cache->getFieldById($field_id);
}
/**
* Returns the same data as field_info_field_by_id() for every field.
*
- * This function is typically used when handling all fields of some entities
- * to avoid thousands of calls to field_info_field_by_id().
+ * Use of this function should be avoided when possible, since it loads and
+ * statically caches a potentially large array of information.
+ *
+ * When iterating over the fields present in a given bundle after a call to
+ * field_info_instances($entity_type, $bundle), it is recommended to use
+ * field_info_field() on each individual field instead.
*
* @return
* An array, each key is a field ID and the values are field arrays as
@@ -662,41 +547,57 @@ function field_info_field_by_id($field_id) {
* @see field_info_field_by_id()
*/
function field_info_field_by_ids() {
- $info = _field_info_collate_fields();
- return $info['fields'];
+ $cache = _field_info_field_cache();
+ return $cache->getFields();
}
/**
* Retrieves information about field instances.
*
+ * Use of this function to retrieve instances across separate bundles (i.e.
+ * when the $bundle parameter is NULL) should be avoided when possible, since
+ * it loads and statically caches a potentially large array of information. Use
+ * field_info_field_map() instead.
+ *
+ * When retrieving the instances of a specific bundle (i.e. when both
+ * $entity_type and $bundle_name are provided), the function also populates a
+ * static cache with the corresponding field definitions, allowing fast
+ * retrieval of field_info_field() later in the request.
+ *
* @param $entity_type
- * The entity type for which to return instances.
+ * (optional) The entity type for which to return instances.
* @param $bundle_name
- * The bundle name for which to return instances.
+ * (optional) The bundle name for which to return instances. If $entity_type
+ * is NULL, the $bundle_name parameter is ignored.
*
* @return
* If $entity_type is not set, return all instances keyed by entity type and
* bundle name. If $entity_type is set, return all instances for that entity
* type, keyed by bundle name. If $entity_type and $bundle_name are set, return
* all instances for that bundle.
+ *
+ * @see field_info_field_map()
*/
function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
- $info = _field_info_collate_fields();
+ $cache = _field_info_field_cache();
- if (isset($entity_type) && isset($bundle_name)) {
- return isset($info['instances'][$entity_type][$bundle_name]) ? $info['instances'][$entity_type][$bundle_name] : array();
+ if (!isset($entity_type)) {
+ return $cache->getInstances();
}
- elseif (isset($entity_type)) {
- return isset($info['instances'][$entity_type]) ? $info['instances'][$entity_type] : array();
- }
- else {
- return $info['instances'];
+ if (!isset($bundle_name)) {
+ return $cache->getInstances($entity_type);
}
+
+ return $cache->getBundleInstances($entity_type, $bundle_name);
}
/**
* Returns an array of instance data for a specific field and bundle.
*
+ * The function populates a static cache with all fields and instances used in
+ * the bundle, allowing fast retrieval of field_info_field() or
+ * field_info_instance() later in the request.
+ *
* @param $entity_type
* The entity type for the instance.
* @param $field_name
@@ -709,9 +610,10 @@ function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
* NULL if the instance does not exist.
*/
function field_info_instance($entity_type, $field_name, $bundle_name) {
- $info = _field_info_collate_fields();
- if (isset($info['instances'][$entity_type][$bundle_name][$field_name])) {
- return $info['instances'][$entity_type][$bundle_name][$field_name];
+ $cache = _field_info_field_cache();
+ $info = $cache->getBundleInstances($entity_type, $bundle_name);
+ if (isset($info[$field_name])) {
+ return $info[$field_name];
}
}
@@ -769,11 +671,10 @@ function field_info_instance($entity_type, $field_name, $bundle_name) {
* The array of pseudo-field elements in the bundle.
*/
function field_info_extra_fields($entity_type, $bundle, $context) {
- $info = _field_info_collate_fields();
- if (isset($info['extra_fields'][$entity_type][$bundle][$context])) {
- return $info['extra_fields'][$entity_type][$bundle][$context];
- }
- return array();
+ $cache = _field_info_field_cache();
+ $info = $cache->getBundleExtraFields($entity_type, $bundle);
+
+ return isset($info[$context]) ? $info[$context] : array();
}
/**
diff --git a/modules/field/field.install b/modules/field/field.install
index 34d28073d..a4b153481 100644
--- a/modules/field/field.install
+++ b/modules/field/field.install
@@ -460,5 +460,12 @@ function field_update_7002() {
}
/**
+ * Add the FieldInfo class to the class registry.
+ */
+function field_update_7003() {
+ // Empty update to force a rebuild of the registry.
+}
+
+/**
* @} End of "addtogroup updates-7.x-extra".
*/
diff --git a/modules/field/field.module b/modules/field/field.module
index b6cf05c9b..4331cdf42 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -873,7 +873,8 @@ function field_view_field($entity_type, $entity, $field_name, $display = array()
if ($field = field_info_field($field_name)) {
if (is_array($display)) {
// When using custom display settings, fill in default values.
- $display = _field_info_prepare_instance_display($field, $display);
+ $cache = _field_info_field_cache();
+ $display = $cache->prepareInstanceDisplay($display, $field["type"]);
}
// Hook invocations are done through the _field_invoke() functions in
@@ -1197,7 +1198,7 @@ function _element_validate_integer($element, &$form_state) {
* Use element_validate_integer_positive() instead.
*
* @deprecated
- * @see element_validate_number_positive()
+ * @see element_validate_integer_positive()
*/
function _element_validate_integer_positive($element, &$form_state) {
element_validate_integer_positive($element, $form_state);
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module b/modules/field/modules/field_sql_storage/field_sql_storage.module
index a75619427..c639f38f2 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -324,11 +324,14 @@ function field_sql_storage_field_storage_delete_field($field) {
* Implements hook_field_storage_load().
*/
function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fields, $options) {
- $field_info = field_info_field_by_ids();
$load_current = $age == FIELD_LOAD_CURRENT;
foreach ($fields as $field_id => $ids) {
- $field = $field_info[$field_id];
+ // By the time this hook runs, the relevant field definitions have been
+ // populated and cached in FieldInfo, so calling field_info_field_by_id()
+ // on each field individually is more efficient than loading all fields in
+ // memory upfront with field_info_field_by_ids().
+ $field = field_info_field_by_id($field_id);
$field_name = $field['field_name'];
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index 8004178eb..9cd8535b5 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -1144,6 +1144,16 @@ class FieldInfoTestCase extends FieldTestCase {
$this->assertIdentical($instances, $expected, "field_info_instances('user') returns " . var_export($expected, TRUE) . '.');
$instances = field_info_instances('user', 'user');
$this->assertIdentical($instances, array(), "field_info_instances('user', 'user') returns an empty array.");
+
+ // Test that querying for invalid entity types does not add entries in the
+ // list returned by field_info_instances().
+ field_info_cache_clear();
+ field_info_instances('invalid_entity', 'invalid_bundle');
+ // Simulate new request by clearing static caches.
+ drupal_static_reset();
+ field_info_instances('invalid_entity', 'invalid_bundle');
+ $instances = field_info_instances();
+ $this->assertFalse(isset($instances['invalid_entity']), 'field_info_instances() does not contain entries for the invalid entity type that was queried before');
}
/**
@@ -1254,6 +1264,80 @@ class FieldInfoTestCase extends FieldTestCase {
}
/**
+ * Test field_info_field_map().
+ */
+ function testFieldMap() {
+ // We will overlook fields created by the 'standard' install profile.
+ $exclude = field_info_field_map();
+
+ // Create a new bundle for 'test_entity' entity type.
+ field_test_create_bundle('test_bundle_2');
+
+ // Create a couple fields.
+ $fields = array(
+ array(
+ 'field_name' => 'field_1',
+ 'type' => 'test_field',
+ ),
+ array(
+ 'field_name' => 'field_2',
+ 'type' => 'hidden_test_field',
+ ),
+ );
+ foreach ($fields as $field) {
+ field_create_field($field);
+ }
+
+ // Create a couple instances.
+ $instances = array(
+ array(
+ 'field_name' => 'field_1',
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ ),
+ array(
+ 'field_name' => 'field_1',
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle_2',
+ ),
+ array(
+ 'field_name' => 'field_2',
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ ),
+ array(
+ 'field_name' => 'field_2',
+ 'entity_type' => 'test_cacheable_entity',
+ 'bundle' => 'test_bundle',
+ ),
+ );
+ foreach ($instances as $instance) {
+ field_create_instance($instance);
+ }
+
+ $expected = array(
+ 'field_1' => array(
+ 'type' => 'test_field',
+ 'bundles' => array(
+ 'test_entity' => array('test_bundle', 'test_bundle_2'),
+ ),
+ ),
+ 'field_2' => array(
+ 'type' => 'hidden_test_field',
+ 'bundles' => array(
+ 'test_entity' => array('test_bundle'),
+ 'test_cacheable_entity' => array('test_bundle'),
+ ),
+ ),
+ );
+
+ // Check that the field map is correct.
+ $map = field_info_field_map();
+ $map = array_diff_key($map, $exclude);
+ $this->assertEqual($map, $expected);
+ }
+
+ /**
* Test that the field_info settings convenience functions work.
*/
function testSettingsInfo() {
@@ -1277,6 +1361,31 @@ class FieldInfoTestCase extends FieldTestCase {
$this->assertIdentical(field_info_formatter_settings($type), $data['settings'], "field_info_formatter_settings returns {$type}'s formatter settings");
}
}
+
+ /**
+ * Tests that the field info cache can be built correctly.
+ */
+ function testFieldInfoCache() {
+ // Create a test field and ensure it's in the array returned by
+ // field_info_fields().
+ $field_name = drupal_strtolower($this->randomName());
+ $field = array(
+ 'field_name' => $field_name,
+ 'type' => 'test_field',
+ );
+ field_create_field($field);
+ $fields = field_info_fields();
+ $this->assertTrue(isset($fields[$field_name]), 'The test field is initially found in the array returned by field_info_fields().');
+
+ // Now rebuild the field info cache, and set a variable which will cause
+ // the cache to be cleared while it's being rebuilt; see
+ // field_test_entity_info(). Ensure the test field is still in the returned
+ // array.
+ field_info_cache_clear();
+ variable_set('field_test_clear_info_cache_in_hook_entity_info', TRUE);
+ $fields = field_info_fields();
+ $this->assertTrue(isset($fields[$field_name]), 'The test field is found in the array returned by field_info_fields() even if its cache is cleared while being rebuilt.');
+ }
}
class FieldFormTestCase extends FieldTestCase {
@@ -2179,6 +2288,41 @@ class FieldCrudTestCase extends FieldTestCase {
}
/**
+ * Tests reading field definitions.
+ */
+ function testReadFields() {
+ $field_definition = array(
+ 'field_name' => 'field_1',
+ 'type' => 'test_field',
+ );
+ field_create_field($field_definition);
+
+ // Check that 'single column' criteria works.
+ $fields = field_read_fields(array('field_name' => $field_definition['field_name']));
+ $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
+
+ // Check that 'multi column' criteria works.
+ $fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => $field_definition['type']));
+ $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
+ $fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => 'foo'));
+ $this->assertTrue(empty($fields), 'No field was found.');
+
+ // Create an instance of the field.
+ $instance_definition = array(
+ 'field_name' => $field_definition['field_name'],
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ );
+ field_create_instance($instance_definition);
+
+ // Check that criteria spanning over the field_config_instance table work.
+ $fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'bundle' => $instance_definition['bundle']));
+ $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
+ $fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'field_name' => $instance_definition['field_name']));
+ $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
+ }
+
+ /**
* Test creation of indexes on data column.
*/
function testFieldIndexes() {
diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc
index 95af3eeba..c6686ebc2 100644
--- a/modules/field/tests/field_test.entity.inc
+++ b/modules/field/tests/field_test.entity.inc
@@ -9,6 +9,12 @@
* Implements hook_entity_info().
*/
function field_test_entity_info() {
+ // If requested, clear the field cache while this hook is being called. See
+ // testFieldInfoCache().
+ if (variable_get('field_test_clear_info_cache_in_hook_entity_info', FALSE)) {
+ field_info_cache_clear();
+ }
+
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
$test_entity_modes = array(
'full' => array(
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index 44770acb9..43bb20276 100644
--- a/modules/field_ui/field_ui.admin.inc
+++ b/modules/field_ui/field_ui.admin.inc
@@ -1534,7 +1534,7 @@ function field_ui_existing_field_options($entity_type, $bundle) {
// - locked fields,
// - fields already in the current bundle,
// - fields that cannot be added to the entity type,
- // - fields that that shoud not be added via user interface.
+ // - fields that should not be added via user interface.
if (empty($field['locked'])
&& !field_info_instance($entity_type, $field['field_name'], $bundle)
@@ -1544,7 +1544,7 @@ function field_ui_existing_field_options($entity_type, $bundle) {
'type' => $field['type'],
'type_label' => $field_types[$field['type']]['label'],
'field' => $field['field_name'],
- 'label' => t($instance['label']),
+ 'label' => $instance['label'],
'widget_type' => $instance['widget']['type'],
);
}
diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module
index 93cbcccc7..5f8bc45ef 100644
--- a/modules/field_ui/field_ui.module
+++ b/modules/field_ui/field_ui.module
@@ -332,23 +332,30 @@ function _field_ui_bundle_admin_path($entity_type, $bundle_name) {
* Identifies inactive fields within a bundle.
*/
function field_ui_inactive_instances($entity_type, $bundle_name = NULL) {
- if (!empty($bundle_name)) {
- $inactive = array($bundle_name => array());
- $params = array('bundle' => $bundle_name);
+ $params = array('entity_type' => $entity_type);
+
+ if (empty($bundle_name)) {
+ $active = field_info_instances($entity_type);
+ $inactive = array();
}
else {
- $inactive = array();
- $params = array();
+ // Restrict to the specified bundle. For consistency with the case where
+ // $bundle_name is NULL, the $active and $inactive arrays are keyed by
+ // bundle name first.
+ $params['bundle'] = $bundle_name;
+ $active = array($bundle_name => field_info_instances($entity_type, $bundle_name));
+ $inactive = array($bundle_name => array());
}
- $params['entity_type'] = $entity_type;
- $active_instances = field_info_instances($entity_type);
+ // Iterate on existing definitions, and spot those that do not appear in the
+ // $active list collected earlier.
$all_instances = field_read_instances($params, array('include_inactive' => TRUE));
foreach ($all_instances as $instance) {
- if (!isset($active_instances[$instance['bundle']][$instance['field_name']])) {
+ if (!isset($active[$instance['bundle']][$instance['field_name']])) {
$inactive[$instance['bundle']][$instance['field_name']] = $instance;
}
}
+
if (!empty($bundle_name)) {
return $inactive[$bundle_name];
}
diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test
index d0a822a82..b67b70e2a 100644
--- a/modules/field_ui/field_ui.test
+++ b/modules/field_ui/field_ui.test
@@ -269,7 +269,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
*/
function assertFieldSettings($bundle, $field_name, $string = 'dummy test string', $entity_type = 'node') {
// Reset the fields info.
- _field_info_collate_fields(TRUE);
+ field_info_cache_clear();
// Assert field settings.
$field = field_info_field($field_name);
$this->assertTrue($field['settings']['test_field_setting'] == $string, t('Field settings were found.'));
@@ -360,7 +360,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
$this->fieldUIDeleteField($bundle_path1, $this->field_name, $this->field_label, $this->type);
// Reset the fields info.
- _field_info_collate_fields(TRUE);
+ field_info_cache_clear();
// Check that the field instance was deleted.
$this->assertNull(field_info_instance('node', $this->field_name, $this->type), t('Field instance was deleted.'));
// Check that the field was not deleted
@@ -370,7 +370,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
$this->fieldUIDeleteField($bundle_path2, $this->field_name, $this->field_label, $type_name2);
// Reset the fields info.
- _field_info_collate_fields(TRUE);
+ field_info_cache_clear();
// Check that the field instance was deleted.
$this->assertNull(field_info_instance('node', $this->field_name, $type_name2), t('Field instance was deleted.'));
// Check that the field was deleted too.
diff --git a/modules/filter/filter.admin.inc b/modules/filter/filter.admin.inc
index 5a21e6e2e..60284d993 100644
--- a/modules/filter/filter.admin.inc
+++ b/modules/filter/filter.admin.inc
@@ -2,13 +2,14 @@
/**
* @file
- * Admin page callbacks for the filter module.
+ * Administrative page callbacks for the Filter module.
*/
/**
- * Menu callback; Displays a list of all text formats and allows them to be rearranged.
+ * Page callback: Form constructor for a form to list and reorder text formats.
*
* @ingroup forms
+ * @see filter_menu()
* @see filter_admin_overview_submit()
*/
function filter_admin_overview($form) {
@@ -45,6 +46,9 @@ function filter_admin_overview($form) {
return $form;
}
+/**
+ * Form submission handler for filter_admin_overview().
+ */
function filter_admin_overview_submit($form, &$form_state) {
foreach ($form_state['values']['formats'] as $id => $data) {
if (is_array($data) && isset($data['weight'])) {
@@ -95,7 +99,26 @@ function theme_filter_admin_overview($variables) {
}
/**
- * Menu callback; Display a text format form.
+ * Page callback: Displays the text format add/edit form.
+ *
+ * @param object|null $format
+ * (optional) An object representing a format, with the following properties:
+ * - format: A machine-readable name representing the ID of the text format
+ * to save. If this corresponds to an existing text format, that format
+ * will be updated; otherwise, a new format will be created.
+ * - name: The title of the text format.
+ * - cache: (optional) An integer indicating whether the text format is
+ * cacheable (1) or not (0). Defaults to 1.
+ * - status: (optional) An integer indicating whether the text format is
+ * enabled (1) or not (0). Defaults to 1.
+ * - weight: (optional) The weight of the text format, which controls its
+ * placement in text format lists. If omitted, the weight is set to 0.
+ * Defaults to NULL.
+ *
+ * @return
+ * A form array.
+ *
+ * @see filter_menu()
*/
function filter_admin_format_page($format = NULL) {
if (!isset($format->name)) {
@@ -109,11 +132,24 @@ function filter_admin_format_page($format = NULL) {
}
/**
- * Generate a text format form.
+ * Form constructor for the text format add/edit form.
+ *
+ * @param $format
+ * A format object having the properties:
+ * - format: A machine-readable name representing the ID of the text format to
+ * save. If this corresponds to an existing text format, that format will be
+ * updated; otherwise, a new format will be created.
+ * - name: The title of the text format.
+ * - cache: An integer indicating whether the text format is cacheable (1) or
+ * not (0). Defaults to 1.
+ * - status: (optional) An integer indicating whether the text format is
+ * enabled (1) or not (0). Defaults to 1.
+ * - weight: (optional) The weight of the text format, which controls its
+ * placement in text format lists. If omitted, the weight is set to 0.
*
- * @ingroup forms
* @see filter_admin_format_form_validate()
* @see filter_admin_format_form_submit()
+ * @ingroup forms
*/
function filter_admin_format_form($form, &$form_state, $format) {
$is_fallback = ($format->format == filter_fallback_format());
@@ -287,7 +323,9 @@ function theme_filter_admin_format_filter_order($variables) {
}
/**
- * Validate text format form submissions.
+ * Form validation handler for filter_admin_format_form().
+ *
+ * @see filter_admin_format_form_submit()
*/
function filter_admin_format_form_validate($form, &$form_state) {
$format_format = trim($form_state['values']['format']);
@@ -304,7 +342,9 @@ function filter_admin_format_form_validate($form, &$form_state) {
}
/**
- * Process text format form submissions.
+ * Form submission handler for filter_admin_format_form().
+ *
+ * @see filter_admin_format_form_validate()
*/
function filter_admin_format_form_submit($form, &$form_state) {
// Remove unnecessary values.
@@ -336,10 +376,14 @@ function filter_admin_format_form_submit($form, &$form_state) {
}
/**
- * Menu callback; confirm deletion of a format.
+ * Form constructor for the text format deletion confirmation form.
*
- * @ingroup forms
+ * @param $format
+ * An object representing a text format.
+ *
+ * @see filter_menu()
* @see filter_admin_disable_submit()
+ * @ingroup forms
*/
function filter_admin_disable($form, &$form_state, $format) {
$form['#format'] = $format;
@@ -353,7 +397,7 @@ function filter_admin_disable($form, &$form_state, $format) {
}
/**
- * Process filter disable form submission.
+ * Form submission handler for filter_admin_disable().
*/
function filter_admin_disable_submit($form, &$form_state) {
$format = $form['#format'];
@@ -362,4 +406,3 @@ function filter_admin_disable_submit($form, &$form_state) {
$form_state['redirect'] = 'admin/config/content/formats';
}
-
diff --git a/modules/filter/filter.install b/modules/filter/filter.install
index 9d17eb54b..71ba97b08 100644
--- a/modules/filter/filter.install
+++ b/modules/filter/filter.install
@@ -2,7 +2,7 @@
/**
* @file
- * Install, update and uninstall functions for the filter module.
+ * Install, update, and uninstall functions for the Filter module.
*/
/**
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index 7b451b7e3..182033fe8 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -2,7 +2,7 @@
/**
* @file
- * Framework for handling filtering of content.
+ * Framework for handling the filtering of content.
*/
/**
@@ -71,6 +71,7 @@ function filter_theme() {
* Implements hook_element_info().
*
* @see filter_process_format()
+ * @see text_format_wrapper()
*/
function filter_element_info() {
$type['text_format'] = array(
@@ -132,13 +133,16 @@ function filter_menu() {
}
/**
- * Access callback for deleting text formats.
+ * Access callback: Checks access for disabling text formats.
*
* @param $format
* A text format object.
+ *
* @return
* TRUE if the text format can be disabled by the current user, FALSE
* otherwise.
+ *
+ * @see filter_menu()
*/
function _filter_disable_format_access($format) {
// The fallback format can never be disabled.
@@ -146,7 +150,7 @@ function _filter_disable_format_access($format) {
}
/**
- * Load a text format object from the database.
+ * Loads a text format object from the database.
*
* @param $format_id
* The format ID.
@@ -164,29 +168,32 @@ function filter_format_load($format_id) {
}
/**
- * Save a text format object to the database.
+ * Saves a text format object to the database.
*
* @param $format
- * A format object using the properties:
- * - 'format': A machine-readable name representing the ID of the text format
+ * A format object having the properties:
+ * - format: A machine-readable name representing the ID of the text format
* to save. If this corresponds to an existing text format, that format
* will be updated; otherwise, a new format will be created.
- * - 'name': The title of the text format.
- * - 'status': (optional) An integer indicating whether the text format is
+ * - name: The title of the text format.
+ * - status: (optional) An integer indicating whether the text format is
* enabled (1) or not (0). Defaults to 1.
- * - 'weight': (optional) The weight of the text format, which controls its
+ * - weight: (optional) The weight of the text format, which controls its
* placement in text format lists. If omitted, the weight is set to 0.
- * - 'filters': (optional) An associative, multi-dimensional array of filters
+ * - filters: (optional) An associative, multi-dimensional array of filters
* assigned to the text format, keyed by the name of each filter and using
* the properties:
- * - 'weight': (optional) The weight of the filter in the text format. If
+ * - weight: (optional) The weight of the filter in the text format. If
* omitted, either the currently stored weight is retained (if there is
* one), or the filter is assigned a weight of 10, which will usually
* put it at the bottom of the list.
- * - 'status': (optional) A boolean indicating whether the filter is
+ * - status: (optional) A boolean indicating whether the filter is
* enabled in the text format. If omitted, the filter will be disabled.
- * - 'settings': (optional) An array of configured settings for the filter.
+ * - settings: (optional) An array of configured settings for the filter.
* See hook_filter_info() for details.
+ *
+ * @return
+ * SAVED_NEW or SAVED_UPDATED.
*/
function filter_format_save($format) {
$format->name = trim($format->name);
@@ -271,7 +278,7 @@ function filter_format_save($format) {
}
/**
- * Disable a text format.
+ * Disables a text format.
*
* There is no core facility to re-enable a disabled format. It is not deleted
* to keep information for contrib and to make sure the format ID is never
@@ -313,7 +320,15 @@ function filter_format_exists($format_id) {
}
/**
- * Display a text format form title.
+ * Displays a text format form title.
+ *
+ * @param object $format
+ * A format object.
+ *
+ * @return string
+ * The name of the format.
+ *
+ * @see filter_menu()
*/
function filter_admin_format_title($format) {
return $format->name;
@@ -350,6 +365,7 @@ function filter_permission() {
*
* @param $format
* An object representing a text format.
+ *
* @return
* The machine-readable permission name, or FALSE if the provided text format
* is malformed or is the fallback format (which is available to all users).
@@ -380,11 +396,13 @@ function filter_modules_disabled($modules) {
}
/**
- * Retrieve a list of text formats, ordered by weight.
+ * Retrieves a list of text formats, ordered by weight.
*
* @param $account
* (optional) If provided, only those formats that are allowed for this user
- * account will be returned. All formats will be returned otherwise.
+ * account will be returned. All formats will be returned otherwise. Defaults
+ * to NULL.
+ *
* @return
* An array of text format objects, keyed by the format ID and ordered by
* weight.
@@ -427,7 +445,7 @@ function filter_formats($account = NULL) {
}
/**
- * Resets text format caches.
+ * Resets the text format caches.
*
* @see filter_formats()
*/
@@ -443,6 +461,7 @@ function filter_formats_reset() {
*
* @param $format
* An object representing the text format.
+ *
* @return
* An array of role names, keyed by role ID.
*/
@@ -461,6 +480,7 @@ function filter_get_roles_by_format($format) {
*
* @param $rid
* The user role ID to retrieve text formats for.
+ *
* @return
* An array of text format objects that are allowed for the role, keyed by
* the text format ID and ordered by weight.
@@ -494,7 +514,8 @@ function filter_get_formats_by_role($rid) {
*
* @param $account
* (optional) The user account to check. Defaults to the currently logged-in
- * user.
+ * user. Defaults to NULL.
+ *
* @return
* The ID of the user's default text format.
*
@@ -525,15 +546,18 @@ function filter_default_format($account = NULL) {
* format is initialized to output plain text. Installation profiles and site
* administrators have the freedom to configure it further.
*
- * Note that the fallback format is completely distinct from the default
- * format, which differs per user and is simply the first format which that
- * user has access to. The default and fallback formats are only guaranteed to
- * be the same for users who do not have access to any other format; otherwise,
- * the fallback format's weight determines its placement with respect to the
- * user's other formats.
+ * Note that the fallback format is completely distinct from the default format,
+ * which differs per user and is simply the first format which that user has
+ * access to. The default and fallback formats are only guaranteed to be the
+ * same for users who do not have access to any other format; otherwise, the
+ * fallback format's weight determines its placement with respect to the user's
+ * other formats.
*
- * Any modules implementing a format deletion functionality must not delete
- * this format.
+ * Any modules implementing a format deletion functionality must not delete this
+ * format.
+ *
+ * @return
+ * The ID of the fallback text format.
*
* @see hook_filter_format_disable()
* @see filter_default_format()
@@ -550,6 +574,9 @@ function filter_fallback_format() {
/**
* Returns the title of the fallback text format.
+ *
+ * @return string
+ * The title of the fallback text format.
*/
function filter_fallback_format_title() {
$fallback_format = filter_format_load(filter_fallback_format());
@@ -557,7 +584,10 @@ function filter_fallback_format_title() {
}
/**
- * Return a list of all filters provided by modules.
+ * Returns a list of all filters provided by modules.
+ *
+ * @return array
+ * An array of filter formats.
*/
function filter_get_filters() {
$filters = &drupal_static(__FUNCTION__, array());
@@ -588,14 +618,16 @@ function filter_get_filters() {
}
/**
- * Helper function for sorting the filter list by filter name.
+ * Sorts an array of filters by filter name.
+ *
+ * Callback for uasort() within filter_get_filters().
*/
function _filter_list_cmp($a, $b) {
return strcmp($a['title'], $b['title']);
}
/**
- * Check if text in a certain text format is allowed to be cached.
+ * Checks if the text in a certain text format is allowed to be cached.
*
* This function can be used to check whether the result of the filtering
* process can be cached. A text format may allow caching depending on the
@@ -603,6 +635,7 @@ function _filter_list_cmp($a, $b) {
*
* @param $format_id
* The text format ID to check.
+ *
* @return
* TRUE if the given text format allows caching, FALSE otherwise.
*/
@@ -619,6 +652,7 @@ function filter_format_allowcache($format_id) {
*
* @param $format
* The text format object to check.
+ *
* @return
* TRUE if all the filters enabled in the given text format allow caching,
* FALSE otherwise.
@@ -640,7 +674,7 @@ function _filter_format_is_cacheable($format) {
}
/**
- * Retrieve a list of filters for a given text format.
+ * Retrieves a list of filters for a given text format.
*
* Note that this function returns all associated filters regardless of whether
* they are enabled or disabled. All functions working with the filter
@@ -694,7 +728,7 @@ function filter_list_format($format_id) {
}
/**
- * Run all the enabled filters on a piece of text.
+ * Runs all the enabled filters on a piece of text.
*
* Note: Because filters can inject JavaScript or execute PHP code, security is
* vital here. When a user supplies a text format, you should validate it using
@@ -705,16 +739,20 @@ function filter_list_format($format_id) {
* @param $text
* The text to be filtered.
* @param $format_id
- * The format id of the text to be filtered. If no format is assigned, the
- * fallback format will be used.
+ * (optional) The format ID of the text to be filtered. If no format is
+ * assigned, the fallback format will be used. Defaults to NULL.
* @param $langcode
- * Optional: the language code of the text to be filtered, e.g. 'en' for
+ * (optional) The language code of the text to be filtered, e.g. 'en' for
* English. This allows filters to be language aware so language specific
- * text replacement can be implemented.
+ * text replacement can be implemented. Defaults to an empty string.
* @param $cache
- * Boolean whether to cache the filtered output in the {cache_filter} table.
- * The caller may set this to FALSE when the output is already cached
- * elsewhere to avoid duplicate cache lookups and storage.
+ * (optional) A Boolean indicating whether to cache the filtered output in the
+ * {cache_filter} table. The caller may set this to FALSE when the output is
+ * already cached elsewhere to avoid duplicate cache lookups and storage.
+ * Defaults to FALSE.
+ *
+ * @return
+ * The filtered text.
*
* @ingroup sanitization
*/
@@ -784,8 +822,8 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
* the text format id specified in #format or the user's default format by
* default, if NULL.
*
- * The resulting value for the element will be an array holding the value and the
- * format. For example, the value for the body element will be:
+ * The resulting value for the element will be an array holding the value and
+ * the format. For example, the value for the body element will be:
* @code
* $form_state['values']['body']['value'] = 'foo';
* $form_state['values']['body']['format'] = 'foo';
@@ -795,7 +833,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
* The form element to process. Properties used:
* - #base_type: The form element #type to use for the 'value' element.
* 'textarea' by default.
- * - #format: (optional) The text format id to preselect. If NULL or not set,
+ * - #format: (optional) The text format ID to preselect. If NULL or not set,
* the default format for the current user will be used.
*
* @return
@@ -933,7 +971,7 @@ function filter_process_format($element) {
}
/**
- * #pre_render callback for #type 'text_format' to hide field value from prying eyes.
+ * Render API callback: Hides the field value of 'text_format' elements.
*
* To not break form processing and previews if a user does not have access to a
* stored text format, the expanded form elements in filter_process_format() are
@@ -976,7 +1014,7 @@ function theme_text_format_wrapper($variables) {
* An object representing the text format.
* @param $account
* (optional) The user account to check access for; if omitted, the currently
- * logged-in user is used.
+ * logged-in user is used. Defaults to NULL.
*
* @return
* Boolean TRUE if the user is allowed to access the given format.
@@ -998,7 +1036,20 @@ function filter_access($format, $account = NULL) {
}
/**
- * Helper function for fetching filter tips.
+ * Retrieves the filter tips.
+ *
+ * @param $format_id
+ * The ID of the text format for which to retrieve tips, or -1 to return tips
+ * for all formats accessible to the current user.
+ * @param $long
+ * (optional) Boolean indicating whether the long form of tips should be
+ * returned. Defaults to FALSE.
+ *
+ * @return
+ * An associative array of filtering tips, keyed by filter name. Each
+ * filtering tip is an associative array with elements:
+ * - tip: Tip text.
+ * - id: Filter ID.
*/
function _filter_tips($format_id, $long = FALSE) {
global $user;
@@ -1032,14 +1083,14 @@ function _filter_tips($format_id, $long = FALSE) {
/**
* Parses an HTML snippet and returns it as a DOM object.
*
- * This function loads the body part of a partial (X)HTML document
- * and returns a full DOMDocument object that represents this document.
- * You can use filter_dom_serialize() to serialize this DOMDocument
- * back to a XHTML snippet.
+ * This function loads the body part of a partial (X)HTML document and returns
+ * a full DOMDocument object that represents this document. You can use
+ * filter_dom_serialize() to serialize this DOMDocument back to a XHTML
+ * snippet.
*
* @param $text
- * The partial (X)HTML snippet to load. Invalid mark-up
- * will be corrected on import.
+ * The partial (X)HTML snippet to load. Invalid mark-up will be corrected on
+ * import.
* @return
* A DOMDocument that represents the loaded (X)HTML snippet.
*/
@@ -1054,15 +1105,14 @@ function filter_dom_load($text) {
/**
* Converts a DOM object back to an HTML snippet.
*
- * The function serializes the body part of a DOMDocument
- * back to an XHTML snippet.
- *
- * The resulting XHTML snippet will be properly formatted
- * to be compatible with HTML user agents.
+ * The function serializes the body part of a DOMDocument back to an XHTML
+ * snippet. The resulting XHTML snippet will be properly formatted to be
+ * compatible with HTML user agents.
*
* @param $dom_document
* A DOMDocument object to serialize, only the tags below
* the first <body> node will be converted.
+ *
* @return
* A valid (X)HTML snippet, as a string.
*/
@@ -1099,9 +1149,11 @@ function filter_dom_serialize($dom_document) {
* @param $dom_element
* The element potentially containing a CDATA node.
* @param $comment_start
- * String to use as a comment start marker to escape the CDATA declaration.
+ * (optional) A string to use as a comment start marker to escape the CDATA
+ * declaration. Defaults to '//'.
* @param $comment_end
- * String to use as a comment end marker to escape the CDATA declaration.
+ * (optional) A string to use as a comment end marker to escape the CDATA
+ * declaration. Defaults to an empty string.
*/
function filter_dom_serialize_escape_cdata_element($dom_document, $dom_element, $comment_start = '//', $comment_end = '') {
foreach ($dom_element->childNodes as $node) {
@@ -1156,7 +1208,7 @@ function theme_filter_guidelines($variables) {
/**
* @defgroup standard_filters Standard filters
* @{
- * Filters implemented by the filter.module.
+ * Filters implemented by the Filter module.
*/
/**
@@ -1204,7 +1256,10 @@ function filter_filter_info() {
}
/**
- * Settings callback for the HTML filter.
+ * Filter settings callback for the HTML content filter.
+ *
+ * See hook_filter_FILTER_settings() for documentation of parameters and return
+ * value.
*/
function _filter_html_settings($form, &$form_state, $filter, $format, $defaults) {
$filter->settings += $defaults;
@@ -1230,7 +1285,7 @@ function _filter_html_settings($form, &$form_state, $filter, $format, $defaults)
}
/**
- * HTML filter. Provides filtering of input into accepted HTML.
+ * Provides filtering of input into accepted HTML.
*/
function _filter_html($text, $filter) {
$allowed_tags = preg_split('/\s+|<|>/', $filter->settings['allowed_html'], -1, PREG_SPLIT_NO_EMPTY);
@@ -1249,7 +1304,9 @@ function _filter_html($text, $filter) {
}
/**
- * Filter tips callback for HTML filter.
+ * Filter tips callback: Provides help for the HTML filter.
+ *
+ * @see filter_filter_info()
*/
function _filter_html_tips($filter, $format, $long = FALSE) {
global $base_url;
@@ -1347,7 +1404,9 @@ function _filter_html_tips($filter, $format, $long = FALSE) {
}
/**
- * Settings callback for URL filter.
+ * Filter URL settings callback: Provides settings for the URL filter.
+ *
+ * @see filter_filter_info()
*/
function _filter_url_settings($form, &$form_state, $filter, $format, $defaults) {
$filter->settings += $defaults;
@@ -1366,7 +1425,7 @@ function _filter_url_settings($form, &$form_state, $filter, $format, $defaults)
}
/**
- * URL filter. Automatically converts text into hyperlinks.
+ * Converts text into hyperlinks automatically.
*
* This filter identifies and makes clickable three types of "links".
* - URLs like http://example.com.
@@ -1489,7 +1548,9 @@ function _filter_url($text, $filter) {
}
/**
- * preg_replace callback to make links out of absolute URLs.
+ * Makes links out of absolute URLs.
+ *
+ * Callback for preg_replace_callback() within _filter_url().
*/
function _filter_url_parse_full_links($match) {
// The $i:th parenthesis in the regexp contains the URL.
@@ -1502,7 +1563,9 @@ function _filter_url_parse_full_links($match) {
}
/**
- * preg_replace callback to make links out of e-mail addresses.
+ * Makes links out of e-mail addresses.
+ *
+ * Callback for preg_replace_callback() within _filter_url().
*/
function _filter_url_parse_email_links($match) {
// The $i:th parenthesis in the regexp contains the URL.
@@ -1515,7 +1578,9 @@ function _filter_url_parse_email_links($match) {
}
/**
- * preg_replace callback to make links out of domain names starting with "www."
+ * Makes links out of domain names starting with "www."
+ *
+ * Callback for preg_replace_callback() within _filter_url().
*/
function _filter_url_parse_partial_links($match) {
// The $i:th parenthesis in the regexp contains the URL.
@@ -1528,14 +1593,17 @@ function _filter_url_parse_partial_links($match) {
}
/**
- * preg_replace callback to escape contents of HTML comments
+ * Escapes the contents of HTML comments.
+ *
+ * Callback for preg_replace_callback() within _filter_url().
*
* @param $match
* An array containing matches to replace from preg_replace_callback(),
* whereas $match[1] is expected to contain the content to be filtered.
* @param $escape
- * (optional) Boolean whether to escape (TRUE) or unescape comments (FALSE).
- * Defaults to neither. If TRUE, statically cached $comments are reset.
+ * (optional) A Boolean indicating whether to escape (TRUE) or unescape
+ * comments (FALSE). Defaults to NULL, indicating neither. If TRUE, statically
+ * cached $comments are reset.
*/
function _filter_url_escape_comments($match, $escape = NULL) {
static $mode, $comments = array();
@@ -1582,21 +1650,24 @@ function _filter_url_trim($text, $length = NULL) {
}
/**
- * Filter tips callback for URL filter.
+ * Filter tips callback: Provides help for the URL filter.
+ *
+ * @see filter_filter_info()
*/
function _filter_url_tips($filter, $format, $long = FALSE) {
return t('Web page addresses and e-mail addresses turn into links automatically.');
}
/**
- * Scan input and make sure that all HTML tags are properly closed and nested.
+ * Scans the input and makes sure that HTML tags are properly closed.
*/
function _filter_htmlcorrector($text) {
return filter_dom_serialize(filter_dom_load($text));
}
/**
- * Convert line breaks into <p> and <br> in an intelligent fashion.
+ * Converts line breaks into <p> and <br> in an intelligent fashion.
+ *
* Based on: http://photomatt.net/scripts/autop
*/
function _filter_autop($text) {
@@ -1662,7 +1733,9 @@ function _filter_autop($text) {
}
/**
- * Filter tips callback for auto-paragraph filter.
+ * Filter tips callback: Provides help for the auto-paragraph filter.
+ *
+ * @see filter_filter_info()
*/
function _filter_autop_tips($filter, $format, $long = FALSE) {
if ($long) {
@@ -1681,7 +1754,9 @@ function _filter_html_escape($text) {
}
/**
- * Filter tips callback for HTML escaping filter.
+ * Filter tips callback: Provides help for the HTML escaping filter.
+ *
+ * @see filter_filter_info()
*/
function _filter_html_escape_tips($filter, $format, $long = FALSE) {
return t('No HTML tags allowed.');
diff --git a/modules/filter/filter.pages.inc b/modules/filter/filter.pages.inc
index dbbbe4c5a..50f81177f 100644
--- a/modules/filter/filter.pages.inc
+++ b/modules/filter/filter.pages.inc
@@ -2,12 +2,17 @@
/**
* @file
- * User page callbacks for the filter module.
+ * User page callbacks for the Filter module.
*/
-
/**
- * Menu callback; show a page with long filter tips.
+ * Page callback: Displays a page with long filter tips.
+ *
+ * @return string
+ * An HTML-formatted string.
+ *
+ * @see filter_menu()
+ * @see theme_filter_tips()
*/
function filter_tips_long() {
$format_id = arg(2);
@@ -20,13 +25,12 @@ function filter_tips_long() {
return $output;
}
-
/**
* Returns HTML for a set of filter tips.
*
* @param $variables
* An associative array containing:
- * - tips: An array containing descriptions and a CSS id in the form of
+ * - tips: An array containing descriptions and a CSS ID in the form of
* 'module-name/filter-id' (only used when $long is TRUE) for each
* filter in one or more text formats. Example:
* @code
diff --git a/modules/filter/filter.test b/modules/filter/filter.test
index aa1693fba..0c3949517 100644
--- a/modules/filter/filter.test
+++ b/modules/filter/filter.test
@@ -22,7 +22,7 @@ class FilterCRUDTestCase extends DrupalWebTestCase {
}
/**
- * Test CRUD operations for text formats and filters.
+ * Tests CRUD operations for text formats and filters.
*/
function testTextFormatCRUD() {
// Add a text format with minimum data only.
@@ -73,7 +73,7 @@ class FilterCRUDTestCase extends DrupalWebTestCase {
}
/**
- * Verify that a text format is properly stored.
+ * Verifies that a text format is properly stored.
*/
function verifyTextFormat($format) {
$t_args = array('%format' => $format->name);
@@ -111,7 +111,7 @@ class FilterCRUDTestCase extends DrupalWebTestCase {
}
/**
- * Verify that filters are properly stored for a text format.
+ * Verifies that filters are properly stored for a text format.
*/
function verifyFilters($format) {
// Verify filter database records.
@@ -160,6 +160,9 @@ class FilterCRUDTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the administrative functionality of the Filter module.
+ */
class FilterAdminTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -185,6 +188,9 @@ class FilterAdminTestCase extends DrupalWebTestCase {
$this->drupalLogin($this->admin_user);
}
+ /**
+ * Tests the format administration functionality.
+ */
function testFormatAdmin() {
// Add text format.
$this->drupalGet('admin/config/content/formats');
@@ -249,7 +255,7 @@ class FilterAdminTestCase extends DrupalWebTestCase {
}
/**
- * Test filter administration functionality.
+ * Tests filter administration functionality.
*/
function testFilterAdmin() {
// URL filter.
@@ -413,11 +419,43 @@ class FilterAdminTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the filter format access functionality in the Filter module.
+ */
class FilterFormatAccessTestCase extends DrupalWebTestCase {
+ /**
+ * A user with administrative permissions.
+ *
+ * @var object
+ */
protected $admin_user;
+
+ /**
+ * A user with 'administer filters' permission.
+ *
+ * @var object
+ */
protected $filter_admin_user;
+
+ /**
+ * A user with permission to create and edit own content.
+ *
+ * @var object
+ */
protected $web_user;
+
+ /**
+ * An object representing an allowed text format.
+ *
+ * @var object
+ */
protected $allowed_format;
+
+ /**
+ * An object representing a disallowed text format.
+ *
+ * @var object
+ */
protected $disallowed_format;
public static function getInfo() {
@@ -471,6 +509,9 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
));
}
+ /**
+ * Tests the Filter format access permissions functionality.
+ */
function testFormatPermissions() {
// Make sure that a regular user only has access to the text format they
// were granted access to, as well to the fallback format.
@@ -507,6 +548,9 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
$this->assertTrue(isset($options[filter_fallback_format()]), t('The fallback format appears as an option when adding a new node.'));
}
+ /**
+ * Tests if text format is available to a role.
+ */
function testFormatRoles() {
// Get the role ID assigned to the regular user; it must be the maximum.
$rid = max(array_keys($this->web_user->roles));
@@ -528,13 +572,13 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
}
/**
- * Test editing a page using a disallowed text format.
+ * Tests editing a page using a disallowed text format.
*
- * Verifies that regular users and administrators are able to edit a page,
- * but not allowed to change the fields which use an inaccessible text
- * format. Also verifies that fields which use a text format that does not
- * exist can be edited by administrators only, but that the administrator is
- * forced to choose a new format before saving the page.
+ * Verifies that regular users and administrators are able to edit a page, but
+ * not allowed to change the fields which use an inaccessible text format.
+ * Also verifies that fields which use a text format that does not exist can
+ * be edited by administrators only, but that the administrator is forced to
+ * choose a new format before saving the page.
*/
function testFormatWidgetPermissions() {
$langcode = LANGUAGE_NONE;
@@ -650,7 +694,7 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
}
/**
- * Rebuild text format and permission caches in the thread running the tests.
+ * Rebuilds text format and permission caches in the thread running the tests.
*/
protected function resetFilterCaches() {
filter_formats_reset();
@@ -658,6 +702,9 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the default filter functionality in the Filter module.
+ */
class FilterDefaultFormatTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -667,6 +714,9 @@ class FilterDefaultFormatTestCase extends DrupalWebTestCase {
);
}
+ /**
+ * Tests if the default text format is accessible to users.
+ */
function testDefaultTextFormats() {
// Create two text formats, and two users. The first user has access to
// both formats, but the second user only has access to the second one.
@@ -710,7 +760,7 @@ class FilterDefaultFormatTestCase extends DrupalWebTestCase {
}
/**
- * Rebuild text format and permission caches in the thread running the tests.
+ * Rebuilds text format and permission caches in the thread running the tests.
*/
protected function resetFilterCaches() {
filter_formats_reset();
@@ -718,6 +768,9 @@ class FilterDefaultFormatTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the behavior of check_markup() when it is called without text format.
+ */
class FilterNoFormatTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -727,6 +780,12 @@ class FilterNoFormatTestCase extends DrupalWebTestCase {
);
}
+ /**
+ * Tests text without format.
+ *
+ * Tests if text with no format is filtered the same way as text in the
+ * fallback format.
+ */
function testCheckMarkupNoFormat() {
// Create some text. Include some HTML and line breaks, so we get a good
// test of the filtering that is applied to it.
@@ -757,7 +816,10 @@ class FilterSecurityTestCase extends DrupalWebTestCase {
}
/**
- * Test that filtered content is emptied when an actively used filter module is disabled.
+ * Tests removal of filtered content when an active filter is disabled.
+ *
+ * Tests that filtered content is emptied when an actively used filter module
+ * is disabled.
*/
function testDisableFilterModule() {
// Create a new node.
@@ -800,7 +862,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
}
/**
- * Test the line break filter.
+ * Tests the line break filter.
*/
function testLineBreakFilter() {
// Setup dummy filter object.
@@ -1060,7 +1122,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
}
/**
- * Test filter settings, defaults, access restrictions and similar.
+ * Tests filter settings, defaults, access restrictions and similar.
*
* @todo This is for functions like filter_filter and check_markup, whose
* functionality is not completely focused on filtering. Some ideas:
@@ -1116,7 +1178,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
}
/**
- * Test the spam deterrent.
+ * Tests the spam deterrent.
*/
function testNoFollowFilter() {
// Setup dummy filter object.
@@ -1147,7 +1209,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
}
/**
- * Test the loose, admin HTML filter.
+ * Tests the loose, admin HTML filter.
*/
function testFilterXSSAdmin() {
// DRUPAL-SA-2008-044
@@ -1541,7 +1603,7 @@ www.example.com with a newline in comments -->
}
/**
- * Test the HTML corrector filter.
+ * Tests the HTML corrector filter.
*
* @todo This test could really use some validity checking function.
*/
@@ -1745,9 +1807,9 @@ body {color:red}
* @param $needle
* Lowercase, plain text to look for.
* @param $message
- * Message to display if failed.
+ * (optional) Message to display if failed. Defaults to an empty string.
* @param $group
- * The group this message belongs to, defaults to 'Other'.
+ * (optional) The group this message belongs to. Defaults to 'Other'.
* @return
* TRUE on pass, FALSE on fail.
*/
@@ -1769,9 +1831,9 @@ body {color:red}
* @param $needle
* Lowercase, plain text to look for.
* @param $message
- * Message to display if failed.
+ * (optional) Message to display if failed. Defaults to an empty string.
* @param $group
- * The group this message belongs to, defaults to 'Other'.
+ * (optional) The group this message belongs to. Defaults to 'Other'.
* @return
* TRUE on pass, FALSE on fail.
*/
@@ -1781,7 +1843,7 @@ body {color:red}
}
/**
- * Tests for filter hook invocation.
+ * Tests for Filter's hook invocations.
*/
class FilterHooksTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -1799,7 +1861,10 @@ class FilterHooksTestCase extends DrupalWebTestCase {
}
/**
- * Test that hooks run correctly on creating, editing, and deleting a text format.
+ * Tests hooks on format management.
+ *
+ * Tests that hooks run correctly on creating, editing, and deleting a text
+ * format.
*/
function testFilterHooks() {
// Add a text format.
@@ -1846,6 +1911,11 @@ class FilterHooksTestCase extends DrupalWebTestCase {
* Tests filter settings.
*/
class FilterSettingsTestCase extends DrupalWebTestCase {
+ /**
+ * The installation profile to use with this test class.
+ *
+ * @var string
+ */
protected $profile = 'testing';
public static function getInfo() {
diff --git a/modules/image/image.admin.inc b/modules/image/image.admin.inc
index ab99a49e8..9f0fab254 100644
--- a/modules/image/image.admin.inc
+++ b/modules/image/image.admin.inc
@@ -326,7 +326,7 @@ function image_style_delete_form_submit($form, &$form_state) {
/**
* Confirmation form to revert a database style to its default.
*/
-function image_style_revert_form($form, $form_state, $style) {
+function image_style_revert_form($form, &$form_state, $style) {
$form_state['image_style'] = $style;
return confirm_form(
diff --git a/modules/image/image.install b/modules/image/image.install
index b7aac7152..1d7bd4ef4 100644
--- a/modules/image/image.install
+++ b/modules/image/image.install
@@ -391,7 +391,8 @@ function image_update_7002(array &$sandbox) {
}
// Process the table at the top of the list.
- $table = reset(array_keys($sandbox['tables']));
+ $keys = array_keys($sandbox['tables']);
+ $table = reset($keys);
$sandbox['processed'] += _image_update_7002_populate_dimensions($table, $sandbox['tables'][$table], $sandbox['last_fid']);
// Has the table been fully processed?
diff --git a/modules/image/image.module b/modules/image/image.module
index a9cc1a545..b7d6cdda3 100644
--- a/modules/image/image.module
+++ b/modules/image/image.module
@@ -254,7 +254,7 @@ function image_form_system_file_system_settings_alter(&$form, &$form_state) {
}
/**
- * Submit handler for the file system settings form.
+ * Form submission handler for system_file_system_settings().
*
* Adds a menu rebuild after the public file path has been changed, so that the
* menu router item depending on that file path will be regenerated.
@@ -312,9 +312,9 @@ function image_file_download($uri) {
return -1;
}
- // Private file access for the original files. Note that we only
- // check access for non-temporary images, since file.module will
- // grant access for all temporary files.
+ // Private file access for the original files. Note that we only check access
+ // for non-temporary images, since file.module will grant access for all
+ // temporary files.
$files = file_load_multiple(array(), array('uri' => $uri));
if (count($files)) {
$file = reset($files);
@@ -537,7 +537,7 @@ function image_field_update_instance($instance, $prior_instance) {
}
/**
- * Clear cached versions of a specific file in all styles.
+ * Clears cached versions of a specific file in all styles.
*
* @param $path
* The Drupal file path to the original image.
@@ -553,7 +553,7 @@ function image_path_flush($path) {
}
/**
- * Get an array of all styles and their settings.
+ * Gets an array of all styles and their settings.
*
* @return
* An array of styles keyed by the image style ID (isid).
@@ -614,7 +614,9 @@ function image_styles() {
}
/**
- * Load a style by style name or ID. May be used as a loader for menu items.
+ * Loads a style by style name or ID.
+ *
+ * May be used as a loader for menu items.
*
* @param $name
* The name of the style.
@@ -623,6 +625,7 @@ function image_styles() {
* @param $include
* If set, this loader will restrict to a specific type of image style, may be
* one of the defined Image style storage constants.
+ *
* @return
* An image style array containing the following keys:
* - "isid": The unique image style ID.
@@ -660,12 +663,20 @@ function image_style_load($name = NULL, $isid = NULL, $include = NULL) {
}
/**
- * Save an image style.
+ * Saves an image style.
*
- * @param style
- * An image style array.
- * @return
- * An image style array. In the case of a new style, 'isid' will be populated.
+ * @param array $style
+ * An image style array containing:
+ * - name: A unique name for the style.
+ * - isid: (optional) An image style ID.
+ *
+ * @return array
+ * An image style array containing:
+ * - name: An unique name for the style.
+ * - old_name: The original name for the style.
+ * - isid: An image style ID.
+ * - is_new: TRUE if this is a new style, and FALSE if it is an existing
+ * style.
*/
function image_style_save($style) {
if (isset($style['isid']) && is_numeric($style['isid'])) {
@@ -692,13 +703,14 @@ function image_style_save($style) {
}
/**
- * Delete an image style.
+ * Deletes an image style.
*
* @param $style
* An image style array.
* @param $replacement_style_name
* (optional) When deleting a style, specify a replacement style name so
* that existing settings (if any) may be converted to a new style.
+ *
* @return
* TRUE on success.
*/
@@ -717,14 +729,17 @@ function image_style_delete($style, $replacement_style_name = '') {
}
/**
- * Load all the effects for an image style.
+ * Loads all the effects for an image style.
*
- * @param $style
- * An image style array.
- * @return
+ * @param array $style
+ * An image style array containing:
+ * - isid: The unique image style ID that contains this image effect.
+ *
+ * @return array
* An array of image effects associated with specified image style in the
* format array('isid' => array()), or an empty array if the specified style
* has no effects.
+ * @see image_effects()
*/
function image_style_effects($style) {
$effects = image_effects();
@@ -739,10 +754,11 @@ function image_style_effects($style) {
}
/**
- * Get an array of image styles suitable for using as select list options.
+ * Gets an array of image styles suitable for using as select list options.
*
* @param $include_empty
* If TRUE a <none> option will be inserted in the options array.
+ *
* @return
* Array of image styles both key and value are set to style name.
*/
@@ -763,7 +779,7 @@ function image_style_options($include_empty = TRUE) {
}
/**
- * Menu callback; Given a style and image path, generate a derivative.
+ * Page callback: Generates a derivative, given a style and image path.
*
* After generating an image, transfer it to the requesting agent.
*
@@ -931,7 +947,7 @@ function image_style_transform_dimensions($style_name, array &$dimensions) {
}
/**
- * Flush cached media for a style.
+ * Flushes cached media for a style.
*
* @param $style
* An image style array.
@@ -963,12 +979,13 @@ function image_style_flush($style) {
}
/**
- * Return the URL for an image derivative given a style and image path.
+ * Returns the URL for an image derivative given a style and image path.
*
* @param $style_name
* The name of the style to be used with this image.
* @param $path
* The path to the image.
+ *
* @return
* The absolute URL where a style image can be downloaded, suitable for use
* in an <img> tag. Requesting the URL will cause the image to be created.
@@ -979,7 +996,7 @@ function image_style_url($style_name, $path) {
// The token query is added even if the 'image_allow_insecure_derivatives'
// variable is TRUE, so that the emitted links remain valid if it is changed
// back to the default FALSE.
- $token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($style_name, $path));
+ $token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($style_name, file_stream_wrapper_uri_normalize($path)));
// If not using clean URLs, the image derivative callback is only available
// with the query string. If the file does not exist, use url() to ensure
@@ -1017,7 +1034,7 @@ function image_style_path_token($style_name, $uri) {
}
/**
- * Return the URI of an image when using a style.
+ * Returns the URI of an image when using a style.
*
* The path returned by this function may not exist. The default generation
* method only creates images when they are requested by a user's browser.
@@ -1026,6 +1043,7 @@ function image_style_path_token($style_name, $uri) {
* The name of the style to be used with this image.
* @param $uri
* The URI or path to the image.
+ *
* @return
* The URI to an image style image.
* @see image_style_url()
@@ -1043,10 +1061,11 @@ function image_style_path($style_name, $uri) {
}
/**
- * Save a default image style to the database.
+ * Saves a default image style to the database.
*
* @param style
* An image style array provided by a module.
+ *
* @return
* An image style array. The returned style array will include the new 'isid'
* assigned to the style.
@@ -1064,7 +1083,7 @@ function image_default_style_save($style) {
}
/**
- * Revert the changes made by users to a default image style.
+ * Reverts the changes made by users to a default image style.
*
* @param style
* An image style array.
@@ -1081,7 +1100,10 @@ function image_default_style_revert($style) {
}
/**
- * Pull in image effects exposed by modules implementing hook_image_effect_info().
+ * Returns a set of image effects.
+ *
+ * These image effects are exposed by modules implementing
+ * hook_image_effect_info().
*
* @return
* An array of image effects to be used when transforming images.
@@ -1123,7 +1145,7 @@ function image_effect_definitions() {
}
/**
- * Load the definition for an image effect.
+ * Loads the definition for an image effect.
*
* The effect definition is a set of core properties for an image effect, not
* containing any user-settings. The definition defines various functions to
@@ -1135,6 +1157,7 @@ function image_effect_definitions() {
* The name of the effect definition to load.
* @param $style
* An image style array to which this effect will be added.
+ *
* @return
* An array containing the image effect definition with the following keys:
* - "effect": The unique name for the effect being performed. Usually prefixed
@@ -1162,7 +1185,7 @@ function image_effect_definition_load($effect, $style_name = NULL) {
}
/**
- * Load all image effects from the database.
+ * Loads all image effects from the database.
*
* @return
* An array of all image effects.
@@ -1194,7 +1217,7 @@ function image_effects() {
}
/**
- * Load a single image effect.
+ * Loads a single image effect.
*
* @param $ieid
* The image effect ID.
@@ -1203,6 +1226,7 @@ function image_effects() {
* @param $include
* If set, this loader will restrict to a specific type of image style, may be
* one of the defined Image style storage constants.
+ *
* @return
* An image effect array, consisting of the following keys:
* - "ieid": The unique image effect ID.
@@ -1224,10 +1248,11 @@ function image_effect_load($ieid, $style_name, $include = NULL) {
}
/**
- * Save an image effect.
+ * Saves an image effect.
*
* @param $effect
* An image effect array.
+ *
* @return
* An image effect array. In the case of a new effect, 'ieid' will be set.
*/
@@ -1244,7 +1269,7 @@ function image_effect_save($effect) {
}
/**
- * Delete an image effect.
+ * Deletes an image effect.
*
* @param $effect
* An image effect array.
@@ -1256,12 +1281,13 @@ function image_effect_delete($effect) {
}
/**
- * Given an image object and effect, perform the effect on the file.
+ * Applies an image effect to the image object.
*
* @param $image
* An image object returned by image_load().
* @param $effect
* An image effect array.
+ *
* @return
* TRUE on success. FALSE if unable to perform the image effect on the image.
*/
@@ -1312,7 +1338,7 @@ function theme_image_style($variables) {
}
/**
- * Accept a keyword (center, top, left, etc) and return it as a pixel offset.
+ * Accepts a keyword (center, top, left, etc) and returns it as a pixel offset.
*
* @param $value
* @param $current_pixels
diff --git a/modules/image/image.test b/modules/image/image.test
index 25fddf64c..917677046 100644
--- a/modules/image/image.test
+++ b/modules/image/image.test
@@ -168,9 +168,16 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
}
/**
+ * Test image_style_url() with a file URL that has an extra slash in it.
+ */
+ function testImageStyleUrlExtraSlash() {
+ $this->_testImageStyleUrlAndPath('public', TRUE, TRUE);
+ }
+
+ /**
* Test image_style_url().
*/
- function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE) {
+ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
// Make the default scheme neither "public" nor "private" to verify the
// functions work for other than the default scheme.
variable_set('file_default_scheme', 'temporary');
@@ -196,6 +203,15 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$generate_url = image_style_url($this->style_name, $original_uri);
+ // Ensure that the tests still pass when the file is generated by accessing
+ // a poorly constructed (but still valid) file URL that has an extra slash
+ // in it.
+ if ($extra_slash) {
+ $modified_uri = str_replace('://', ':///', $original_uri);
+ $this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
+ $generate_url = image_style_url($this->style_name, $modified_uri);
+ }
+
if (!$clean_url) {
$this->assertTrue(strpos($generate_url, '?q=') !== FALSE, 'When using non-clean URLS, the system path contains the query string.');
}
@@ -224,6 +240,12 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
$this->drupalGet($generate_url);
$this->assertResponse(200, t('Image was generated at the URL.'));
+ // Make sure that access is denied for existing style files if we do not
+ // have access.
+ variable_del('image_module_test_file_download');
+ $this->drupalGet($generate_url);
+ $this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
+
// Repeat this with a different file that we do not have access to and
// make sure that access is denied.
$file_noaccess = array_shift($files);
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index 253535751..f1a71ddfe 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -388,13 +388,13 @@ function locale_languages_edit_form_validate($form, &$form_state) {
form_set_error('prefix', t('Domain and path prefix values should not be set at the same time.'));
}
if (!empty($form_state['values']['domain']) && $duplicate = db_query("SELECT language FROM {languages} WHERE domain = :domain AND language <> :language", array(':domain' => $form_state['values']['domain'], ':language' => $form_state['values']['langcode']))->fetchField()) {
- form_set_error('domain', t('The domain (%domain) is already tied to a language (%language).', array('%domain' => $form_state['values']['domain'], '%language' => $duplicate->language)));
+ form_set_error('domain', t('The domain (%domain) is already tied to a language (%language).', array('%domain' => $form_state['values']['domain'], '%language' => $duplicate)));
}
if (empty($form_state['values']['prefix']) && language_default('language') != $form_state['values']['langcode'] && empty($form_state['values']['domain'])) {
form_set_error('prefix', t('Only the default language can have both the domain and prefix empty.'));
}
if (!empty($form_state['values']['prefix']) && $duplicate = db_query("SELECT language FROM {languages} WHERE prefix = :prefix AND language <> :language", array(':prefix' => $form_state['values']['prefix'], ':language' => $form_state['values']['langcode']))->fetchField()) {
- form_set_error('prefix', t('The prefix (%prefix) is already tied to a language (%language).', array('%prefix' => $form_state['values']['prefix'], '%language' => $duplicate->language)));
+ form_set_error('prefix', t('The prefix (%prefix) is already tied to a language (%language).', array('%prefix' => $form_state['values']['prefix'], '%language' => $duplicate)));
}
}
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 94e7cd151..b60c53120 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -386,20 +386,53 @@ function locale_form_node_form_alter(&$form, &$form_state) {
/**
* Form submit handler for node_form().
*
- * Checks if Locale is registered as a translation handler and handle possible
- * node language changes.
- *
* This submit handler needs to run before entity_form_submit_build_entity()
* is invoked by node_form_submit_build_node(), because it alters the values of
* attached fields. Therefore, it cannot be a hook_node_submit() implementation.
*/
function locale_field_node_form_submit($form, &$form_state) {
- if (field_has_translation_handler('node', 'locale')) {
- $node = (object) $form_state['values'];
- $current_language = entity_language('node', $node);
- list(, , $bundle) = entity_extract_ids('node', $node);
+ locale_field_entity_form_submit('node', $form, $form_state);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function locale_form_comment_form_alter(&$form, &$form_state, $form_id) {
+ // If a content type has multilingual support we set the content language as
+ // comment language.
+ if ($form['language']['#value'] == LANGUAGE_NONE && locale_multilingual_node_type($form['#node']->type)) {
+ global $language_content;
+ $form['language']['#value'] = $language_content->language;
+ $submit_callback = 'locale_field_comment_form_submit';
+ array_unshift($form['actions']['preview']['#submit'], $submit_callback);
+ array_unshift($form['#submit'], $submit_callback);
+ }
+}
- foreach (field_info_instances('node', $bundle) as $instance) {
+/**
+ * Form submit handler for comment_form().
+ *
+ * This submit handler needs to run before entity_form_submit_build_entity()
+ * is invoked by comment_form_submit_build_comment(), because it alters the
+ * values of attached fields.
+ */
+function locale_field_comment_form_submit($form, &$form_state) {
+ locale_field_entity_form_submit('comment', $form, $form_state);
+}
+
+/**
+ * Handles field language on submit for the given entity type.
+ *
+ * Checks if Locale is registered as a translation handler and handle possible
+ * language changes.
+ */
+function locale_field_entity_form_submit($entity_type, $form, &$form_state ) {
+ if (field_has_translation_handler($entity_type, 'locale')) {
+ $entity = (object) $form_state['values'];
+ $current_language = entity_language($entity_type, $entity);
+ list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+ foreach (field_info_instances($entity_type, $bundle) as $instance) {
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
$previous_language = $form[$field_name]['#language'];
@@ -407,7 +440,7 @@ function locale_field_node_form_submit($form, &$form_state) {
// Handle a possible language change: new language values are inserted,
// previous ones are deleted.
if ($field['translatable'] && $previous_language != $current_language) {
- $form_state['values'][$field_name][$current_language] = $node->{$field_name}[$previous_language];
+ $form_state['values'][$field_name][$current_language] = $entity->{$field_name}[$previous_language];
$form_state['values'][$field_name][$previous_language] = array();
}
}
@@ -491,6 +524,9 @@ function locale_field_language_fallback(&$display_language, $entity, $langcode)
*/
function locale_entity_info_alter(&$entity_info) {
$entity_info['node']['translation']['locale'] = TRUE;
+ if (isset($entity_info['comment'])) {
+ $entity_info['comment']['translation']['locale'] = TRUE;
+ }
}
/**
@@ -1060,15 +1096,3 @@ function locale_url_outbound_alter(&$path, &$options, $original_path) {
}
}
}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function locale_form_comment_form_alter(&$form, &$form_state, $form_id) {
- // If a content type has multilingual support we set the content language as
- // comment language.
- if ($form['language']['#value'] == LANGUAGE_NONE && locale_multilingual_node_type($form['#node']->type)) {
- global $language_content;
- $form['language']['#value'] = $language_content->language;
- }
-}
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 632506e13..d88634e19 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -2758,7 +2758,7 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
parent::setUp('locale', 'locale_test');
// Create and login user.
- $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'administer content types', 'create article content'));
+ $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'administer content types', 'administer comments', 'create article content'));
$this->drupalLogin($admin_user);
// Add language.
@@ -2787,6 +2787,12 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
// French no matter what path prefix the URLs have.
$edit = array('language' => 'fr');
$this->drupalPost("user/{$admin_user->uid}/edit", $edit, t('Save'));
+
+ // Make comment body translatable.
+ $field = field_info_field('comment_body');
+ $field['translatable'] = TRUE;
+ field_update_field($field);
+ $this->assertTrue(field_is_translatable('comment', $field), 'Comment body is translatable.');
}
/**
@@ -2817,22 +2823,46 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
foreach (language_list() as $langcode => $language) {
// Post a comment with content language $langcode.
$prefix = empty($language->prefix) ? '' : $language->prefix . '/';
- $edit = array("comment_body[$language_none][0][value]" => $this->randomName());
- $this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Save'));
+ $comment_values[$node_langcode][$langcode] = $this->randomName();
+ // Initially field form widgets have no language.
+ $edit = array(
+ 'subject' => $this->randomName(),
+ "comment_body[$language_none][0][value]" => $comment_values[$node_langcode][$langcode],
+ );
+ $this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Preview'));
+ // After the first submit the submitted entity language is taken into
+ // account.
+ $edit = array(
+ 'subject' => $edit['subject'],
+ "comment_body[$langcode][0][value]" => $comment_values[$node_langcode][$langcode],
+ );
+ $this->drupalPost(NULL, $edit, t('Save'));
// Check that comment language matches the current content language.
- $comment = db_select('comment', 'c')
- ->fields('c')
+ $cid = db_select('comment', 'c')
+ ->fields('c', array('cid'))
->condition('nid', $node->nid)
->orderBy('cid', 'DESC')
+ ->range(0, 1)
->execute()
- ->fetchObject();
+ ->fetchField();
+ $comment = comment_load($cid);
$comment_langcode = entity_language('comment', $comment);
$args = array('%node_language' => $node_langcode, '%comment_language' => $comment_langcode, '%langcode' => $langcode);
$this->assertEqual($comment_langcode, $langcode, t('The comment posted with content language %langcode and belonging to the node with language %node_language has language %comment_language', $args));
+ $this->assertEqual($comment->comment_body[$langcode][0]['value'], $comment_values[$node_langcode][$langcode], 'Comment body correctly stored.');
+ }
+ }
+
+ // Check that comment bodies appear in the administration UI.
+ $this->drupalGet('admin/content/comment');
+ foreach ($comment_values as $node_values) {
+ foreach ($node_values as $value) {
+ $this->assertRaw($value);
}
}
}
+
}
/**
diff --git a/modules/menu/menu.api.php b/modules/menu/menu.api.php
index 3f3818e17..22d93ef3e 100644
--- a/modules/menu/menu.api.php
+++ b/modules/menu/menu.api.php
@@ -11,7 +11,7 @@
*/
/**
- * Informs modules that a custom menu was created.
+ * Respond to a custom menu creation.
*
* This hook is used to notify modules that a custom menu has been created.
* Contributed modules may use the information to perform actions based on the
@@ -34,7 +34,7 @@ function hook_menu_insert($menu) {
}
/**
- * Informs modules that a custom menu was updated.
+ * Respond to a custom menu update.
*
* This hook is used to notify modules that a custom menu has been updated.
* Contributed modules may use the information to perform actions based on the
@@ -59,14 +59,14 @@ function hook_menu_update($menu) {
}
/**
- * Informs modules that a custom menu was deleted.
+ * Respond to a custom menu deletion.
*
* This hook is used to notify modules that a custom menu along with all links
* contained in it (if any) has been deleted. Contributed modules may use the
* information to perform actions based on the information entered into the menu
* system.
*
- * @param $link
+ * @param $menu
* An array representing a custom menu:
* - menu_name: The unique name of the custom menu.
* - title: The human readable menu title.
diff --git a/modules/node/content_types.inc b/modules/node/content_types.inc
index 72adc3491..4b722ee02 100644
--- a/modules/node/content_types.inc
+++ b/modules/node/content_types.inc
@@ -2,7 +2,7 @@
/**
* @file
- * Content type editing UI.
+ * Content type editing user interface.
*/
/**
@@ -388,8 +388,7 @@ function node_node_type_update($info) {
}
/**
- * Resets all of the relevant fields of a module-defined node type to their
- * default values.
+ * Resets relevant fields of a module-defined node type to their default values.
*
* @param $type
* The node type to reset. The node type is passed back by reference with its
@@ -410,6 +409,8 @@ function node_type_reset($type) {
/**
* Menu callback; delete a single content type.
+ *
+ * @ingroup forms
*/
function node_type_delete_confirm($form, &$form_state, $type) {
$form['type'] = array('#type' => 'value', '#value' => $type->type);
@@ -430,6 +431,8 @@ function node_type_delete_confirm($form, &$form_state, $type) {
/**
* Process content type delete confirm submissions.
+ *
+ * @see node_type_delete_confirm()
*/
function node_type_delete_confirm_submit($form, &$form_state) {
node_type_delete($form_state['values']['type']);
diff --git a/modules/node/node.admin.inc b/modules/node/node.admin.inc
index 1508bc054..be09b37cc 100644
--- a/modules/node/node.admin.inc
+++ b/modules/node/node.admin.inc
@@ -7,6 +7,10 @@
/**
* Menu callback: confirm rebuilding of permissions.
+ *
+ * @see node_configure_rebuild_confirm_submit()
+ * @see node_menu()
+ * @ingroup forms
*/
function node_configure_rebuild_confirm() {
return confirm_form(array(), t('Are you sure you want to rebuild the permissions on site content?'),
@@ -15,6 +19,8 @@ function node_configure_rebuild_confirm() {
/**
* Handler for wipe confirmation
+ *
+ * @see node_configure_rebuild_confirm()
*/
function node_configure_rebuild_confirm_submit($form, &$form_state) {
node_access_rebuild(TRUE);
@@ -66,6 +72,9 @@ function node_node_operations() {
/**
* List node administration filters that can be applied.
+ *
+ * @return
+ * An associative array of filters.
*/
function node_filters() {
// Regular filters
@@ -110,7 +119,7 @@ function node_filters() {
}
/**
- * Apply filters for node administration filters based on session.
+ * Applies filters for node administration filters based on session.
*
* @param $query
* A SelectQuery to which the filters should be applied.
@@ -133,7 +142,16 @@ function node_build_filter_query(SelectQueryInterface $query) {
}
/**
- * Return form for node administration filters.
+ * Returns the node administration filters form array to node_admin_content().
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
+ *
+ * @ingroup forms
*/
function node_filter_form() {
$session = isset($_SESSION['node_overview_filter']) ? $_SESSION['node_overview_filter'] : array();
@@ -208,7 +226,15 @@ function node_filter_form() {
}
/**
- * Process result from node administration filter form.
+ * Form submission handler for node_filter_form().
+ *
+ * @see node_admin_content()
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
*/
function node_filter_form_submit($form, &$form_state) {
$filters = node_filters();
@@ -240,15 +266,15 @@ function node_filter_form_submit($form, &$form_state) {
* Make mass update of nodes, changing all nodes in the $nodes array
* to update them with the field values in $updates.
*
- * IMPORTANT NOTE: This function is intended to work when called
- * from a form submit handler. Calling it outside of the form submission
- * process may not work correctly.
+ * IMPORTANT NOTE: This function is intended to work when called from a form
+ * submission handler. Calling it outside of the form submission process may not
+ * work correctly.
*
* @param array $nodes
* Array of node nids to update.
* @param array $updates
- * Array of key/value pairs with node field names and the
- * value to update that field to.
+ * Array of key/value pairs with node field names and the value to update that
+ * field to.
*/
function node_mass_update($nodes, $updates) {
// We use batch processing to prevent timeout when updating a large number
@@ -279,7 +305,17 @@ function node_mass_update($nodes, $updates) {
}
/**
- * Node Mass Update - helper function.
+ * Updates individual nodes when fewer than 10 are queued.
+ *
+ * @param $nid
+ * ID of node to update.
+ * @param $updates
+ * Associative array of updates.
+ *
+ * @return object
+ * An updated node object.
+ *
+ * @see node_mass_update()
*/
function _node_mass_update_helper($nid, $updates) {
$node = node_load($nid, NULL, TRUE);
@@ -293,7 +329,14 @@ function _node_mass_update_helper($nid, $updates) {
}
/**
- * Node Mass Update Batch operation
+ * Executes a batch operation for node_mass_update().
+ *
+ * @param array $nodes
+ * An array of node IDs.
+ * @param array $updates
+ * Associative array of updates.
+ * @param array $context
+ * An array of contextual key/values.
*/
function _node_mass_update_batch_process($nodes, $updates, &$context) {
if (!isset($context['sandbox']['progress'])) {
@@ -324,7 +367,15 @@ function _node_mass_update_batch_process($nodes, $updates, &$context) {
}
/**
- * Node Mass Update Batch 'finished' callback.
+ * Menu callback: Reports the status of batch operation for node_mass_update().
+ *
+ * @param bool $success
+ * A boolean indicating whether the batch mass update operation successfully
+ * concluded.
+ * @param int $results
+ * The number of nodes updated via the batch mode process.
+ * @param array $operations
+ * An array of function calls (not used in this function).
*/
function _node_mass_update_batch_finished($success, $results, $operations) {
if ($success) {
@@ -339,7 +390,17 @@ function _node_mass_update_batch_finished($success, $results, $operations) {
}
/**
- * Menu callback: content administration.
+ * Page callback: Form constructor for the content administration form.
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_menu()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
+ * @ingroup forms
*/
function node_admin_content($form, $form_state) {
if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
@@ -354,6 +415,15 @@ function node_admin_content($form, $form_state) {
/**
* Form builder: Builds the node administration overview.
+ *
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
+ *
+ * @ingroup forms
*/
function node_admin_nodes() {
$admin_access = user_access('administer nodes');
@@ -525,8 +595,15 @@ function node_admin_nodes() {
/**
* Validate node_admin_nodes form submissions.
*
- * Check if any nodes have been selected to perform the chosen
- * 'Update option' on.
+ * Checks whether any nodes have been selected to perform the chosen 'Update
+ * option' on.
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
*/
function node_admin_nodes_validate($form, &$form_state) {
// Error if there are no items to select.
@@ -538,7 +615,14 @@ function node_admin_nodes_validate($form, &$form_state) {
/**
* Process node_admin_nodes form submissions.
*
- * Execute the chosen 'Update option' on the selected nodes.
+ * Executes the chosen 'Update option' on the selected nodes.
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm()
+ * @see node_multiple_delete_confirm_submit()
*/
function node_admin_nodes_submit($form, &$form_state) {
$operations = module_invoke_all('node_operations');
@@ -564,6 +648,17 @@ function node_admin_nodes_submit($form, &$form_state) {
}
}
+/**
+ * Multiple node deletion confirmation form for node_admin_content().
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm_submit()
+ * @ingroup forms
+ */
function node_multiple_delete_confirm($form, &$form_state, $nodes) {
$form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
// array_filter returns only elements with TRUE values
@@ -587,6 +682,16 @@ function node_multiple_delete_confirm($form, &$form_state, $nodes) {
t('Delete'), t('Cancel'));
}
+/**
+ * Form submission handler for node_multiple_delete_confirm().
+ *
+ * @see node_admin_nodes()
+ * @see node_admin_nodes_submit()
+ * @see node_admin_nodes_validate()
+ * @see node_filter_form()
+ * @see node_filter_form_submit()
+ * @see node_multiple_delete_confirm()
+ */
function node_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
node_delete_multiple(array_keys($form_state['values']['nodes']));
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index 052effc9b..f8dcfdeff 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -11,8 +11,8 @@
* Functions to define and modify content types.
*
* Each content type is maintained by a primary module, which is either
- * node.module (for content types created in the user interface) or the
- * module that implements hook_node_info() to define the content type.
+ * node.module (for content types created in the user interface) or the module
+ * that implements hook_node_info() to define the content type.
*
* During node operations (create, update, view, delete, etc.), there are
* several sets of hooks that get invoked to allow modules to modify the base
@@ -22,10 +22,10 @@
* function prefix. For example, poll.module defines the base for the Poll
* content type as "poll", so during creation of a poll node, hook_insert() is
* only invoked by calling poll_insert().
- * - All-module hooks: This set of hooks is invoked on all implementing
- * modules, to allow other modules to modify what the primary node module is
- * doing. For example, hook_node_insert() is invoked on all modules when
- * creating a poll node.
+ * - All-module hooks: This set of hooks is invoked on all implementing modules,
+ * to allow other modules to modify what the primary node module is doing. For
+ * example, hook_node_insert() is invoked on all modules when creating a poll
+ * node.
* - Field hooks: Hooks related to the fields attached to the node. These are
* invoked from the field operations functions described below, and can be
* either field-type-specific or all-module hooks.
@@ -56,16 +56,15 @@
* - hook_entity_update() (all)
* - hook_node_access_records() (all)
* - hook_node_access_records_alter() (all)
- * - Loading a node (calling node_load(), node_load_multiple(), or
- * entity_load() with $entity_type of 'node'):
+ * - Loading a node (calling node_load(), node_load_multiple() or entity_load()
+ * with $entity_type of 'node'):
* - Node and revision information is read from database.
* - hook_load() (node-type-specific)
* - field_attach_load_revision() and field_attach_load()
* - hook_entity_load() (all)
* - hook_node_load() (all)
* - Viewing a single node (calling node_view() - note that the input to
- * node_view() is a loaded node, so the Loading steps above are already
- * done):
+ * node_view() is a loaded node, so the Loading steps above are already done):
* - hook_view() (node-type-specific)
* - field_attach_prepare_view()
* - hook_entity_prepare_view() (all)
@@ -97,9 +96,8 @@
* - Revision information is deleted from database
* - hook_node_revision_delete() (all)
* - field_attach_delete_revision()
- * - Preparing a node for editing (calling node_form() - note that if it's
- * an existing node, it will already be loaded; see the Loading section
- * above):
+ * - Preparing a node for editing (calling node_form() - note that if it is an
+ * existing node, it will already be loaded; see the Loading section above):
* - hook_prepare() (node-type-specific)
* - hook_node_prepare() (all)
* - hook_form() (node-type-specific)
@@ -137,16 +135,16 @@
* associated with permission to view, edit, and delete individual nodes.
*
* The realms and grant IDs can be arbitrarily defined by your node access
- * module; it is common to use role IDs as grant IDs, but that is not
- * required. Your module could instead maintain its own list of users, where
- * each list has an ID. In that case, the return value of this hook would be
- * an array of the list IDs that this user is a member of.
+ * module; it is common to use role IDs as grant IDs, but that is not required.
+ * Your module could instead maintain its own list of users, where each list has
+ * an ID. In that case, the return value of this hook would be an array of the
+ * list IDs that this user is a member of.
*
- * A node access module may implement as many realms as necessary to
- * properly define the access privileges for the nodes. Note that the system
- * makes no distinction between published and unpublished nodes. It is the
- * module's responsibility to provide appropriate realms to limit access to
- * unpublished content.
+ * A node access module may implement as many realms as necessary to properly
+ * define the access privileges for the nodes. Note that the system makes no
+ * distinction between published and unpublished nodes. It is the module's
+ * responsibility to provide appropriate realms to limit access to unpublished
+ * content.
*
* Node access records are stored in the {node_access} table and define which
* grants are required to access a node. There is a special case for the view
@@ -183,7 +181,7 @@
* @param $account
* The user object whose grants are requested.
* @param $op
- * The node operation to be performed, such as "view", "update", or "delete".
+ * The node operation to be performed, such as 'view', 'update', or 'delete'.
*
* @return
* An array whose keys are "realms" of grants, and whose values are arrays of
@@ -264,6 +262,7 @@ function hook_node_grants($account, $op) {
* @return
* An array of grants as defined above.
*
+ * @see hook_node_access_records_alter()
* @ingroup node_access
*/
function hook_node_access_records($node) {
@@ -350,12 +349,11 @@ function hook_node_access_records_alter(&$grants, $node) {
* Alter user access rules when trying to view, edit or delete a node.
*
* Node access modules establish rules for user access to content.
- * hook_node_grants() defines permissions for a user to view, edit or
- * delete nodes by building a $grants array that indicates the permissions
- * assigned to the user by each node access module. This hook is called to allow
- * modules to modify the $grants array by reference, so the interaction of
- * multiple node access modules can be altered or advanced business logic can be
- * applied.
+ * hook_node_grants() defines permissions for a user to view, edit or delete
+ * nodes by building a $grants array that indicates the permissions assigned to
+ * the user by each node access module. This hook is called to allow modules to
+ * modify the $grants array by reference, so the interaction of multiple node
+ * access modules can be altered or advanced business logic can be applied.
*
* @see hook_node_grants()
*
@@ -374,8 +372,8 @@ function hook_node_access_records_alter(&$grants, $node) {
* @param $op
* The operation being performed, 'view', 'update' or 'delete'.
*
- * Developers may use this hook to either add additional grants to a user
- * or to remove existing grants. These rules are typically based on either the
+ * Developers may use this hook to either add additional grants to a user or to
+ * remove existing grants. These rules are typically based on either the
* permissions assigned to a user role, or specific attributes of a user
* account.
*
@@ -412,10 +410,10 @@ function hook_node_grants_alter(&$grants, $account, $op) {
* @return
* An array of operations. Each operation is an associative array that may
* contain the following key-value pairs:
- * - 'label': Required. The label for the operation, displayed in the dropdown
+ * - label: (required) The label for the operation, displayed in the dropdown
* menu.
- * - 'callback': Required. The function to call for the operation.
- * - 'callback arguments': Optional. An array of additional arguments to pass
+ * - callback: (required) The function to call for the operation.
+ * - callback arguments: (optional) An array of additional arguments to pass
* to the callback function.
*/
function hook_node_operations() {
@@ -528,11 +526,10 @@ function hook_node_insert($node) {
/**
* Act on arbitrary nodes being loaded from the database.
*
- * This hook should be used to add information that is not in the node or
- * node revisions table, not to replace information that is in these tables
- * (which could interfere with the entity cache). For performance reasons,
- * information for all available nodes should be loaded in a single query where
- * possible.
+ * This hook should be used to add information that is not in the node or node
+ * revisions table, not to replace information that is in these tables (which
+ * could interfere with the entity cache). For performance reasons, information
+ * for all available nodes should be loaded in a single query where possible.
*
* This hook is invoked during node loading, which is handled by entity_load(),
* via classes NodeController and DrupalDefaultEntityController. After the node
@@ -572,15 +569,15 @@ function hook_node_load($nodes, $types) {
* Modules may implement this hook if they want to have a say in whether or not
* a given user has access to perform a given operation on a node.
*
- * The administrative account (user ID #1) always passes any access check,
- * so this hook is not called in that case. Users with the "bypass node access"
+ * The administrative account (user ID #1) always passes any access check, so
+ * this hook is not called in that case. Users with the "bypass node access"
* permission may always view and edit content through the administrative
* interface.
*
- * Note that not all modules will want to influence access on all
- * node types. If your module does not want to actively grant or
- * block access, return NODE_ACCESS_IGNORE or simply return nothing.
- * Blindly returning FALSE will break other node access modules.
+ * Note that not all modules will want to influence access on all node types. If
+ * your module does not want to actively grant or block access, return
+ * NODE_ACCESS_IGNORE or simply return nothing. Blindly returning FALSE will
+ * break other node access modules.
*
* Also note that this function isn't called for node listings (e.g., RSS feeds,
* the default home page at path 'node', a recent content block, etc.) See
@@ -651,17 +648,17 @@ function hook_node_prepare($node) {
/**
* Act on a node being displayed as a search result.
*
- * This hook is invoked from node_search_execute(), after node_load()
- * and node_view() have been called.
+ * This hook is invoked from node_search_execute(), after node_load() and
+ * node_view() have been called.
*
* @param $node
* The node being displayed in a search result.
*
* @return array
* Extra information to be displayed with search result. This information
- * should be presented as an associative array. It will be concatenated
- * with the post information (last updated, author) in the default search
- * result theming.
+ * should be presented as an associative array. It will be concatenated with
+ * the post information (last updated, author) in the default search result
+ * theming.
*
* @see template_preprocess_search_result()
* @see search-result.tpl.php
@@ -724,8 +721,8 @@ function hook_node_update($node) {
/**
* Act on a node being indexed for searching.
*
- * This hook is invoked during search indexing, after node_load(), and after
- * the result of node_view() is added as $node->rendered to the node object.
+ * This hook is invoked during search indexing, after node_load(), and after the
+ * result of node_view() is added as $node->rendered to the node object.
*
* @param $node
* The node being indexed.
@@ -756,8 +753,8 @@ function hook_node_update_index($node) {
*
* Note: Changes made to the $node object within your hook implementation will
* have no effect. The preferred method to change a node's content is to use
- * hook_node_presave() instead. If it is really necessary to change
- * the node at the validate stage, you can use form_set_value().
+ * hook_node_presave() instead. If it is really necessary to change the node at
+ * the validate stage, you can use form_set_value().
*
* @param $node
* The node being validated.
@@ -874,8 +871,8 @@ function hook_node_view_alter(&$build) {
*
* This hook allows a module to define one or more of its own node types. For
* example, the blog module uses it to define a blog node-type named "Blog
- * entry." The name and attributes of each desired node type are specified in
- * an array returned by the hook.
+ * entry." The name and attributes of each desired node type are specified in an
+ * array returned by the hook.
*
* Only module-provided node types should be defined through this hook. User-
* provided (or 'custom') node types should be defined only in the 'node_type'
@@ -887,22 +884,22 @@ function hook_node_view_alter(&$build) {
* contains a sub-array for each node type, with the machine-readable type
* name as the key. Each sub-array has up to 10 attributes. Possible
* attributes:
- * - "name": the human-readable name of the node type. Required.
- * - "base": the base string used to construct callbacks corresponding to
- * this node type.
- * (i.e. if base is defined as example_foo, then example_foo_insert will
- * be called when inserting a node of that type). This string is usually
- * the name of the module, but not always. Required.
- * - "description": a brief description of the node type. Required.
- * - "help": help information shown to the user when creating a node of
- * this type.. Optional (defaults to '').
- * - "has_title": boolean indicating whether or not this node type has a title
- * field. Optional (defaults to TRUE).
- * - "title_label": the label for the title field of this content type.
- * Optional (defaults to 'Title').
- * - "locked": boolean indicating whether the administrator can change the
- * machine name of this type. FALSE = changeable (not locked),
- * TRUE = unchangeable (locked). Optional (defaults to TRUE).
+ * - name: (required) The human-readable name of the node type.
+ * - base: (required) The base string used to construct callbacks
+ * corresponding to this node type (for example, if base is defined as
+ * example_foo, then example_foo_insert will be called when inserting a node
+ * of that type). This string is usually the name of the module, but not
+ * always.
+ * - description: (required) A brief description of the node type.
+ * - help: (optional) Help information shown to the user when creating a node
+ * of this type.
+ * - has_title: (optional) A Boolean indicating whether or not this node type
+ * has a title field.
+ * - title_label: (optional) The label for the title field of this content
+ * type.
+ * - locked: (optional) A Boolean indicating whether the administrator can
+ * change the machine name of this type. FALSE = changeable (not locked),
+ * TRUE = unchangeable (locked).
*
* The machine name of a node type should contain only letters, numbers, and
* underscores. Underscores will be converted into hyphens for the purpose of
@@ -950,20 +947,20 @@ function hook_node_info() {
* corresponding to the internal name of the ranking mechanism, such as
* 'recent', or 'comments'. The values should be arrays themselves, with the
* following keys available:
- * - "title": the human readable name of the ranking mechanism. Required.
- * - "join": part of a query string to join to any additional necessary
- * table. This is not necessary if the table required is already joined to
- * by the base query, such as for the {node} table. Other tables should use
- * the full table name as an alias to avoid naming collisions. Optional.
- * - "score": part of a query string to calculate the score for the ranking
- * mechanism based on values in the database. This does not need to be
- * wrapped in parentheses, as it will be done automatically; it also does
- * not need to take the weighted system into account, as it will be done
- * automatically. It does, however, need to calculate a decimal between
+ * - title: (required) The human readable name of the ranking mechanism.
+ * - join: (optional) The part of a query string to join to any additional
+ * necessary table. This is not necessary if the table required is already
+ * joined to by the base query, such as for the {node} table. Other tables
+ * should use the full table name as an alias to avoid naming collisions.
+ * - score: (required) The part of a query string to calculate the score for
+ * the ranking mechanism based on values in the database. This does not need
+ * to be wrapped in parentheses, as it will be done automatically; it also
+ * does not need to take the weighted system into account, as it will be
+ * done automatically. It does, however, need to calculate a decimal between
* 0 and 1; be careful not to cast the entire score to an integer by
- * inadvertently introducing a variable argument. Required.
- * - "arguments": if any arguments are required for the score, they can be
- * specified in an array here.
+ * inadvertently introducing a variable argument.
+ * - arguments: (optional) If any arguments are required for the score, they
+ * can be specified in an array here.
*
* @ingroup node_api_hooks
*/
@@ -990,8 +987,8 @@ function hook_ranking() {
/**
* Respond to node type creation.
*
- * This hook is invoked from node_type_save() after the node type is added
- * to the database.
+ * This hook is invoked from node_type_save() after the node type is added to
+ * the database.
*
* @param $info
* The node type object that is being created.
@@ -1003,8 +1000,8 @@ function hook_node_type_insert($info) {
/**
* Respond to node type updates.
*
- * This hook is invoked from node_type_save() after the node type is updated
- * in the database.
+ * This hook is invoked from node_type_save() after the node type is updated in
+ * the database.
*
* @param $info
* The node type object that is being updated.
@@ -1258,25 +1255,24 @@ function hook_validate($node, $form, &$form_state) {
* This hook is invoked only on the module that defines the node's content type
* (use hook_node_view() to act on all node views).
*
- * This hook is invoked during node viewing after the node is fully loaded,
- * so that the node type module can define a custom method for display, or
- * add to the default display.
+ * This hook is invoked during node viewing after the node is fully loaded, so
+ * that the node type module can define a custom method for display, or add to
+ * the default display.
*
* @param $node
* The node to be displayed, as returned by node_load().
* @param $view_mode
* View mode, e.g. 'full', 'teaser', ...
* @return
- * $node. The passed $node parameter should be modified as necessary and
- * returned so it can be properly presented. Nodes are prepared for display
- * by assembling a structured array, formatted as in the Form API, in
- * $node->content. As with Form API arrays, the #weight property can be
- * used to control the relative positions of added elements. After this
- * hook is invoked, node_view() calls field_attach_view() to add field
- * views to $node->content, and then invokes hook_node_view() and
- * hook_node_view_alter(), so if you want to affect the final
- * view of the node, you might consider implementing one of these hooks
- * instead.
+ * The passed $node parameter should be modified as necessary and returned so
+ * it can be properly presented. Nodes are prepared for display by assembling
+ * a structured array, formatted as in the Form API, in $node->content. As
+ * with Form API arrays, the #weight property can be used to control the
+ * relative positions of added elements. After this hook is invoked,
+ * node_view() calls field_attach_view() to add field views to $node->content,
+ * and then invokes hook_node_view() and hook_node_view_alter(), so if you
+ * want to affect the final view of the node, you might consider implementing
+ * one of these hooks instead.
*
* @ingroup node_api_hooks
*/
diff --git a/modules/node/node.install b/modules/node/node.install
index 16d3dbaa0..43bfd531f 100644
--- a/modules/node/node.install
+++ b/modules/node/node.install
@@ -914,6 +914,7 @@ function node_update_7012() {
* Change {node}.vid default value from 0 to NULL to avoid deadlock issues on MySQL.
*/
function node_update_7013() {
+ db_drop_unique_key('node', 'vid');
db_change_field('node', 'vid', 'vid', array(
'description' => 'The current {node_revision}.vid version identifier.',
'type' => 'int',
@@ -921,6 +922,7 @@ function node_update_7013() {
'not null' => FALSE,
'default' => NULL,
));
+ db_add_unique_key('node', 'vid', array('vid'));
}
/**
diff --git a/modules/node/node.module b/modules/node/node.module
index d86c74d2d..abcd4e0c5 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -200,8 +200,8 @@ function node_entity_info() {
),
);
- // Search integration is provided by node.module, so search-related
- // view modes for nodes are defined here and not in search.module.
+ // Search integration is provided by node.module, so search-related view modes
+ // for nodes are defined here and not in search.module.
if (module_exists('search')) {
$return['node']['view modes'] += array(
'search_index' => array(
@@ -244,6 +244,12 @@ function node_field_display_node_alter(&$display, $context) {
/**
* Entity URI callback.
+ *
+ * @param $node
+ * A node entity.
+ *
+ * @return array
+ * An array with 'path' as the key and the path to the node as its value.
*/
function node_uri($node) {
return array(
@@ -296,7 +302,7 @@ function node_title_list($result, $title = NULL) {
}
/**
- * Update the 'last viewed' timestamp of the specified node for current user.
+ * Updates the 'last viewed' timestamp of the specified node for current user.
*
* @param $node
* A node object.
@@ -315,8 +321,14 @@ function node_tag_new($node) {
}
/**
- * Retrieves the timestamp at which the current user last viewed the
- * specified node.
+ * Retrieves the timestamp for the current user's last view of a specified node.
+ *
+ * @param $nid
+ * A node ID.
+ *
+ * @return
+ * If a node has been previously viewed by the user, the timestamp in seconds
+ * of when the last view occurred; otherwise, zero.
*/
function node_last_viewed($nid) {
global $user;
@@ -330,12 +342,13 @@ function node_last_viewed($nid) {
}
/**
- * Decide on the type of marker to be displayed for a given node.
+ * Determines the type of marker to be displayed for a given node.
*
* @param $nid
* Node ID whose history supplies the "last viewed" timestamp.
* @param $timestamp
* Time which is compared against node's "last viewed" timestamp.
+ *
* @return
* One of the MARK constants.
*/
@@ -359,7 +372,7 @@ function node_mark($nid, $timestamp) {
}
/**
- * Extract the type name.
+ * Extracts the type name.
*
* @param $node
* Either a string or object, containing the node type information.
@@ -461,6 +474,8 @@ function node_type_get_name($node) {
* node_type_save(), and obsolete ones are deleted via a call to
* node_type_delete(). See _node_types_build() for an explanation of the new
* and obsolete types.
+ *
+ * @see _node_types_build()
*/
function node_types_rebuild() {
_node_types_build(TRUE);
@@ -483,11 +498,34 @@ function node_type_load($name) {
/**
* Saves a node type to the database.
*
- * @param $info
- * The node type to save, as an object.
- *
- * @return
- * Status flag indicating outcome of the operation.
+ * @param object $info
+ * The node type to save; an object with the following properties:
+ * - type: A string giving the machine name of the node type.
+ * - name: A string giving the human-readable name of the node type.
+ * - base: A string that indicates the base string for hook functions. For
+ * example, 'node_content' is the value used by the UI when creating a new
+ * node type.
+ * - description: A string that describes the node type.
+ * - help: A string giving the help information shown to the user when
+ * creating a node of this type.
+ * - custom: TRUE or FALSE indicating whether this type is defined by a module
+ * (FALSE) or by a user (TRUE) via Add Content Type.
+ * - modified: TRUE or FALSE indicating whether this type has been modified by
+ * an administrator. Currently not used in any way.
+ * - locked: TRUE or FALSE indicating whether the administrator can change the
+ * machine name of this type.
+ * - disabled: TRUE or FALSE indicating whether this type has been disabled.
+ * - has_title: TRUE or FALSE indicating whether this type uses the node title
+ * field.
+ * - title_label: A string containing the label for the title.
+ * - module: A string giving the module defining this type of node.
+ * - orig_type: A string giving the original machine-readable name of this
+ * node type. This may be different from the current type name if the
+ * 'locked' key is FALSE.
+ *
+ * @return int
+ * A status flag indicating the outcome of the operation, either SAVED_NEW or
+ * SAVED_UPDATED.
*/
function node_type_save($info) {
$existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
@@ -540,7 +578,7 @@ function node_type_save($info) {
}
/**
- * Add default body field to a node type.
+ * Adds default body field to a node type.
*
* @param $type
* A node type object.
@@ -655,6 +693,7 @@ function node_type_update_nodes($old_type, $type) {
*
* @param $rebuild
* TRUE to rebuild node types. Equivalent to calling node_types_rebuild().
+ *
* @return
* An object with two properties:
* - names: Associative array of the names of node types, keyed by the type.
@@ -761,8 +800,9 @@ function node_type_cache_reset() {
* which prevents users from changing the machine name of the type.
*
* @param $info
- * An object or array containing values to override the defaults. See
- * hook_node_info() for details on what the array elements mean.
+ * (optional) An object or array containing values to override the defaults.
+ * See hook_node_info() for details on what the array elements mean. Defaults
+ * to an empty array.
*
* @return
* A node type object, with missing values in $info set to their defaults.
@@ -845,12 +885,13 @@ function node_rdf_mapping() {
}
/**
- * Determine whether a node hook exists.
+ * Determines whether a node hook exists.
*
* @param $node
* A node object or a string containing the node type.
* @param $hook
* A string containing the name of the hook.
+ *
* @return
* TRUE if the $hook exists in the node type of $node.
*/
@@ -860,7 +901,7 @@ function node_hook($node, $hook) {
}
/**
- * Invoke a node hook.
+ * Invokes a node hook.
*
* @param $node
* A node object or a string containing the node type.
@@ -868,6 +909,7 @@ function node_hook($node, $hook) {
* A string containing the name of the hook.
* @param $a2, $a3, $a4
* Arguments to pass on to the hook, after the $node argument.
+ *
* @return
* The returned value of the invoked hook.
*/
@@ -880,11 +922,11 @@ function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
}
/**
- * Load node entities from the database.
+ * Loads node entities from the database.
*
* This function should be used whenever you need to load more than one node
- * from the database. Nodes are loaded into memory and will not require
- * database access if loaded again during the same page request.
+ * from the database. Nodes are loaded into memory and will not require database
+ * access if loaded again during the same page request.
*
* @see entity_load()
* @see EntityFieldQuery
@@ -910,7 +952,7 @@ function node_load_multiple($nids = array(), $conditions = array(), $reset = FAL
}
/**
- * Load a node object from the database.
+ * Loads a node object from the database.
*
* @param $nid
* The node ID.
@@ -934,6 +976,9 @@ function node_load($nid = NULL, $vid = NULL, $reset = FALSE) {
*
* Fills in a few default values, and then invokes hook_prepare() on the node
* type module, and hook_node_prepare() on all modules.
+ *
+ * @param $node
+ * A node object.
*/
function node_object_prepare($node) {
// Set up default values, if required.
@@ -963,7 +1008,9 @@ function node_object_prepare($node) {
}
/**
- * Perform validation checks on the given node.
+ * Implements hook_validate().
+ *
+ * Performs validation checks on the given node.
*/
function node_validate($node, $form, &$form_state) {
$type = node_type_get_type($node);
@@ -1000,7 +1047,13 @@ function node_validate($node, $form, &$form_state) {
}
/**
- * Prepare node for saving by populating author and creation date.
+ * Prepares node for saving by populating author and creation date.
+ *
+ * @param $node
+ * A node object.
+ *
+ * @return
+ * An updated node object.
*/
function node_submit($node) {
// A user might assign the node author by entering a user name in the node
@@ -1021,7 +1074,7 @@ function node_submit($node) {
}
/**
- * Save changes to a node or add a new node.
+ * Saves changes to a node or adds a new node.
*
* @param $node
* The $node object to be saved. If $node->nid is
@@ -1159,6 +1212,13 @@ function node_save($node) {
* Helper function to save a revision with the uid of the current user.
*
* The resulting revision ID is available afterward in $node->vid.
+ *
+ * @param $node
+ * A node object.
+ * @param $uid
+ * The current user's UID.
+ * @param $update
+ * (optional) An array of primary keys' field names to update.
*/
function _node_save_revision($node, $uid, $update = NULL) {
$temp_uid = $node->uid;
@@ -1174,7 +1234,7 @@ function _node_save_revision($node, $uid, $update = NULL) {
}
/**
- * Delete a node.
+ * Deletes a node.
*
* @param $nid
* A node ID.
@@ -1184,7 +1244,7 @@ function node_delete($nid) {
}
/**
- * Delete multiple nodes.
+ * Deletes multiple nodes.
*
* @param $nids
* An array of node IDs.
@@ -1237,7 +1297,7 @@ function node_delete_multiple($nids) {
}
/**
- * Delete a node revision.
+ * Deletes a node revision.
*
* @param $revision_id
* The revision ID to delete.
@@ -1262,7 +1322,7 @@ function node_revision_delete($revision_id) {
}
/**
- * Generate an array for rendering the given node.
+ * Generates an array for rendering the given node.
*
* @param $node
* A node object.
@@ -1367,8 +1427,8 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
entity_prepare_view('node', array($node->nid => $node), $langcode);
$node->content += field_attach_view('node', $node, $view_mode, $langcode);
- // Always display a read more link on teasers because we have no way
- // to know when a teaser view is different than a full view.
+ // Always display a read more link on teasers because we have no way to know
+ // when a teaser view is different than a full view.
$links = array();
$node->content['links'] = array(
'#theme' => 'links__node',
@@ -1400,12 +1460,13 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
}
/**
- * Generate an array which displays a node detail page.
+ * Generates an array which displays a node detail page.
*
* @param $node
* A node object.
* @param $message
* A flag which sets a page title relevant to the revision being viewed.
+ *
* @return
* A $page element suitable for use by drupal_render().
*/
@@ -1428,6 +1489,9 @@ function node_show($node, $message = FALSE) {
*
* @param $node
* A node object.
+ *
+ * @return
+ * The ID of the node if this is a full page view, otherwise FALSE.
*/
function node_is_page($node) {
$page_node = menu_get_object();
@@ -1435,7 +1499,7 @@ function node_is_page($node) {
}
/**
- * Process variables for node.tpl.php
+ * Processes variables for node.tpl.php
*
* Most themes utilize their own copy of node.tpl.php. The default is located
* inside "modules/node/node.tpl.php". Look in there for the full list of
@@ -1557,7 +1621,7 @@ function node_permission() {
}
/**
- * Gather the rankings from the the hook_ranking implementations.
+ * Gathers the rankings from the the hook_ranking() implementations.
*
* @param $query
* A query object that has been extended with the Search DB Extender.
@@ -1804,6 +1868,7 @@ function node_user_delete($account) {
* An associative array containing:
* - form: A render element representing the form.
*
+ * @see node_search_admin()
* @ingroup themeable
*/
function theme_node_search_admin($variables) {
@@ -1872,11 +1937,11 @@ function _node_revision_access($node, $op = 'view', $account = NULL) {
$node_current_revision = node_load($node->nid);
$is_current_revision = $node_current_revision->vid == $node->vid;
- // There should be at least two revisions. If the vid of the given node
- // and the vid of the current revision differ, then we already have two
+ // There should be at least two revisions. If the vid of the given node and
+ // the vid of the current revision differ, then we already have two
// different revisions so there is no need for a separate database check.
- // Also, if you try to revert to or delete the current revision, that's
- // not good.
+ // Also, if you try to revert to or delete the current revision, that's not
+ // good.
if ($is_current_revision && (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
$access[$cid] = FALSE;
}
@@ -1884,8 +1949,8 @@ function _node_revision_access($node, $op = 'view', $account = NULL) {
$access[$cid] = TRUE;
}
else {
- // First check the access to the current revision and finally, if the
- // node passed in is not the current revision then access to that, too.
+ // First check the access to the current revision and finally, if the node
+ // passed in is not the current revision then access to that, too.
$access[$cid] = node_access($op, $node_current_revision, $account) && ($is_current_revision || node_access($op, $node, $account));
}
}
@@ -1893,6 +1958,14 @@ function _node_revision_access($node, $op = 'view', $account = NULL) {
return $access[$cid];
}
+/**
+ * Access callback: Checks whether the user has permission to add a node.
+ *
+ * @return
+ * TRUE if the user has add permission, otherwise FALSE.
+ *
+ * @see node_menu()
+ */
function _node_add_access() {
$types = node_type_get_types();
foreach ($types as $type) {
@@ -2110,14 +2183,30 @@ function node_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}
/**
- * Title callback for a node type.
+ * Title callback: Returns the unsanitized title of the node type edit form.
+ *
+ * @param $type
+ * The node type object.
+ *
+ * @return string
+ * An unsanitized string that is the title of the node type edit form.
+ *
+ * @see node_menu()
*/
function node_type_page_title($type) {
return $type->name;
}
/**
- * Title callback.
+ * Title callback: Returns the title of the node.
+ *
+ * @param $node
+ * The node object.
+ *
+ * @return
+ * An unsanitized string that is the title of the node.
+ *
+ * @see node_menu()
*/
function node_page_title($node) {
return $node->title;
@@ -2137,7 +2226,13 @@ function node_last_changed($nid) {
}
/**
- * Return a list of all the existing revision numbers.
+ * Returns a list of all the existing revision numbers.
+ *
+ * @param Drupal\node\Node $node
+ * The node entity.
+ *
+ * @return
+ * An associative array keyed by node revision number.
*/
function node_revision_list($node) {
$revisions = array();
@@ -2223,16 +2318,16 @@ function node_block_save($delta = '', $edit = array()) {
* (optional) The maximum number of nodes to find. Defaults to 10.
*
* @return
- * An array of partial node objects or an empty array if there are no recent
- * nodes visible to the current user.
+ * An array of node entities or an empty array if there are no recent nodes
+ * visible to the current user.
*/
function node_get_recent($number = 10) {
$query = db_select('node', 'n');
if (!user_access('bypass node access')) {
- // If the user is able to view their own unpublished nodes, allow them
- // to see these in addition to published nodes. Check that they actually
- // have some unpublished nodes to view before adding the condition.
+ // If the user is able to view their own unpublished nodes, allow them to
+ // see these in addition to published nodes. Check that they actually have
+ // some unpublished nodes to view before adding the condition.
if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
$query->condition(db_or()
->condition('n.status', NODE_PUBLISHED)
@@ -2362,7 +2457,7 @@ function node_form_block_admin_configure_alter(&$form, &$form_state) {
}
/**
- * Form submit handler for block configuration form.
+ * Form submission handler for node_form_block_admin_configure_alter().
*
* @see node_form_block_admin_configure_alter()
*/
@@ -2394,7 +2489,7 @@ function node_form_block_custom_block_delete_alter(&$form, &$form_state) {
}
/**
- * Form submit handler for custom block delete form.
+ * Form submission handler for node_form_block_custom_block_delete_alter().
*
* @see node_form_block_custom_block_delete_alter()
*/
@@ -2419,8 +2514,8 @@ function node_modules_uninstalled($modules) {
/**
* Implements hook_block_list_alter().
*
- * Check the content type specific visibilty settings.
- * Remove the block if the visibility conditions are not met.
+ * Check the content type specific visibilty settings. Remove the block if the
+ * visibility conditions are not met.
*/
function node_block_list_alter(&$blocks) {
global $theme_key;
@@ -2485,7 +2580,8 @@ function node_block_list_alter(&$blocks) {
* @param $channel
* An associative array containing title, link, description and other keys,
* to be parsed by format_rss_channel() and format_xml_elements().
- * A list of channel elements can be found at the @link http://cyber.law.harvard.edu/rss/rss.html RSS 2.0 Specification. @endlink
+ * A list of channel elements can be found at the
+ * @link http://cyber.law.harvard.edu/rss/rss.html RSS 2.0 Specification. @endlink
* The link should be an absolute URL.
*/
function node_feed($nids = FALSE, $channel = array()) {
@@ -2559,7 +2655,7 @@ function node_feed($nids = FALSE, $channel = array()) {
}
/**
- * Construct a drupal_render() style array from an array of loaded nodes.
+ * Constructs a drupal_render() style array from an array of loaded nodes.
*
* @param $nodes
* An array of nodes as returned by node_load_multiple().
@@ -2568,8 +2664,8 @@ function node_feed($nids = FALSE, $channel = array()) {
* @param $weight
* An integer representing the weight of the first node in the list.
* @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
+ * (optional) A language code to use for rendering. Defaults to NULL which is
+ * the global content language of the current request.
*
* @return
* An array in the format expected by drupal_render().
@@ -2588,7 +2684,12 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $weight = 0, $langcod
}
/**
- * Menu callback; Generate a listing of promoted nodes.
+ * Menu callback: Generates a listing of promoted nodes.
+ *
+ * @return array
+ * An array in the format expected by drupal_render().
+ *
+ * @see node_menu()
*/
function node_page_default() {
$select = db_select('node', 'n')
@@ -2638,7 +2739,15 @@ function node_page_default() {
}
/**
- * Menu callback; view a single node.
+ * Menu callback: Displays a single node.
+ *
+ * @param $node
+ * The node object.
+ *
+ * @return
+ * A page array suitable for use by drupal_render().
+ *
+ * @see node_menu()
*/
function node_page_view($node) {
// If there is a menu link to this node, the link becomes the last part
@@ -2667,7 +2776,7 @@ function node_update_index() {
}
/**
- * Index a single node.
+ * Indexes a single node.
*
* @param $node
* The node to index.
@@ -2771,7 +2880,7 @@ function node_form_search_form_alter(&$form, $form_state) {
}
/**
- * Form API callback for the search form. Registered in node_form_alter().
+ * Form validation handler for node_form_alter().
*/
function node_search_validate($form, &$form_state) {
// Initialize using any existing basic search keywords.
@@ -2819,8 +2928,8 @@ function node_search_validate($form, &$form_state) {
* @{
* The node access system determines who can do what to which nodes.
*
- * In determining access rights for a node, node_access() first checks
- * whether the user has the "bypass node access" permission. Such users have
+ * In determining access rights for a node, node_access() first checks whether
+ * the user has the "bypass node access" permission. Such users have
* unrestricted access to all nodes. user 1 will always pass this check.
*
* Next, all implementations of hook_node_access() will be called. Each
@@ -2858,8 +2967,7 @@ function node_search_validate($form, &$form_state) {
*/
/**
- * Determine whether the current user may perform the given operation on the
- * specified node.
+ * Determines whether the current user may perform the operation on the node.
*
* @param $op
* The operation to be performed on the node. Possible values are:
@@ -2873,6 +2981,7 @@ function node_search_validate($form, &$form_state) {
* @param $account
* Optional, a user object representing the user for whom the operation is to
* be performed. Determines access for a user other than the current user.
+ *
* @return
* TRUE if the operation may be performed, FALSE otherwise.
*/
@@ -3005,6 +3114,7 @@ function node_node_access($node, $op, $account) {
*
* @param $type
* The machine-readable name of the node type.
+ *
* @return array
* An array of permission names and descriptions.
*/
@@ -3038,11 +3148,11 @@ function node_list_permissions($type) {
*
* By default, this will include all node types in the system. To exclude a
* specific node from getting permissions defined for it, set the
- * node_permissions_$type variable to 0. Core does not provide an interface
- * for doing so, however, contrib modules may exclude their own nodes in
+ * node_permissions_$type variable to 0. Core does not provide an interface for
+ * doing so. However, contrib modules may exclude their own nodes in
* hook_install(). Alternatively, contrib modules may configure all node types
- * at once, or decide to apply some other hook_node_access() implementation
- * to some or all node types.
+ * at once, or decide to apply some other hook_node_access() implementation to
+ * some or all node types.
*
* @return
* An array of node types managed by this module.
@@ -3061,21 +3171,22 @@ function node_permissions_get_configured_types() {
}
/**
- * Fetch an array of permission IDs granted to the given user ID.
+ * Fetches an array of permission IDs granted to the given user ID.
*
* The implementation here provides only the universal "all" grant. A node
- * access module should implement hook_node_grants() to provide a grant
- * list for the user.
+ * access module should implement hook_node_grants() to provide a grant list for
+ * the user.
*
- * After the default grants have been loaded, we allow modules to alter
- * the grants array by reference. This hook allows for complex business
- * logic to be applied when integrating multiple node access modules.
+ * After the default grants have been loaded, we allow modules to alter the
+ * grants array by reference. This hook allows for complex business logic to be
+ * applied when integrating multiple node access modules.
*
* @param $op
* The operation that the user is trying to perform.
* @param $account
* The user object for the user performing the operation. If omitted, the
* current user is used.
+ *
* @return
* An associative array in which the keys are realms, and the values are
* arrays of grants for those realms.
@@ -3163,11 +3274,10 @@ function node_access_view_all_nodes($account = NULL) {
/**
* Implements hook_query_TAG_alter().
*
- * This is the hook_query_alter() for queries tagged with 'node_access'.
- * It adds node access checks for the user account given by the 'account'
- * meta-data (or global $user if not provided), for an operation given by
- * the 'op' meta-data (or 'view' if not provided; other possible values are
- * 'update' and 'delete').
+ * This is the hook_query_alter() for queries tagged with 'node_access'. It adds
+ * node access checks for the user account given by the 'account' meta-data (or
+ * global $user if not provided), for an operation given by the 'op' meta-data
+ * (or 'view' if not provided; other possible values are 'update' and 'delete').
*/
function node_query_node_access_alter(QueryAlterableInterface $query) {
_node_query_node_access_alter($query, 'node');
@@ -3206,8 +3316,8 @@ function _node_query_node_access_alter($query, $type) {
}
// If $account can bypass node access, or there are no node access modules,
- // or the operation is 'view' and the $acount has a global view grant (i.e.,
- // a view grant for node ID 0), we don't need to alter the query.
+ // or the operation is 'view' and the $account has a global view grant
+ // (such as a view grant for node ID 0), we don't need to alter the query.
if (user_access('bypass node access', $account)) {
return;
}
@@ -3394,15 +3504,14 @@ function node_access_acquire_grants($node, $delete = TRUE) {
*
* If a realm is provided, it will only delete grants from that realm, but it
* will always delete a grant from the 'all' realm. Modules that utilize
- * node_access can use this function when doing mass updates due to widespread
+ * node_access() can use this function when doing mass updates due to widespread
* permission changes.
*
* Note: Don't call this function directly from a contributed module. Call
* node_access_acquire_grants() instead.
*
* @param $node
- * The $node being written to. All that is necessary is that it contains a
- * nid.
+ * The node whose grants are being written.
* @param $grants
* A list of grants to write. Each grant is an array that must contain the
* following keys: realm, gid, grant_view, grant_update, grant_delete.
@@ -3410,10 +3519,14 @@ function node_access_acquire_grants($node, $delete = TRUE) {
* is a module-defined id to define grant privileges. each grant_* field
* is a boolean value.
* @param $realm
- * If provided, only read/write grants for that realm.
+ * (optional) If provided, read/write grants for that realm only. Defaults to
+ * NULL.
* @param $delete
- * If false, do not delete records. This is only for optimization purposes,
- * and assumes the caller has already performed a mass delete of some form.
+ * (optional) If false, does not delete records. This is only for optimization
+ * purposes, and assumes the caller has already performed a mass delete of
+ * some form. Defaults to TRUE.
+ *
+ * @see node_access_acquire_grants()
*/
function node_access_write_grants($node, $grants, $realm = NULL, $delete = TRUE) {
if ($delete) {
@@ -3442,21 +3555,23 @@ function node_access_write_grants($node, $grants, $realm = NULL, $delete = TRUE)
}
/**
- * Flag / unflag the node access grants for rebuilding, or read the current
- * value of the flag.
+ * Flags or unflags the node access grants for rebuilding.
*
+ * If the argument isn't specified, the current value of the flag is returned.
* When the flag is set, a message is displayed to users with 'access
* administration pages' permission, pointing to the 'rebuild' confirm form.
* This can be used as an alternative to direct node_access_rebuild calls,
* allowing administrators to decide when they want to perform the actual
- * (possibly time consuming) rebuild.
- * When unsure the current user is an administrator, node_access_rebuild
- * should be used instead.
+ * (possibly time consuming) rebuild. When unsure if the current user is an
+ * administrator, node_access_rebuild() should be used instead.
*
* @param $rebuild
* (Optional) The boolean value to be written.
- * @return
- * (If no value was provided for $rebuild) The current value of the flag.
+ *
+ * @return
+ * The current value of the flag if no value was provided for $rebuild.
+ *
+ * @see node_access_rebuild()
*/
function node_access_needs_rebuild($rebuild = NULL) {
if (!isset($rebuild)) {
@@ -3471,15 +3586,15 @@ function node_access_needs_rebuild($rebuild = NULL) {
}
/**
- * Rebuild the node access database. This is occasionally needed by modules
- * that make system-wide changes to access levels.
+ * Rebuilds the node access database.
*
- * When the rebuild is required by an admin-triggered action (e.g module
- * settings form), calling node_access_needs_rebuild(TRUE) instead of
+ * This is occasionally needed by modules that make system-wide changes to
+ * access levels. When the rebuild is required by an admin-triggered action (e.g
+ * module settings form), calling node_access_needs_rebuild(TRUE) instead of
* node_access_rebuild() lets the user perform his changes and actually
* rebuild only once he is done.
*
- * Note : As of Drupal 6, node access modules are not required to (and actually
+ * Note: As of Drupal 6, node access modules are not required to (and actually
* should not) call node_access_rebuild() in hook_enable/disable anymore.
*
* @see node_access_needs_rebuild()
@@ -3543,11 +3658,14 @@ function node_access_rebuild($batch_mode = FALSE) {
}
/**
- * Batch operation for node_access_rebuild_batch.
+ * Performs batch operation for node_access_rebuild().
+ *
+ * This is a multistep operation: we go through all nodes by packs of 20. The
+ * batch processing engine interrupts processing and sends progress feedback
+ * after 1 second execution time.
*
- * This is a multistep operation : we go through all nodes by packs of 20.
- * The batch processing engine interrupts processing and sends progress
- * feedback after 1 second execution time.
+ * @param array $context
+ * An array of contextual key/value information for rebuild batch process.
*/
function _node_access_rebuild_batch_operation(&$context) {
if (empty($context['sandbox'])) {
@@ -3578,7 +3696,14 @@ function _node_access_rebuild_batch_operation(&$context) {
}
/**
- * Post-processing for node_access_rebuild_batch.
+ * Performs post-processing for node_access_rebuild().
+ *
+ * @param bool $success
+ * A boolean indicating whether the re-build process has completed.
+ * @param array $results
+ * An array of results information.
+ * @param array $operations
+ * An array of function calls (not used in this function).
*/
function _node_access_rebuild_batch_finished($success, $results, $operations) {
if ($success) {
@@ -3595,7 +3720,6 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
* @} End of "defgroup node_access".
*/
-
/**
* @defgroup node_content Hook implementations for user-created content types
* @{
@@ -3631,6 +3755,7 @@ function node_content_form($node, $form_state) {
/**
* Implements hook_forms().
+ *
* All node forms share the same form handler.
*/
function node_forms() {
@@ -3715,6 +3840,12 @@ function node_action_info() {
/**
* Sets the status of a node to 1 (published).
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_publish_action($node, $context = array()) {
@@ -3725,6 +3856,12 @@ function node_publish_action($node, $context = array()) {
/**
* Sets the status of a node to 0 (unpublished).
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_unpublish_action($node, $context = array()) {
@@ -3735,6 +3872,12 @@ function node_unpublish_action($node, $context = array()) {
/**
* Sets the sticky-at-top-of-list property of a node to 1.
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_make_sticky_action($node, $context = array()) {
@@ -3745,6 +3888,12 @@ function node_make_sticky_action($node, $context = array()) {
/**
* Sets the sticky-at-top-of-list property of a node to 0.
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_make_unsticky_action($node, $context = array()) {
@@ -3755,6 +3904,12 @@ function node_make_unsticky_action($node, $context = array()) {
/**
* Sets the promote property of a node to 1.
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_promote_action($node, $context = array()) {
@@ -3765,6 +3920,12 @@ function node_promote_action($node, $context = array()) {
/**
* Sets the promote property of a node to 0.
*
+ * @param $node
+ * A node object.
+ * @param $context
+ * (optional) Array of additional information about what triggered the action.
+ * Not used for this action.
+ *
* @ingroup actions
*/
function node_unpromote_action($node, $context = array()) {
@@ -3775,6 +3936,9 @@ function node_unpromote_action($node, $context = array()) {
/**
* Saves a node.
*
+ * @param $node
+ * The node to be saved.
+ *
* @ingroup actions
*/
function node_save_action($node) {
@@ -3791,6 +3955,9 @@ function node_save_action($node) {
* Array with the following elements:
* - 'owner_uid': User ID to assign to the node.
*
+ * @see node_assign_owner_action_form()
+ * @see node_assign_owner_action_validate()
+ * @see node_assign_owner_action_submit()
* @ingroup actions
*/
function node_assign_owner_action($node, $context) {
@@ -3801,6 +3968,16 @@ function node_assign_owner_action($node, $context) {
/**
* Generates the settings form for node_assign_owner_action().
+ *
+ * @param $context
+ * Array of additional information about what triggered the action. Includes
+ * the following elements:
+ * - 'owner_uid': User ID to assign to the node.
+ *
+ * @see node_assign_owner_action_submit()
+ * @see node_assign_owner_action_validate()
+ *
+ * @ingroup forms
*/
function node_assign_owner_action_form($context) {
$description = t('The username of the user to which you would like to assign ownership.');
@@ -3841,6 +4018,8 @@ function node_assign_owner_action_form($context) {
/**
* Validates settings form for node_assign_owner_action().
+ *
+ * @see node_assign_owner_action_submit()
*/
function node_assign_owner_action_validate($form, $form_state) {
$exists = (bool) db_query_range('SELECT 1 FROM {users} WHERE name = :name', 0, 1, array(':name' => $form_state['values']['owner_name']))->fetchField();
@@ -3851,6 +4030,8 @@ function node_assign_owner_action_validate($form, $form_state) {
/**
* Saves settings form for node_assign_owner_action().
+ *
+ * @see node_assign_owner_action_validate()
*/
function node_assign_owner_action_submit($form, $form_state) {
// Username can change, so we need to store the ID, not the username.
@@ -3860,6 +4041,14 @@ function node_assign_owner_action_submit($form, $form_state) {
/**
* Generates settings form for node_unpublish_by_keyword_action().
+ *
+ * @param array $context
+ * Array of additional information about what triggered this action.
+ *
+ * @return array
+ * A form array.
+ *
+ * @see node_unpublish_by_keyword_action_submit()
*/
function node_unpublish_by_keyword_action_form($context) {
$form['keywords'] = array(
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index c6cb1bcc2..dee92e16c 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -5,7 +5,6 @@
* Page callbacks for adding, editing, deleting, and revisions management for content.
*/
-
/**
* Menu callback; presents the node editing form.
*/
@@ -63,6 +62,12 @@ function theme_node_add_list($variables) {
/**
* Returns a node submission form.
+ *
+ * @param $type
+ * The node type for the submitted node.
+ *
+ * @return
+ * The themed form.
*/
function node_add($type) {
global $user;
@@ -75,6 +80,12 @@ function node_add($type) {
return $output;
}
+/**
+ * Form validation handler for node_form().
+ *
+ * @see node_form()
+ * @see node_form_submit()
+ */
function node_form_validate($form, &$form_state) {
// $form_state['node'] contains the actual entity being edited, but we must
// not update it with form values that have not yet been validated, so we
@@ -85,7 +96,13 @@ function node_form_validate($form, &$form_state) {
}
/**
- * Generate the node add/edit form array.
+ * Form constructor for the node add/edit form.
+ *
+ * @see node_form_validate()
+ * @see node_form_submit()
+ * @see node_form_build_preview()
+ * @see node_form_delete_submit()
+ * @ingroup forms
*/
function node_form($form, &$form_state, $node) {
global $user;
@@ -311,7 +328,12 @@ function node_form($form, &$form_state, $node) {
}
/**
- * Button submit function: handle the 'Delete' button on the node form.
+ * Form submission handler for node_form().
+ *
+ * Handles the 'Delete' button on the node form.
+ *
+ * @see node_form()
+ * @see node_form_validate()
*/
function node_form_delete_submit($form, &$form_state) {
$destination = array();
@@ -323,7 +345,14 @@ function node_form_delete_submit($form, &$form_state) {
$form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
}
-
+/**
+ * Form submission handler for node_form().
+ *
+ * Handles the 'Preview' button on the node form.
+ *
+ * @see node_form()
+ * @see node_form_validate()
+ */
function node_form_build_preview($form, &$form_state) {
$node = node_form_submit_build_node($form, $form_state);
$form_state['node_preview'] = node_preview($node);
@@ -331,7 +360,15 @@ function node_form_build_preview($form, &$form_state) {
}
/**
- * Generate a node preview.
+ * Generates a node preview.
+ *
+ * @param $node
+ * The node to preview.
+ *
+ * @return
+ * An HTML-formatted string of a node preview.
+ *
+ * @see node_form_build_preview()
*/
function node_preview($node) {
if (node_access('create', $node) || node_access('update', $node)) {
@@ -377,6 +414,7 @@ function node_preview($node) {
* An associative array containing:
* - node: The node object which is being previewed.
*
+ * @see node_preview()
* @ingroup themeable
*/
function theme_node_preview($variables) {
@@ -407,6 +445,12 @@ function theme_node_preview($variables) {
return $output;
}
+/**
+ * Form submission handler for node_form().
+ *
+ * @see node_form()
+ * @see node_form_validate()
+ */
function node_form_submit($form, &$form_state) {
$node = node_form_submit_build_node($form, $form_state);
$insert = empty($node->nid);
@@ -472,7 +516,9 @@ function node_form_submit_build_node($form, &$form_state) {
}
/**
- * Menu callback -- ask for confirmation of node deletion
+ * Form constructor for the node deletion confirmation form.
+ *
+ * @see node_delete_confirm_submit()
*/
function node_delete_confirm($form, &$form_state, $node) {
$form['#node'] = $node;
@@ -488,7 +534,9 @@ function node_delete_confirm($form, &$form_state, $node) {
}
/**
- * Execute node deletion
+ * Executes node deletion.
+ *
+ * @see node_delete_confirm()
*/
function node_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
@@ -502,7 +550,15 @@ function node_delete_confirm_submit($form, &$form_state) {
}
/**
- * Generate an overview table of older revisions of a node.
+ * Generates an overview table of older revisions of a node.
+ *
+ * @param $node
+ * A node object.
+ *
+ * @return array
+ * An array as expected by drupal_render().
+ *
+ * @see node_menu()
*/
function node_revision_overview($node) {
drupal_set_title(t('Revisions for %title', array('%title' => $node->title)), PASS_THROUGH);
@@ -553,13 +609,26 @@ function node_revision_overview($node) {
}
/**
- * Ask for confirmation of the reversion to prevent against CSRF attacks.
+ * Asks for confirmation of the reversion to prevent against CSRF attacks.
+ *
+ * @param int $node_revision
+ * The node revision ID.
+ *
+ * @return array
+ * An array as expected by drupal_render().
+ *
+ * @see node_menu()
+ * @see node_revision_revert_confirm_submit()
+ * @ingroup forms
*/
function node_revision_revert_confirm($form, $form_state, $node_revision) {
$form['#node_revision'] = $node_revision;
return confirm_form($form, t('Are you sure you want to revert to the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/' . $node_revision->nid . '/revisions', '', t('Revert'), t('Cancel'));
}
+/**
+ * Form submission handler for node_revision_revert_confirm().
+ */
function node_revision_revert_confirm_submit($form, &$form_state) {
$node_revision = $form['#node_revision'];
$node_revision->revision = 1;
@@ -572,11 +641,29 @@ function node_revision_revert_confirm_submit($form, &$form_state) {
$form_state['redirect'] = 'node/' . $node_revision->nid . '/revisions';
}
+/**
+ * Form constructor for the revision deletion confirmation form.
+ *
+ * This form prevents against CSRF attacks.
+ *
+ * @param $node_revision
+ * The node revision ID.
+ *
+ * @return
+ * An array as expected by drupal_render().
+ *
+ * @see node_menu()
+ * @see node_revision_delete_confirm_submit()
+ * @ingroup forms
+ */
function node_revision_delete_confirm($form, $form_state, $node_revision) {
$form['#node_revision'] = $node_revision;
return confirm_form($form, t('Are you sure you want to delete the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/' . $node_revision->nid . '/revisions', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}
+/**
+ * Form submission handler for node_revision_delete_confirm().
+ */
function node_revision_delete_confirm_submit($form, &$form_state) {
$node_revision = $form['#node_revision'];
node_revision_delete($node_revision->vid);
diff --git a/modules/node/node.test b/modules/node/node.test
index d789d3c0e..2180f5838 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -149,6 +149,9 @@ class NodeLoadHooksTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the node revision functionality.
+ */
class NodeRevisionsTestCase extends DrupalWebTestCase {
protected $nodes;
protected $logs;
@@ -198,7 +201,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
}
/**
- * Check node revision related operations.
+ * Checks node revision related operations.
*/
function testRevisions() {
$nodes = $this->nodes;
@@ -282,6 +285,9 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the node edit functionality.
+ */
class PageEditTestCase extends DrupalWebTestCase {
protected $web_user;
protected $admin_user;
@@ -302,7 +308,7 @@ class PageEditTestCase extends DrupalWebTestCase {
}
/**
- * Check node edit functionality.
+ * Checks node edit functionality.
*/
function testPageEdit() {
$this->drupalLogin($this->web_user);
@@ -369,7 +375,7 @@ class PageEditTestCase extends DrupalWebTestCase {
}
/**
- * Check changing node authored by fields.
+ * Tests changing a node's "authored by" field.
*/
function testPageAuthoredBy() {
$this->drupalLogin($this->admin_user);
@@ -414,6 +420,9 @@ class PageEditTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the node entity preview functionality.
+ */
class PagePreviewTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -431,7 +440,7 @@ class PagePreviewTestCase extends DrupalWebTestCase {
}
/**
- * Check the node preview functionality.
+ * Checks the node preview functionality.
*/
function testPagePreview() {
$langcode = LANGUAGE_NONE;
@@ -455,7 +464,7 @@ class PagePreviewTestCase extends DrupalWebTestCase {
}
/**
- * Check the node preview functionality, when using revisions.
+ * Checks the node preview functionality, when using revisions.
*/
function testPagePreviewWithRevisions() {
$langcode = LANGUAGE_NONE;
@@ -485,6 +494,9 @@ class PagePreviewTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests creating and saving a node.
+ */
class NodeCreationTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -503,7 +515,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
}
/**
- * Create a "Basic page" node and verify its consistency in the database.
+ * Creates a "Basic page" node and verifies its consistency in the database.
*/
function testNodeCreation() {
// Create a node.
@@ -522,7 +534,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
}
/**
- * Create a page node and verify that a transaction rolls back the failed creation
+ * Verifies that a transaction rolls back the failed creation.
*/
function testFailedPageCreation() {
// Create a node.
@@ -563,6 +575,9 @@ class NodeCreationTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the functionality of node entity edit permissions.
+ */
class PageViewTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -573,7 +588,7 @@ class PageViewTestCase extends DrupalWebTestCase {
}
/**
- * Creates a node and then an anonymous and unpermissioned user attempt to edit the node.
+ * Tests an anonymous and unpermissioned user attempting to edit the node.
*/
function testPageView() {
// Create a node to view.
@@ -602,6 +617,9 @@ class PageViewTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the summary length functionality.
+ */
class SummaryLengthTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -612,7 +630,7 @@ class SummaryLengthTestCase extends DrupalWebTestCase {
}
/**
- * Creates a node and then an anonymous and unpermissioned user attempt to edit the node.
+ * Tests the node summary length functionality.
*/
function testSummaryLength() {
// Create a node to view.
@@ -644,6 +662,9 @@ class SummaryLengthTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests XSS functionality with a node entity.
+ */
class NodeTitleXSSTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -653,6 +674,9 @@ class NodeTitleXSSTestCase extends DrupalWebTestCase {
);
}
+ /**
+ * Tests XSS functionality with a node entity.
+ */
function testNodeTitleXSS() {
// Prepare a user to do the stuff.
$web_user = $this->drupalCreateUser(array('create page content', 'edit any page content'));
@@ -678,6 +702,9 @@ class NodeTitleXSSTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests the availability of the syndicate block.
+ */
class NodeBlockTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
@@ -709,7 +736,7 @@ class NodeBlockTestCase extends DrupalWebTestCase {
}
/**
- * Check that the post information displays when enabled for a content type.
+ * Checks that the post information displays when enabled for a content type.
*/
class NodePostSettingsTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -728,7 +755,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
}
/**
- * Set "Basic page" content type to display post information and confirm its presence on a new node.
+ * Confirms "Basic page" content type and post information is on a new node.
*/
function testPagePostInfo() {
@@ -751,7 +778,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
}
/**
- * Set "Basic page" content type to not display post information and confirm its absence on a new node.
+ * Confirms absence of post information on a new node.
*/
function testPageNotPostInfo() {
@@ -774,7 +801,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
}
/**
- * Ensure that data added to nodes by other modules appears in RSS feeds.
+ * Ensures that data added to nodes by other modules appears in RSS feeds.
*
* Create a node, enable the node_test module to ensure that extra data is
* added to the node->content array, then verify that the data appears on the
@@ -801,8 +828,7 @@ class NodeRSSContentTestCase extends DrupalWebTestCase {
}
/**
- * Create a new node and ensure that it includes the custom data when added
- * to an RSS feed.
+ * Ensures that a new node includes the custom data when added to an RSS feed.
*/
function testNodeRSSContent() {
// Create a node.
@@ -841,9 +867,11 @@ class NodeRSSContentTestCase extends DrupalWebTestCase {
}
/**
- * Test case to verify basic node_access functionality.
+ * Tests basic node_access functionality.
+ *
+ * Note that hook_node_access_records() is covered in another test class.
+ *
* @todo Cover hook_node_access in a separate test class.
- * hook_node_access_records is covered in another test class.
*/
class NodeAccessTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -855,7 +883,7 @@ class NodeAccessTestCase extends DrupalWebTestCase {
}
/**
- * Asserts node_access correctly grants or denies access.
+ * Asserts node_access() correctly grants or denies access.
*/
function assertNodeAccess($ops, $node, $account) {
foreach ($ops as $op => $result) {
@@ -910,7 +938,7 @@ class NodeAccessTestCase extends DrupalWebTestCase {
}
/**
- * Test case to verify hook_node_access_records functionality.
+ * Tests hook_node_access_records() functionality.
*/
class NodeAccessRecordsTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -929,7 +957,7 @@ class NodeAccessRecordsTestCase extends DrupalWebTestCase {
}
/**
- * Create a node and test the creation of node access rules.
+ * Creates a node and tests the creation of node access rules.
*/
function testNodeAccessRecords() {
// Create an article node.
@@ -1005,9 +1033,6 @@ class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
);
}
- /**
- * Enable modules and create user with specific permissions.
- */
public function setUp() {
parent::setUp('node_access_test');
node_access_rebuild();
@@ -1015,7 +1040,7 @@ class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
}
/**
- * Test the "private" node access.
+ * Tests the "private" node access functionality.
*
* - Create 2 users with "access content" and "create article" permissions.
* - Each user creates one private and one not private article.
@@ -1152,7 +1177,7 @@ class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
}
/**
- * Test case to check node save related functionality, including import-save
+ * Tests node save related functionality, including import-save.
*/
class NodeSaveTestCase extends DrupalWebTestCase {
@@ -1173,7 +1198,8 @@ class NodeSaveTestCase extends DrupalWebTestCase {
}
/**
- * Import test, to check if custom node ids are saved properly.
+ * Checks whether custom node IDs are saved properly during an import operation.
+ *
* Workflow:
* - first create a piece of content
* - save the content
@@ -1207,8 +1233,7 @@ class NodeSaveTestCase extends DrupalWebTestCase {
}
/**
- * Check that the "created" and "changed" timestamps are set correctly when
- * saving a new node or updating an existing node.
+ * Verifies accuracy of the "created" and "changed" timestamp functionality.
*/
function testTimestamps() {
// Use the default timestamps.
@@ -1307,7 +1332,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
}
/**
- * Ensure that node type functions (node_type_get_*) work correctly.
+ * Ensures that node type functions (node_type_get_*) work correctly.
*
* Load available node types and validate the returned data.
*/
@@ -1326,7 +1351,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
}
/**
- * Test creating a content type programmatically and via a form.
+ * Tests creating a content type programmatically and via a form.
*/
function testNodeTypeCreation() {
// Create a content type programmaticaly.
@@ -1356,7 +1381,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
}
/**
- * Test editing a node type using the UI.
+ * Tests editing a node type using the UI.
*/
function testNodeTypeEditing() {
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types'));
@@ -1409,7 +1434,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
}
/**
- * Test that node_types_rebuild() correctly handles the 'disabled' flag.
+ * Tests that node_types_rebuild() correctly handles the 'disabled' flag.
*/
function testNodeTypeStatus() {
// Enable all core node modules, and all types should be active.
@@ -1470,7 +1495,7 @@ class NodeTypePersistenceTestCase extends DrupalWebTestCase {
}
/**
- * Test node type customizations persist through disable and uninstall.
+ * Tests that node type customizations persist through disable and uninstall.
*/
function testNodeTypeCustomizationPersistence() {
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types', 'administer modules'));
@@ -1534,7 +1559,7 @@ class NodeTypePersistenceTestCase extends DrupalWebTestCase {
}
/**
- * Rebuild the node_access table.
+ * Verifies the rebuild functionality for the node_access table.
*/
class NodeAccessRebuildTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -1553,6 +1578,9 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase {
$this->web_user = $web_user;
}
+ /**
+ * Tests rebuilding the node access permissions table.
+ */
function testNodeAccessRebuild() {
$this->drupalGet('admin/reports/status');
$this->clickLink(t('Rebuild permissions'));
@@ -1562,7 +1590,7 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase {
}
/**
- * Test node administration page functionality.
+ * Tests node administration page functionality.
*/
class NodeAdminTestCase extends DrupalWebTestCase {
public static function getInfo() {
@@ -1630,6 +1658,7 @@ class NodeAdminTestCase extends DrupalWebTestCase {
* Tests content overview with different user permissions.
*
* Taxonomy filters are tested separately.
+ *
* @see TaxonomyNodeFilterTestCase
*/
function testContentAdminPages() {
@@ -1727,7 +1756,7 @@ class NodeAdminTestCase extends DrupalWebTestCase {
}
/**
- * Test node title.
+ * Tests node title functionality.
*/
class NodeTitleTestCase extends DrupalWebTestCase {
protected $admin_user;
@@ -1747,7 +1776,7 @@ class NodeTitleTestCase extends DrupalWebTestCase {
}
/**
- * Create one node and test if the node title has the correct value.
+ * Creates one node and tests if the node title has the correct value.
*/
function testNodeTitle() {
// Create "Basic page" content with title.
@@ -1790,7 +1819,7 @@ class NodeFeedTestCase extends DrupalWebTestCase {
}
/**
- * Ensure that node_feed accepts and prints extra channel elements.
+ * Ensures that node_feed() accepts and prints extra channel elements.
*/
function testNodeFeedExtraChannelElements() {
ob_start();
@@ -1822,7 +1851,7 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase {
}
/**
- * Test the recent comments block.
+ * Tests the recent comments block.
*/
function testRecentNodeBlock() {
$this->drupalLogin($this->admin_user);
@@ -1935,7 +1964,7 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase {
}
}
/**
- * Test multistep node forms basic options.
+ * Tests basic options of multi-step node forms.
*/
class MultiStepNodeFormBasicOptionsTest extends DrupalWebTestCase {
public static function getInfo() {
@@ -1953,7 +1982,7 @@ class MultiStepNodeFormBasicOptionsTest extends DrupalWebTestCase {
}
/**
- * Change the default values of basic options to ensure they persist.
+ * Tests changing the default values of basic options to ensure they persist.
*/
function testMultiStepNodeFormBasicOptions() {
$edit = array(
@@ -1985,7 +2014,7 @@ class NodeBuildContent extends DrupalWebTestCase {
}
/**
- * Test to ensure that a node's content array is rebuilt on every call to node_build_content().
+ * Ensures that content array is rebuilt on every call to node_build_content().
*/
function testNodeRebuildContent() {
$node = $this->drupalCreateNode();
@@ -2065,10 +2094,10 @@ class NodeQueryAlter extends DrupalWebTestCase {
}
/**
- * Lower-level test of 'node_access' query alter, for user with access.
+ * Tests 'node_access' query alter, for user with access.
*
- * Verifies that a non-standard table alias can be used, and that a
- * user with node access can view the nodes.
+ * Verifies that a non-standard table alias can be used, and that a user with
+ * node access can view the nodes.
*/
function testNodeQueryAlterLowLevelWithAccess() {
// User with access should be able to view 4 nodes.
@@ -2088,10 +2117,10 @@ class NodeQueryAlter extends DrupalWebTestCase {
}
/**
- * Lower-level test of 'node_access' query alter, for user without access.
+ * Tests 'node_access' query alter, for user without access.
*
- * Verifies that a non-standard table alias can be used, and that a
- * user without node access cannot view the nodes.
+ * Verifies that a non-standard table alias can be used, and that a user
+ * without node access cannot view the nodes.
*/
function testNodeQueryAlterLowLevelNoAccess() {
// User without access should be able to view 0 nodes.
@@ -2111,10 +2140,10 @@ class NodeQueryAlter extends DrupalWebTestCase {
}
/**
- * Lower-level test of 'node_access' query alter, for edit access.
+ * Tests 'node_access' query alter, for edit access.
*
- * Verifies that a non-standard table alias can be used, and that a
- * user with view-only node access cannot edit the nodes.
+ * Verifies that a non-standard table alias can be used, and that a user with
+ * view-only node access cannot edit the nodes.
*/
function testNodeQueryAlterLowLevelEditAccess() {
// User with view-only access should not be able to edit nodes.
@@ -2136,13 +2165,13 @@ class NodeQueryAlter extends DrupalWebTestCase {
}
/**
- * Lower-level test of 'node_access' query alter override.
+ * Tests 'node_access' query alter override.
*
* Verifies that node_access_view_all_nodes() is called from
- * node_query_node_access_alter(). We do this by checking that
- * a user which normally would not have view privileges is able
- * to view the nodes when we add a record to {node_access} paired
- * with a corresponding privilege in hook_node_grants().
+ * node_query_node_access_alter(). We do this by checking that a user who
+ * normally would not have view privileges is able to view the nodes when we
+ * add a record to {node_access} paired with a corresponding privilege in
+ * hook_node_grants().
*/
function testNodeQueryAlterOverride() {
$record = array(
diff --git a/modules/node/tests/node_access_test.module b/modules/node/tests/node_access_test.module
index 813bf929b..ec35c41f1 100644
--- a/modules/node/tests/node_access_test.module
+++ b/modules/node/tests/node_access_test.module
@@ -2,7 +2,9 @@
/**
* @file
- * Dummy module implementing node access related hooks to test API interaction
+ * A dummy module implementing node access related hooks for testing purposes.
+ *
+ * A dummy module implementing node access related hooks to test API interaction
* with the Node module. This module restricts view permission to those with
* a special 'node test view' permission.
*/
@@ -140,6 +142,8 @@ function node_access_test_page() {
* database query is shown, and a list of the node IDs, for debugging purposes.
* And if there is a query exception, the page says "Exception" and gives the
* error.
+ *
+ * @see node_access_test_menu()
*/
function node_access_entity_test_page() {
$output = '';
diff --git a/modules/node/tests/node_test.module b/modules/node/tests/node_test.module
index a52c1fad0..fb6678521 100644
--- a/modules/node/tests/node_test.module
+++ b/modules/node/tests/node_test.module
@@ -2,8 +2,10 @@
/**
* @file
- * Dummy module implementing node related hooks to test API interaction with
- * the Node module.
+ * A dummy module for testing node related hooks.
+ *
+ * This is a dummy module that implements node related hooks to test API
+ * interaction with the Node module.
*/
/**
diff --git a/modules/node/tests/node_test_exception.module b/modules/node/tests/node_test_exception.module
index 0fe9f35ea..66bc71747 100644
--- a/modules/node/tests/node_test_exception.module
+++ b/modules/node/tests/node_test_exception.module
@@ -2,8 +2,7 @@
/**
* @file
- * Dummy module implementing node related hooks to test API interaction with
- * the Node module.
+ * A module implementing node related hooks to test API interaction.
*/
/**
diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module
index c07cc6cfa..728198680 100644
--- a/modules/overlay/overlay.module
+++ b/modules/overlay/overlay.module
@@ -704,7 +704,7 @@ function overlay_overlay_child_initialize() {
}
/**
- * Requests that the overlay overlay closes when the page is displayed.
+ * Requests that the overlay closes when the page is displayed.
*
* @param $redirect
* (optional) The path that should open in the parent window after the
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index e3cab62a2..5c65e12f4 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -2646,10 +2646,9 @@ class DrupalWebTestCase extends DrupalTestCase {
/**
* Follows a link by name.
*
- * Will click the first link found with this link text by default, or a
- * later one if an index is given. Match is case insensitive with
- * normalized space. The label is translated label. There is an assert
- * for successful click.
+ * Will click the first link found with this link text by default, or a later
+ * one if an index is given. Match is case sensitive with normalized space.
+ * The label is translated label. There is an assert for successful click.
*
* @param $label
* Text between the anchor tags.
@@ -3149,6 +3148,42 @@ class DrupalWebTestCase extends DrupalTestCase {
}
/**
+ * Asserts themed output.
+ *
+ * @param $callback
+ * The name of the theme function to invoke; e.g. 'links' for theme_links().
+ * @param $variables
+ * An array of variables to pass to the theme function.
+ * @param $expected
+ * The expected themed output string.
+ * @param $message
+ * (optional) A message to display with the assertion. Do not translate
+ * messages: use format_string() to embed variables in the message text, not
+ * t(). If left blank, a default message will be displayed.
+ * @param $group
+ * (optional) The group this message is in, which is displayed in a column
+ * in test output. Use 'Debug' to indicate this is debugging output. Do not
+ * translate this string. Defaults to 'Other'; most tests do not override
+ * this default.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertThemeOutput($callback, array $variables = array(), $expected, $message = '', $group = 'Other') {
+ $output = theme($callback, $variables);
+ $this->verbose('Variables:' . '<pre>' . check_plain(var_export($variables, TRUE)) . '</pre>'
+ . '<hr />' . 'Result:' . '<pre>' . check_plain(var_export($output, TRUE)) . '</pre>'
+ . '<hr />' . 'Expected:' . '<pre>' . check_plain(var_export($expected, TRUE)) . '</pre>'
+ . '<hr />' . $output
+ );
+ if (!$message) {
+ $message = '%callback rendered correctly.';
+ }
+ $message = format_string($message, array('%callback' => 'theme_' . $callback . '()'));
+ return $this->assertIdentical($output, $expected, $message, $group);
+ }
+
+ /**
* Asserts that a field exists in the current page by the given XPath.
*
* @param $xpath
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index e8e403330..cc4606951 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -2298,6 +2298,12 @@ class FormatDateUnitTest extends DrupalWebTestCase {
$edit = array('date_format' => $admin_date_format);
$this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+ // Add a new date format which just differs in the case.
+ $admin_date_format_uppercase = 'j M Y';
+ $edit = array('date_format' => $admin_date_format_uppercase);
+ $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+ $this->assertText(t('Custom date format added.'));
+
// Add new date type.
$edit = array(
'date_type' => 'Example Style',
@@ -2306,8 +2312,18 @@ class FormatDateUnitTest extends DrupalWebTestCase {
);
$this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
+ // Add a second date format with a different case than the first.
+ $edit = array(
+ 'machine_name' => 'example_style_uppercase',
+ 'date_type' => 'Example Style Uppercase',
+ 'date_format' => $admin_date_format_uppercase,
+ );
+ $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
+ $this->assertText(t('New date type added successfully.'));
+
$timestamp = strtotime('2007-03-10T00:00:00+00:00');
$this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', t('Test format_date() using an admin-defined date type.'));
+ $this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007', 'Test format_date() using an admin-defined date type with different case.');
$this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'medium'), t('Test format_date() defaulting to medium when $type not found.'));
}
diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test
index 6e1d15979..b58578e99 100644
--- a/modules/simpletest/tests/database_test.test
+++ b/modules/simpletest/tests/database_test.test
@@ -48,7 +48,7 @@ class DatabaseTestCase extends DrupalWebTestCase {
}
foreach ($schema as $name => $data) {
- $this->assertTrue(db_table_exists($name), t('Table @name created successfully.', array('@name' => $name)));
+ $this->assertTrue(db_table_exists($name), format_string('Table @name created successfully.', array('@name' => $name)));
}
}
@@ -191,25 +191,25 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
$db1 = Database::getConnection('default', 'default');
$db2 = Database::getConnection('slave', 'default');
- $this->assertNotNull($db1, t('default connection is a real connection object.'));
- $this->assertNotNull($db2, t('slave connection is a real connection object.'));
- $this->assertNotIdentical($db1, $db2, t('Each target refers to a different connection.'));
+ $this->assertNotNull($db1, 'default connection is a real connection object.');
+ $this->assertNotNull($db2, 'slave connection is a real connection object.');
+ $this->assertNotIdentical($db1, $db2, 'Each target refers to a different connection.');
// Try to open those targets another time, that should return the same objects.
$db1b = Database::getConnection('default', 'default');
$db2b = Database::getConnection('slave', 'default');
- $this->assertIdentical($db1, $db1b, t('A second call to getConnection() returns the same object.'));
- $this->assertIdentical($db2, $db2b, t('A second call to getConnection() returns the same object.'));
+ $this->assertIdentical($db1, $db1b, 'A second call to getConnection() returns the same object.');
+ $this->assertIdentical($db2, $db2b, 'A second call to getConnection() returns the same object.');
// Try to open an unknown target.
$unknown_target = $this->randomName();
$db3 = Database::getConnection($unknown_target, 'default');
- $this->assertNotNull($db3, t('Opening an unknown target returns a real connection object.'));
- $this->assertIdentical($db1, $db3, t('An unknown target opens the default connection.'));
+ $this->assertNotNull($db3, 'Opening an unknown target returns a real connection object.');
+ $this->assertIdentical($db1, $db3, 'An unknown target opens the default connection.');
// Try to open that unknown target another time, that should return the same object.
$db3b = Database::getConnection($unknown_target, 'default');
- $this->assertIdentical($db3, $db3b, t('A second call to getConnection() returns the same object.'));
+ $this->assertIdentical($db3, $db3b, 'A second call to getConnection() returns the same object.');
}
/**
@@ -227,7 +227,7 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
$db1 = Database::getConnection('default', 'default');
$db2 = Database::getConnection('slave', 'default');
- $this->assertIdentical($db1, $db2, t('Both targets refer to the same connection.'));
+ $this->assertIdentical($db1, $db2, 'Both targets refer to the same connection.');
}
/**
@@ -242,7 +242,7 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
$db2 = Database::getConnection('default', 'default');
// Opening a connection after closing it should yield an object different than the original.
- $this->assertNotIdentical($db1, $db2, t('Opening the default connection after it is closed returns a new object.'));
+ $this->assertNotIdentical($db1, $db2, 'Opening the default connection after it is closed returns a new object.');
}
/**
@@ -257,8 +257,8 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
// In the MySQL driver, the port can be different, so check individual
// options.
- $this->assertEqual($connection_info['default']['driver'], $connectionOptions['driver'], t('The default connection info driver matches the current connection options driver.'));
- $this->assertEqual($connection_info['default']['database'], $connectionOptions['database'], t('The default connection info database matches the current connection options database.'));
+ $this->assertEqual($connection_info['default']['driver'], $connectionOptions['driver'], 'The default connection info driver matches the current connection options driver.');
+ $this->assertEqual($connection_info['default']['database'], $connectionOptions['database'], 'The default connection info database matches the current connection options database.');
// Set up identical slave and confirm connection options are identical.
Database::addConnectionInfo('default', 'slave', $connection_info['default']);
@@ -267,7 +267,7 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
// Get a fresh copy of the default connection options.
$connectionOptions = $db->getConnectionOptions();
- $this->assertIdentical($connectionOptions, $connectionOptions2, t('The default and slave connection options are identical.'));
+ $this->assertIdentical($connectionOptions, $connectionOptions2, 'The default and slave connection options are identical.');
// Set up a new connection with different connection info.
$test = $connection_info['default'];
@@ -277,7 +277,46 @@ class DatabaseConnectionTestCase extends DatabaseTestCase {
// Get a fresh copy of the default connection options.
$connectionOptions = $db->getConnectionOptions();
- $this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], t('The test connection info database does not match the current connection options database.'));
+ $this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], 'The test connection info database does not match the current connection options database.');
+ }
+}
+
+/**
+ * Test cloning Select queries.
+ */
+class DatabaseSelectCloneTest extends DatabaseTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Select tests, cloning',
+ 'description' => 'Test cloning Select queries.',
+ 'group' => 'Database',
+ );
+ }
+
+ /**
+ * Test that subqueries as value within conditions are cloned properly.
+ */
+ function testSelectConditionSubQueryCloning() {
+ $subquery = db_select('test', 't');
+ $subquery->addField('t', 'id', 'id');
+ $subquery->condition('age', 28, '<');
+
+ $query = db_select('test', 't');
+ $query->addField('t', 'name', 'name');
+ $query->condition('id', $subquery, 'IN');
+
+ $clone = clone $query;
+ // Cloned query should not be altered by the following modification
+ // happening on original query.
+ $subquery->condition('age', 25, '>');
+
+ $clone_result = $clone->countQuery()->execute()->fetchField();
+ $query_result = $query->countQuery()->execute()->fetchField();
+
+ // Make sure the cloned query has not been modified
+ $this->assertEqual(3, $clone_result, 'The cloned query returns the expected number of rows');
+ $this->assertEqual(2, $query_result, 'The query returns the expected number of rows');
}
}
@@ -302,14 +341,14 @@ class DatabaseFetchTestCase extends DatabaseTestCase {
function testQueryFetchDefault() {
$records = array();
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25));
- $this->assertTrue($result instanceof DatabaseStatementInterface, t('Result set is a Drupal statement object.'));
+ $this->assertTrue($result instanceof DatabaseStatementInterface, 'Result set is a Drupal statement object.');
foreach ($result as $record) {
$records[] = $record;
- $this->assertTrue(is_object($record), t('Record is an object.'));
- $this->assertIdentical($record->name, 'John', t('25 year old is John.'));
+ $this->assertTrue(is_object($record), 'Record is an object.');
+ $this->assertIdentical($record->name, 'John', '25 year old is John.');
}
- $this->assertIdentical(count($records), 1, t('There is only one record.'));
+ $this->assertIdentical(count($records), 1, 'There is only one record.');
}
/**
@@ -320,11 +359,11 @@ class DatabaseFetchTestCase extends DatabaseTestCase {
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_OBJ));
foreach ($result as $record) {
$records[] = $record;
- $this->assertTrue(is_object($record), t('Record is an object.'));
- $this->assertIdentical($record->name, 'John', t('25 year old is John.'));
+ $this->assertTrue(is_object($record), 'Record is an object.');
+ $this->assertIdentical($record->name, 'John', '25 year old is John.');
}
- $this->assertIdentical(count($records), 1, t('There is only one record.'));
+ $this->assertIdentical(count($records), 1, 'There is only one record.');
}
/**
@@ -335,12 +374,12 @@ class DatabaseFetchTestCase extends DatabaseTestCase {
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_ASSOC));
foreach ($result as $record) {
$records[] = $record;
- if ($this->assertTrue(is_array($record), t('Record is an array.'))) {
- $this->assertIdentical($record['name'], 'John', t('Record can be accessed associatively.'));
+ if ($this->assertTrue(is_array($record), 'Record is an array.')) {
+ $this->assertIdentical($record['name'], 'John', 'Record can be accessed associatively.');
}
}
- $this->assertIdentical(count($records), 1, t('There is only one record.'));
+ $this->assertIdentical(count($records), 1, 'There is only one record.');
}
/**
@@ -353,12 +392,12 @@ class DatabaseFetchTestCase extends DatabaseTestCase {
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => 'FakeRecord'));
foreach ($result as $record) {
$records[] = $record;
- if ($this->assertTrue($record instanceof FakeRecord, t('Record is an object of class FakeRecord.'))) {
- $this->assertIdentical($record->name, 'John', t('25 year old is John.'));
+ if ($this->assertTrue($record instanceof FakeRecord, 'Record is an object of class FakeRecord.')) {
+ $this->assertIdentical($record->name, 'John', '25 year old is John.');
}
}
- $this->assertIdentical(count($records), 1, t('There is only one record.'));
+ $this->assertIdentical(count($records), 1, 'There is only one record.');
}
}
@@ -387,8 +426,8 @@ class DatabaseFetch2TestCase extends DatabaseTestCase {
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_NUM));
foreach ($result as $record) {
$records[] = $record;
- if ($this->assertTrue(is_array($record), t('Record is an array.'))) {
- $this->assertIdentical($record[0], 'John', t('Record can be accessed numerically.'));
+ if ($this->assertTrue(is_array($record), 'Record is an array.')) {
+ $this->assertIdentical($record[0], 'John', 'Record can be accessed numerically.');
}
}
@@ -403,13 +442,13 @@ class DatabaseFetch2TestCase extends DatabaseTestCase {
$result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25), array('fetch' => PDO::FETCH_BOTH));
foreach ($result as $record) {
$records[] = $record;
- if ($this->assertTrue(is_array($record), t('Record is an array.'))) {
- $this->assertIdentical($record[0], 'John', t('Record can be accessed numerically.'));
- $this->assertIdentical($record['name'], 'John', t('Record can be accessed associatively.'));
+ if ($this->assertTrue(is_array($record), 'Record is an array.')) {
+ $this->assertIdentical($record[0], 'John', 'Record can be accessed numerically.');
+ $this->assertIdentical($record['name'], 'John', 'Record can be accessed associatively.');
}
}
- $this->assertIdentical(count($records), 1, t('There is only one record.'));
+ $this->assertIdentical(count($records), 1, 'There is only one record.');
}
/**
@@ -419,12 +458,12 @@ class DatabaseFetch2TestCase extends DatabaseTestCase {
$records = array();
$result = db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25));
$column = $result->fetchCol();
- $this->assertIdentical(count($column), 3, t('fetchCol() returns the right number of records.'));
+ $this->assertIdentical(count($column), 3, 'fetchCol() returns the right number of records.');
$result = db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25));
$i = 0;
foreach ($result as $record) {
- $this->assertIdentical($record->name, $column[$i++], t('Column matches direct accesss.'));
+ $this->assertIdentical($record->name, $column[$i++], 'Column matches direct accesss.');
}
}
}
@@ -456,9 +495,9 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
$query->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertIdentical($num_records_before + 1, (int) $num_records_after, t('Record inserts correctly.'));
+ $this->assertIdentical($num_records_before + 1, (int) $num_records_after, 'Record inserts correctly.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Yoko'))->fetchField();
- $this->assertIdentical($saved_age, '29', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '29', 'Can retrieve after inserting.');
}
/**
@@ -485,13 +524,13 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
$query->execute();
$num_records_after = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertIdentical($num_records_before + 3, $num_records_after, t('Record inserts correctly.'));
+ $this->assertIdentical($num_records_before + 3, $num_records_after, 'Record inserts correctly.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();
- $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();
- $this->assertIdentical($saved_age, '31', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();
- $this->assertIdentical($saved_age, '32', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');
}
/**
@@ -520,13 +559,13 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
$query->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertIdentical((int) $num_records_before + 3, (int) $num_records_after, t('Record inserts correctly.'));
+ $this->assertIdentical((int) $num_records_before + 3, (int) $num_records_after, 'Record inserts correctly.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();
- $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();
- $this->assertIdentical($saved_age, '31', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();
- $this->assertIdentical($saved_age, '32', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');
}
/**
@@ -542,11 +581,11 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
->values(array('Moe', '32'))
->execute();
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Larry'))->fetchField();
- $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Curly'))->fetchField();
- $this->assertIdentical($saved_age, '31', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '31', 'Can retrieve after inserting.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Moe'))->fetchField();
- $this->assertIdentical($saved_age, '32', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '32', 'Can retrieve after inserting.');
}
/**
@@ -560,7 +599,7 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
))
->execute();
- $this->assertIdentical($id, '5', t('Auto-increment ID returned successfully.'));
+ $this->assertIdentical($id, '5', 'Auto-increment ID returned successfully.');
}
/**
@@ -586,7 +625,7 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
->execute();
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Meredith'))->fetchField();
- $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '30', 'Can retrieve after inserting.');
}
}
@@ -608,12 +647,12 @@ class DatabaseInsertLOBTestCase extends DatabaseTestCase {
*/
function testInsertOneBlob() {
$data = "This is\000a test.";
- $this->assertTrue(strlen($data) === 15, t('Test data contains a NULL.'));
+ $this->assertTrue(strlen($data) === 15, 'Test data contains a NULL.');
$id = db_insert('test_one_blob')
->fields(array('blob1' => $data))
->execute();
$r = db_query('SELECT * FROM {test_one_blob} WHERE id = :id', array(':id' => $id))->fetchAssoc();
- $this->assertTrue($r['blob1'] === $data, t('Can insert a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));
+ $this->assertTrue($r['blob1'] === $data, format_string('Can insert a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));
}
/**
@@ -627,7 +666,7 @@ class DatabaseInsertLOBTestCase extends DatabaseTestCase {
))
->execute();
$r = db_query('SELECT * FROM {test_two_blobs} WHERE id = :id', array(':id' => $id))->fetchAssoc();
- $this->assertTrue($r['blob1'] === 'This is' && $r['blob2'] === 'a test', t('Can insert multiple blobs per row.'));
+ $this->assertTrue($r['blob1'] === 'This is' && $r['blob2'] === 'a test', 'Can insert multiple blobs per row.');
}
}
@@ -654,7 +693,7 @@ class DatabaseInsertDefaultsTestCase extends DatabaseTestCase {
$schema = drupal_get_schema('test');
$job = db_query('SELECT job FROM {test} WHERE id = :id', array(':id' => $id))->fetchField();
- $this->assertEqual($job, $schema['fields']['job']['default'], t('Default field value is set.'));
+ $this->assertEqual($job, $schema['fields']['job']['default'], 'Default field value is set.');
}
/**
@@ -666,13 +705,13 @@ class DatabaseInsertDefaultsTestCase extends DatabaseTestCase {
try {
$result = db_insert('test')->execute();
// This is only executed if no exception has been thrown.
- $this->fail(t('Expected exception NoFieldsException has not been thrown.'));
+ $this->fail('Expected exception NoFieldsException has not been thrown.');
} catch (NoFieldsException $e) {
- $this->pass(t('Expected exception NoFieldsException has been thrown.'));
+ $this->pass('Expected exception NoFieldsException has been thrown.');
}
$num_records_after = (int) db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertIdentical($num_records_before, $num_records_after, t('Do nothing as no fields are specified.'));
+ $this->assertIdentical($num_records_before, $num_records_after, 'Do nothing as no fields are specified.');
}
/**
@@ -687,7 +726,7 @@ class DatabaseInsertDefaultsTestCase extends DatabaseTestCase {
$schema = drupal_get_schema('test');
$job = db_query('SELECT job FROM {test} WHERE id = :id', array(':id' => $id))->fetchField();
- $this->assertEqual($job, $schema['fields']['job']['default'], t('Default field value is set.'));
+ $this->assertEqual($job, $schema['fields']['job']['default'], 'Default field value is set.');
}
}
@@ -712,10 +751,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->fields(array('name' => 'Tiffany'))
->condition('id', 1)
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$saved_name = db_query('SELECT name FROM {test} WHERE id = :id', array(':id' => 1))->fetchField();
- $this->assertIdentical($saved_name, 'Tiffany', t('Updated name successfully.'));
+ $this->assertIdentical($saved_name, 'Tiffany', 'Updated name successfully.');
}
/**
@@ -727,10 +766,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->fields(array('age' => NULL))
->condition('name', 'Kermit')
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$saved_age = db_query('SELECT age FROM {test_null} WHERE name = :name', array(':name' => 'Kermit'))->fetchField();
- $this->assertNull($saved_age, t('Updated name successfully.'));
+ $this->assertNull($saved_age, 'Updated name successfully.');
}
/**
@@ -741,10 +780,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('job', 'Singer')
->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -755,10 +794,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('age', 26, '>')
->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -769,10 +808,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->where('age > :age', array(':age' => 26))
->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -784,10 +823,10 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
->where('age > :age', array(':age' => 26))
->condition('name', 'Ringo');
$num_updated = $update->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '1', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');
}
/**
@@ -807,7 +846,21 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
$num_rows = db_update('test')
->expression('age', 'age * age')
->execute();
- $this->assertIdentical($num_rows, 3, t('Number of affected rows are returned.'));
+ $this->assertIdentical($num_rows, 3, 'Number of affected rows are returned.');
+ }
+
+ /**
+ * Confirm that we can update the primary key of a record successfully.
+ */
+ function testPrimaryKeyUpdate() {
+ $num_updated = db_update('test')
+ ->fields(array('id' => 42, 'name' => 'John'))
+ ->condition('id', 1)
+ ->execute();
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
+
+ $saved_name= db_query('SELECT name FROM {test} WHERE id = :id', array(':id' => 42))->fetchField();
+ $this->assertIdentical($saved_name, 'John', 'Updated primary key successfully.');
}
}
@@ -835,10 +888,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->condition('name', 'Paul')
);
$num_updated = $update->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -849,10 +902,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('name', array('John', 'Paul'), 'IN')
->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -865,10 +918,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('name', array('John', 'Paul', 'George'), 'NoT IN')
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '1', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');
}
/**
@@ -879,10 +932,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('age', array(25, 26), 'BETWEEN')
->execute();
- $this->assertIdentical($num_updated, 2, t('Updated 2 records.'));
+ $this->assertIdentical($num_updated, 2, 'Updated 2 records.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '2', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '2', 'Updated fields successfully.');
}
/**
@@ -893,10 +946,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->condition('name', '%ge%', 'LIKE')
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '1', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');
}
/**
@@ -910,15 +963,15 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->fields(array('job' => 'Musician'))
->expression('age', 'age + :age', array(':age' => 4))
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$num_matches = db_query('SELECT COUNT(*) FROM {test} WHERE job = :job', array(':job' => 'Musician'))->fetchField();
- $this->assertIdentical($num_matches, '1', t('Updated fields successfully.'));
+ $this->assertIdentical($num_matches, '1', 'Updated fields successfully.');
$person = db_query('SELECT * FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetch();
- $this->assertEqual($person->name, 'Ringo', t('Name set correctly.'));
- $this->assertEqual($person->age, $before_age + 4, t('Age set correctly.'));
- $this->assertEqual($person->job, 'Musician', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Ringo', 'Name set correctly.');
+ $this->assertEqual($person->age, $before_age + 4, 'Age set correctly.');
+ $this->assertEqual($person->job, 'Musician', 'Job set correctly.');
$GLOBALS['larry_test'] = 0;
}
@@ -931,10 +984,10 @@ class DatabaseUpdateComplexTestCase extends DatabaseTestCase {
->condition('name', 'Ringo')
->expression('age', 'age + :age', array(':age' => 4))
->execute();
- $this->assertIdentical($num_updated, 1, t('Updated 1 record.'));
+ $this->assertIdentical($num_updated, 1, 'Updated 1 record.');
$after_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchField();
- $this->assertEqual($before_age + 4, $after_age, t('Age updated correctly'));
+ $this->assertEqual($before_age + 4, $after_age, 'Age updated correctly');
}
}
@@ -956,7 +1009,7 @@ class DatabaseUpdateLOBTestCase extends DatabaseTestCase {
*/
function testUpdateOneBlob() {
$data = "This is\000a test.";
- $this->assertTrue(strlen($data) === 15, t('Test data contains a NULL.'));
+ $this->assertTrue(strlen($data) === 15, 'Test data contains a NULL.');
$id = db_insert('test_one_blob')
->fields(array('blob1' => $data))
->execute();
@@ -968,7 +1021,7 @@ class DatabaseUpdateLOBTestCase extends DatabaseTestCase {
->execute();
$r = db_query('SELECT * FROM {test_one_blob} WHERE id = :id', array(':id' => $id))->fetchAssoc();
- $this->assertTrue($r['blob1'] === $data, t('Can update a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));
+ $this->assertTrue($r['blob1'] === $data, format_string('Can update a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r))));
}
/**
@@ -988,7 +1041,7 @@ class DatabaseUpdateLOBTestCase extends DatabaseTestCase {
->execute();
$r = db_query('SELECT * FROM {test_two_blobs} WHERE id = :id', array(':id' => $id))->fetchAssoc();
- $this->assertTrue($r['blob1'] === 'and so' && $r['blob2'] === 'is this', t('Can update multiple blobs per row.'));
+ $this->assertTrue($r['blob1'] === 'and so' && $r['blob2'] === 'is this', 'Can update multiple blobs per row.');
}
}
@@ -1028,10 +1081,10 @@ class DatabaseDeleteTruncateTestCase extends DatabaseTestCase {
->condition('pid', $subquery, 'IN');
$num_deleted = $delete->execute();
- $this->assertEqual($num_deleted, 1, t("Deleted 1 record."));
+ $this->assertEqual($num_deleted, 1, "Deleted 1 record.");
$num_records_after = db_query('SELECT COUNT(*) FROM {test_task}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after + $num_deleted, t('Deletion adds up.'));
+ $this->assertEqual($num_records_before, $num_records_after + $num_deleted, 'Deletion adds up.');
}
/**
@@ -1043,10 +1096,10 @@ class DatabaseDeleteTruncateTestCase extends DatabaseTestCase {
$num_deleted = db_delete('test')
->condition('id', 1)
->execute();
- $this->assertIdentical($num_deleted, 1, t('Deleted 1 record.'));
+ $this->assertIdentical($num_deleted, 1, 'Deleted 1 record.');
$num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after + $num_deleted, t('Deletion adds up.'));
+ $this->assertEqual($num_records_before, $num_records_after + $num_deleted, 'Deletion adds up.');
}
/**
@@ -1058,7 +1111,7 @@ class DatabaseDeleteTruncateTestCase extends DatabaseTestCase {
db_truncate('test')->execute();
$num_records_after = db_query("SELECT COUNT(*) FROM {test}")->fetchField();
- $this->assertEqual(0, $num_records_after, t('Truncate really deletes everything.'));
+ $this->assertEqual(0, $num_records_after, 'Truncate really deletes everything.');
}
}
@@ -1089,15 +1142,15 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
))
->execute();
- $this->assertEqual($result, MergeQuery::STATUS_INSERT, t('Insert status returned.'));
+ $this->assertEqual($result, MergeQuery::STATUS_INSERT, 'Insert status returned.');
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before + 1, $num_records_after, t('Merge inserted properly.'));
+ $this->assertEqual($num_records_before + 1, $num_records_after, 'Merge inserted properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Presenter'))->fetch();
- $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.'));
- $this->assertEqual($person->age, 31, t('Age set correctly.'));
- $this->assertEqual($person->job, 'Presenter', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');
+ $this->assertEqual($person->age, 31, 'Age set correctly.');
+ $this->assertEqual($person->job, 'Presenter', 'Job set correctly.');
}
/**
@@ -1114,15 +1167,15 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
))
->execute();
- $this->assertEqual($result, MergeQuery::STATUS_UPDATE, t('Update status returned.'));
+ $this->assertEqual($result, MergeQuery::STATUS_UPDATE, 'Update status returned.');
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.'));
- $this->assertEqual($person->age, 31, t('Age set correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');
+ $this->assertEqual($person->age, 31, 'Age set correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');
}
/**
@@ -1138,12 +1191,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.'));
- $this->assertEqual($person->age, 30, t('Age skipped correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');
+ $this->assertEqual($person->age, 30, 'Age skipped correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');
}
/**
@@ -1164,12 +1217,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Joe', t('Name set correctly.'));
- $this->assertEqual($person->age, 30, t('Age skipped correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Joe', 'Name set correctly.');
+ $this->assertEqual($person->age, 30, 'Age skipped correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');
}
/**
@@ -1193,12 +1246,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge updated properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.'));
- $this->assertEqual($person->age, $age_before + 4, t('Age updated correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job set correctly.'));
+ $this->assertEqual($person->name, 'Tiffany', 'Name set correctly.');
+ $this->assertEqual($person->age, $age_before + 4, 'Age updated correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job set correctly.');
}
/**
@@ -1212,12 +1265,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before + 1, $num_records_after, t('Merge inserted properly.'));
+ $this->assertEqual($num_records_before + 1, $num_records_after, 'Merge inserted properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Presenter'))->fetch();
- $this->assertEqual($person->name, '', t('Name set correctly.'));
- $this->assertEqual($person->age, 0, t('Age set correctly.'));
- $this->assertEqual($person->job, 'Presenter', t('Job set correctly.'));
+ $this->assertEqual($person->name, '', 'Name set correctly.');
+ $this->assertEqual($person->age, 0, 'Age set correctly.');
+ $this->assertEqual($person->job, 'Presenter', 'Job set correctly.');
}
/**
@@ -1231,12 +1284,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge skipped properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge skipped properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Meredith', t('Name skipped correctly.'));
- $this->assertEqual($person->age, 30, t('Age skipped correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job skipped correctly.'));
+ $this->assertEqual($person->name, 'Meredith', 'Name skipped correctly.');
+ $this->assertEqual($person->age, 30, 'Age skipped correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job skipped correctly.');
db_merge('test_people')
->key(array('job' => 'Speaker'))
@@ -1244,12 +1297,12 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
- $this->assertEqual($num_records_before, $num_records_after, t('Merge skipped properly.'));
+ $this->assertEqual($num_records_before, $num_records_after, 'Merge skipped properly.');
$person = db_query('SELECT * FROM {test_people} WHERE job = :job', array(':job' => 'Speaker'))->fetch();
- $this->assertEqual($person->name, 'Meredith', t('Name skipped correctly.'));
- $this->assertEqual($person->age, 30, t('Age skipped correctly.'));
- $this->assertEqual($person->job, 'Speaker', t('Job skipped correctly.'));
+ $this->assertEqual($person->name, 'Meredith', 'Name skipped correctly.');
+ $this->assertEqual($person->age, 30, 'Age skipped correctly.');
+ $this->assertEqual($person->job, 'Speaker', 'Job skipped correctly.');
}
/**
@@ -1266,10 +1319,10 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
->execute();
}
catch (InvalidMergeQueryException $e) {
- $this->pass(t('InvalidMergeQueryException thrown for invalid query.'));
+ $this->pass('InvalidMergeQueryException thrown for invalid query.');
return;
}
- $this->fail(t('No InvalidMergeQueryException thrown'));
+ $this->fail('No InvalidMergeQueryException thrown');
}
}
@@ -1300,7 +1353,7 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$num_records++;
}
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
}
/**
@@ -1320,8 +1373,8 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$query = (string)$query;
$expected = "/* Testing query comments */ SELECT test.name AS name, test.age AS age\nFROM \n{test} test";
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
- $this->assertEqual($query, $expected, t('The flattened query contains the comment string.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
+ $this->assertEqual($query, $expected, 'The flattened query contains the comment string.');
}
/**
@@ -1341,8 +1394,8 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$query = (string)$query;
$expected = "/* Testing query comments SELECT nid FROM {node}; -- */ SELECT test.name AS name, test.age AS age\nFROM \n{test} test";
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
- $this->assertEqual($query, $expected, t('The flattened query contains the sanitised comment string.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
+ $this->assertEqual($query, $expected, 'The flattened query contains the sanitised comment string.');
}
/**
@@ -1356,13 +1409,13 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$result = $query->execute();
// Check that the aliases are being created the way we want.
- $this->assertEqual($name_field, 'name', t('Name field alias is correct.'));
- $this->assertEqual($age_field, 'age', t('Age field alias is correct.'));
+ $this->assertEqual($name_field, 'name', 'Name field alias is correct.');
+ $this->assertEqual($age_field, 'age', 'Age field alias is correct.');
// Ensure that we got the right record.
$record = $result->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
- $this->assertEqual($record->$age_field, 27, t('Fetched age is correct.'));
+ $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');
+ $this->assertEqual($record->$age_field, 27, 'Fetched age is correct.');
}
/**
@@ -1376,13 +1429,13 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$result = $query->execute();
// Check that the aliases are being created the way we want.
- $this->assertEqual($name_field, 'name', t('Name field alias is correct.'));
- $this->assertEqual($age_field, 'double_age', t('Age field alias is correct.'));
+ $this->assertEqual($name_field, 'name', 'Name field alias is correct.');
+ $this->assertEqual($age_field, 'double_age', 'Age field alias is correct.');
// Ensure that we got the right record.
$record = $result->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
- $this->assertEqual($record->$age_field, 27*2, t('Fetched age expression is correct.'));
+ $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');
+ $this->assertEqual($record->$age_field, 27*2, 'Fetched age expression is correct.');
}
/**
@@ -1397,14 +1450,14 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$result = $query->execute();
// Check that the aliases are being created the way we want.
- $this->assertEqual($age_double_field, 'expression', t('Double age field alias is correct.'));
- $this->assertEqual($age_triple_field, 'expression_2', t('Triple age field alias is correct.'));
+ $this->assertEqual($age_double_field, 'expression', 'Double age field alias is correct.');
+ $this->assertEqual($age_triple_field, 'expression_2', 'Triple age field alias is correct.');
// Ensure that we got the right record.
$record = $result->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
- $this->assertEqual($record->$age_double_field, 27*2, t('Fetched double age expression is correct.'));
- $this->assertEqual($record->$age_triple_field, 27*3, t('Fetched triple age expression is correct.'));
+ $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');
+ $this->assertEqual($record->$age_double_field, 27*2, 'Fetched double age expression is correct.');
+ $this->assertEqual($record->$age_triple_field, 27*3, 'Fetched triple age expression is correct.');
}
/**
@@ -1417,17 +1470,17 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->execute()->fetchObject();
// Check that all fields we asked for are present.
- $this->assertNotNull($record->id, t('ID field is present.'));
- $this->assertNotNull($record->name, t('Name field is present.'));
- $this->assertNotNull($record->age, t('Age field is present.'));
- $this->assertNotNull($record->job, t('Job field is present.'));
+ $this->assertNotNull($record->id, 'ID field is present.');
+ $this->assertNotNull($record->name, 'Name field is present.');
+ $this->assertNotNull($record->age, 'Age field is present.');
+ $this->assertNotNull($record->job, 'Job field is present.');
// Ensure that we got the right record.
// Check that all fields we asked for are present.
- $this->assertEqual($record->id, 2, t('ID field has the correct value.'));
- $this->assertEqual($record->name, 'George', t('Name field has the correct value.'));
- $this->assertEqual($record->age, 27, t('Age field has the correct value.'));
- $this->assertEqual($record->job, 'Singer', t('Job field has the correct value.'));
+ $this->assertEqual($record->id, 2, 'ID field has the correct value.');
+ $this->assertEqual($record->name, 'George', 'Name field has the correct value.');
+ $this->assertEqual($record->age, 27, 'Age field has the correct value.');
+ $this->assertEqual($record->job, 'Singer', 'Job field has the correct value.');
}
/**
@@ -1440,17 +1493,17 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->execute()->fetchObject();
// Check that all fields we asked for are present.
- $this->assertNotNull($record->id, t('ID field is present.'));
- $this->assertNotNull($record->name, t('Name field is present.'));
- $this->assertNotNull($record->age, t('Age field is present.'));
- $this->assertNotNull($record->job, t('Job field is present.'));
+ $this->assertNotNull($record->id, 'ID field is present.');
+ $this->assertNotNull($record->name, 'Name field is present.');
+ $this->assertNotNull($record->age, 'Age field is present.');
+ $this->assertNotNull($record->job, 'Job field is present.');
// Ensure that we got the right record.
// Check that all fields we asked for are present.
- $this->assertEqual($record->id, 2, t('ID field has the correct value.'));
- $this->assertEqual($record->name, 'George', t('Name field has the correct value.'));
- $this->assertEqual($record->age, 27, t('Age field has the correct value.'));
- $this->assertEqual($record->job, 'Singer', t('Job field has the correct value.'));
+ $this->assertEqual($record->id, 2, 'ID field has the correct value.');
+ $this->assertEqual($record->name, 'George', 'Name field has the correct value.');
+ $this->assertEqual($record->age, 27, 'Age field has the correct value.');
+ $this->assertEqual($record->job, 'Singer', 'Job field has the correct value.');
}
/**
@@ -1464,8 +1517,8 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->isNull('age')
->execute()->fetchCol();
- $this->assertEqual(count($names), 1, t('Correct number of records found with NULL age.'));
- $this->assertEqual($names[0], 'Fozzie', t('Correct record returned for NULL age.'));
+ $this->assertEqual(count($names), 1, 'Correct number of records found with NULL age.');
+ $this->assertEqual($names[0], 'Fozzie', 'Correct record returned for NULL age.');
}
/**
@@ -1480,9 +1533,9 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->orderBy('name')
->execute()->fetchCol();
- $this->assertEqual(count($names), 2, t('Correct number of records found withNOT NULL age.'));
- $this->assertEqual($names[0], 'Gonzo', t('Correct record returned for NOT NULL age.'));
- $this->assertEqual($names[1], 'Kermit', t('Correct record returned for NOT NULL age.'));
+ $this->assertEqual(count($names), 2, 'Correct number of records found withNOT NULL age.');
+ $this->assertEqual($names[0], 'Gonzo', 'Correct record returned for NOT NULL age.');
+ $this->assertEqual($names[1], 'Kermit', 'Correct record returned for NOT NULL age.');
}
/**
@@ -1503,10 +1556,10 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$names = $query_1->execute()->fetchCol();
// Ensure we only get 2 records.
- $this->assertEqual(count($names), 2, t('UNION correctly discarded duplicates.'));
+ $this->assertEqual(count($names), 2, 'UNION correctly discarded duplicates.');
- $this->assertEqual($names[0], 'George', t('First query returned correct name.'));
- $this->assertEqual($names[1], 'Ringo', t('Second query returned correct name.'));
+ $this->assertEqual($names[0], 'George', 'First query returned correct name.');
+ $this->assertEqual($names[1], 'Ringo', 'Second query returned correct name.');
}
/**
@@ -1526,11 +1579,11 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
$names = $query_1->execute()->fetchCol();
// Ensure we get all 3 records.
- $this->assertEqual(count($names), 3, t('UNION ALL correctly preserved duplicates.'));
+ $this->assertEqual(count($names), 3, 'UNION ALL correctly preserved duplicates.');
- $this->assertEqual($names[0], 'George', t('First query returned correct first name.'));
- $this->assertEqual($names[1], 'Ringo', t('Second query returned correct second name.'));
- $this->assertEqual($names[2], 'Ringo', t('Third query returned correct name.'));
+ $this->assertEqual($names[0], 'George', 'First query returned correct first name.');
+ $this->assertEqual($names[1], 'Ringo', 'Second query returned correct second name.');
+ $this->assertEqual($names[2], 'Ringo', 'Third query returned correct name.');
}
/**
@@ -1565,7 +1618,7 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->orderBy('id')
->execute()
->fetchCol();
- $this->assertEqual($ordered_ids, $expected_ids, t('A query without random ordering returns IDs in the correct order.'));
+ $this->assertEqual($ordered_ids, $expected_ids, 'A query without random ordering returns IDs in the correct order.');
// Now perform the same query, but instead choose a random ordering. We
// expect this to contain a differently ordered version of the original
@@ -1576,10 +1629,10 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->orderRandom()
->execute()
->fetchCol();
- $this->assertNotEqual($randomized_ids, $ordered_ids, t('A query with random ordering returns an unordered set of IDs.'));
+ $this->assertNotEqual($randomized_ids, $ordered_ids, 'A query with random ordering returns an unordered set of IDs.');
$sorted_ids = $randomized_ids;
sort($sorted_ids);
- $this->assertEqual($sorted_ids, $ordered_ids, t('After sorting the random list, the result matches the original query.'));
+ $this->assertEqual($sorted_ids, $ordered_ids, 'After sorting the random list, the result matches the original query.');
// Now perform the exact same query again, and make sure the order is
// different.
@@ -1589,10 +1642,10 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
->orderRandom()
->execute()
->fetchCol();
- $this->assertNotEqual($randomized_ids_second_set, $randomized_ids, t('Performing the query with random ordering a second time returns IDs in a different order.'));
+ $this->assertNotEqual($randomized_ids_second_set, $randomized_ids, 'Performing the query with random ordering a second time returns IDs in a different order.');
$sorted_ids_second_set = $randomized_ids_second_set;
sort($sorted_ids_second_set);
- $this->assertEqual($sorted_ids_second_set, $sorted_ids, t('After sorting the second random list, the result matches the sorted version of the first random list.'));
+ $this->assertEqual($sorted_ids_second_set, $sorted_ids, 'After sorting the second random list, the result matches the sorted version of the first random list.');
}
/**
@@ -1649,7 +1702,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// WHERE tt.task = 'code'
$people = $select->execute()->fetchCol();
- $this->assertEqual(count($people), 1, t('Returned the correct number of rows.'));
+ $this->assertEqual(count($people), 1, 'Returned the correct number of rows.');
}
}
@@ -1676,7 +1729,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// INNER JOIN test t ON t.id=tt.pid
$people = $select->execute()->fetchCol();
- $this->assertEqual(count($people), 1, t('Returned the correct number of rows.'));
+ $this->assertEqual(count($people), 1, 'Returned the correct number of rows.');
}
/**
@@ -1699,7 +1752,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// FROM test tt2
// WHERE tt2.pid IN (SELECT tt.pid AS pid FROM test_task tt WHERE tt.priority=1)
$people = $select->execute()->fetchCol();
- $this->assertEqual(count($people), 5, t('Returned the correct number of rows.'));
+ $this->assertEqual(count($people), 5, 'Returned the correct number of rows.');
}
/**
@@ -1723,7 +1776,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// INNER JOIN (SELECT tt.pid AS pid FROM test_task tt WHERE priority=1) tt ON t.id=tt.pid
$people = $select->execute()->fetchCol();
- $this->assertEqual(count($people), 2, t('Returned the correct number of rows.'));
+ $this->assertEqual(count($people), 2, 'Returned the correct number of rows.');
}
/**
@@ -1753,7 +1806,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// Ensure that we got the right record.
$record = $result->fetch();
- $this->assertEqual($record->name, 'George', t('Fetched name is correct using EXISTS query.'));
+ $this->assertEqual($record->name, 'George', 'Fetched name is correct using EXISTS query.');
}
/**
@@ -1783,7 +1836,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
// Ensure that we got the right number of records.
$people = $query->execute()->fetchCol();
- $this->assertEqual(count($people), 3, t('NOT EXISTS query returned the correct results.'));
+ $this->assertEqual(count($people), 3, 'NOT EXISTS query returned the correct results.');
}
}
@@ -1814,11 +1867,11 @@ class DatabaseSelectOrderedTestCase extends DatabaseTestCase {
$last_age = 0;
foreach ($result as $record) {
$num_records++;
- $this->assertTrue($record->age >= $last_age, t('Results returned in correct order.'));
+ $this->assertTrue($record->age >= $last_age, 'Results returned in correct order.');
$last_age = $record->age;
}
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
}
/**
@@ -1845,11 +1898,11 @@ class DatabaseSelectOrderedTestCase extends DatabaseTestCase {
$num_records++;
foreach ($record as $kk => $col) {
if ($expected[$k][$kk] != $results[$k][$kk]) {
- $this->assertTrue(FALSE, t('Results returned in correct order.'));
+ $this->assertTrue(FALSE, 'Results returned in correct order.');
}
}
}
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
}
/**
@@ -1866,11 +1919,11 @@ class DatabaseSelectOrderedTestCase extends DatabaseTestCase {
$last_age = 100000000;
foreach ($result as $record) {
$num_records++;
- $this->assertTrue($record->age <= $last_age, t('Results returned in correct order.'));
+ $this->assertTrue($record->age <= $last_age, 'Results returned in correct order.');
$last_age = $record->age;
}
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
}
}
@@ -1904,12 +1957,12 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$last_priority = 0;
foreach ($result as $record) {
$num_records++;
- $this->assertTrue($record->$priority_field >= $last_priority, t('Results returned in correct order.'));
- $this->assertNotEqual($record->$name_field, 'Ringo', t('Taskless person not selected.'));
+ $this->assertTrue($record->$priority_field >= $last_priority, 'Results returned in correct order.');
+ $this->assertNotEqual($record->$name_field, 'Ringo', 'Taskless person not selected.');
$last_priority = $record->$priority_field;
}
- $this->assertEqual($num_records, 7, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 7, 'Returned the correct number of rows.');
}
/**
@@ -1930,11 +1983,11 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
foreach ($result as $record) {
$num_records++;
- $this->assertTrue(strcmp($record->$name_field, $last_name) >= 0, t('Results returned in correct order.'));
+ $this->assertTrue(strcmp($record->$name_field, $last_name) >= 0, 'Results returned in correct order.');
$last_priority = $record->$name_field;
}
- $this->assertEqual($num_records, 8, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 8, 'Returned the correct number of rows.');
}
/**
@@ -1953,7 +2006,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$records = array();
foreach ($result as $record) {
$num_records++;
- $this->assertTrue($record->$count_field >= $last_count, t('Results returned in correct order.'));
+ $this->assertTrue($record->$count_field >= $last_count, 'Results returned in correct order.');
$last_count = $record->$count_field;
$records[$record->$task_field] = $record->$count_field;
}
@@ -1967,10 +2020,10 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
);
foreach ($correct_results as $task => $count) {
- $this->assertEqual($records[$task], $count, t("Correct number of '@task' records found.", array('@task' => $task)));
+ $this->assertEqual($records[$task], $count, format_string("Correct number of '@task' records found.", array('@task' => $task)));
}
- $this->assertEqual($num_records, 6, t('Returned the correct number of total rows.'));
+ $this->assertEqual($num_records, 6, 'Returned the correct number of total rows.');
}
/**
@@ -1990,8 +2043,8 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$records = array();
foreach ($result as $record) {
$num_records++;
- $this->assertTrue($record->$count_field >= 2, t('Record has the minimum count.'));
- $this->assertTrue($record->$count_field >= $last_count, t('Results returned in correct order.'));
+ $this->assertTrue($record->$count_field >= 2, 'Record has the minimum count.');
+ $this->assertTrue($record->$count_field >= $last_count, 'Results returned in correct order.');
$last_count = $record->$count_field;
$records[$record->$task_field] = $record->$count_field;
}
@@ -2001,10 +2054,10 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
);
foreach ($correct_results as $task => $count) {
- $this->assertEqual($records[$task], $count, t("Correct number of '@task' records found.", array('@task' => $task)));
+ $this->assertEqual($records[$task], $count, format_string("Correct number of '@task' records found.", array('@task' => $task)));
}
- $this->assertEqual($num_records, 1, t('Returned the correct number of total rows.'));
+ $this->assertEqual($num_records, 1, 'Returned the correct number of total rows.');
}
/**
@@ -2022,7 +2075,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$num_records++;
}
- $this->assertEqual($num_records, 2, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 2, 'Returned the correct number of rows.');
}
/**
@@ -2039,7 +2092,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$num_records++;
}
- $this->assertEqual($num_records, 6, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 6, 'Returned the correct number of rows.');
}
/**
@@ -2053,13 +2106,13 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$count = $query->countQuery()->execute()->fetchField();
- $this->assertEqual($count, 4, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 4, 'Counted the correct number of records.');
// Now make sure we didn't break the original query! We should still have
// all of the fields we asked for.
$record = $query->execute()->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Correct data retrieved.'));
- $this->assertEqual($record->$age_field, 27, t('Correct data retrieved.'));
+ $this->assertEqual($record->$name_field, 'George', 'Correct data retrieved.');
+ $this->assertEqual($record->$age_field, 27, 'Correct data retrieved.');
}
function testHavingCountQuery() {
@@ -2070,7 +2123,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$query->addField('test', 'age');
$query->addExpression('age + 1');
$count = count($query->execute()->fetchCol());
- $this->assertEqual($count, 4, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 4, 'Counted the correct number of records.');
}
/**
@@ -2085,20 +2138,20 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
// Check that the 'all_fields' statement is handled properly.
$tables = $query->getTables();
- $this->assertEqual($tables['test']['all_fields'], 1, t('Query correctly sets \'all_fields\' statement.'));
+ $this->assertEqual($tables['test']['all_fields'], 1, 'Query correctly sets \'all_fields\' statement.');
$tables = $count->getTables();
- $this->assertFalse(isset($tables['test']['all_fields']), t('Count query correctly unsets \'all_fields\' statement.'));
+ $this->assertFalse(isset($tables['test']['all_fields']), 'Count query correctly unsets \'all_fields\' statement.');
// Check that the ordering clause is handled properly.
$orderby = $query->getOrderBy();
- $this->assertEqual($orderby['name'], 'ASC', t('Query correctly sets ordering clause.'));
+ $this->assertEqual($orderby['name'], 'ASC', 'Query correctly sets ordering clause.');
$orderby = $count->getOrderBy();
- $this->assertFalse(isset($orderby['name']), t('Count query correctly unsets ordering caluse.'));
+ $this->assertFalse(isset($orderby['name']), 'Count query correctly unsets ordering caluse.');
// Make sure that the count query works.
$count = $count->execute()->fetchField();
- $this->assertEqual($count, 4, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 4, 'Counted the correct number of records.');
}
@@ -2113,11 +2166,11 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
// records in the {test} table).
$query = db_select('test');
$query->fields('test', array('fail'));
- $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), t('Count Query removed fields'));
+ $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), 'Count Query removed fields');
$query = db_select('test');
$query->addExpression('fail');
- $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), t('Count Query removed expressions'));
+ $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), 'Count Query removed expressions');
}
/**
@@ -2130,7 +2183,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$count = $query->countQuery()->execute()->fetchField();
- $this->assertEqual($count, 6, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 6, 'Counted the correct number of records.');
}
/**
@@ -2143,7 +2196,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$count = $query->countQuery()->execute()->fetchField();
- $this->assertEqual($count, 3, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 3, 'Counted the correct number of records.');
// Use a column alias as, without one, the query can succeed for the wrong
// reason.
@@ -2155,7 +2208,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$count = $query->countQuery()->execute()->fetchField();
- $this->assertEqual($count, 3, t('Counted the correct number of records.'));
+ $this->assertEqual($count, 3, 'Counted the correct number of records.');
}
/**
@@ -2172,7 +2225,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$query->condition(db_or()->condition('age', 26)->condition('age', 27));
$job = $query->execute()->fetchField();
- $this->assertEqual($job, 'Songwriter', t('Correct data retrieved.'));
+ $this->assertEqual($job, 'Songwriter', 'Correct data retrieved.');
}
/**
@@ -2185,8 +2238,8 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
$query->addField($alias, 'job', 'otherjob');
$query->where("$alias.name <> test.name");
$crowded_job = $query->execute()->fetch();
- $this->assertEqual($crowded_job->job, $crowded_job->otherjob, t('Correctly joined same table twice.'));
- $this->assertNotEqual($crowded_job->name, $crowded_job->othername, t('Correctly joined same table twice.'));
+ $this->assertEqual($crowded_job->job, $crowded_job->otherjob, 'Correctly joined same table twice.');
+ $this->assertNotEqual($crowded_job->name, $crowded_job->othername, 'Correctly joined same table twice.');
}
}
@@ -2251,7 +2304,7 @@ class DatabaseSelectComplexTestCase2 extends DatabaseTestCase {
// Verify that the string only has one copy of condition placeholder 0.
$pos = strpos($str, 'db_condition_placeholder_0', 0);
$pos2 = strpos($str, 'db_condition_placeholder_0', $pos + 1);
- $this->assertFalse($pos2, "Condition placeholder is not repeated");
+ $this->assertFalse($pos2, 'Condition placeholder is not repeated.');
}
}
@@ -2295,7 +2348,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
$correct_number = $count - ($limit * $page);
}
- $this->assertEqual(count($data->names), $correct_number, t('Correct number of records returned by pager: @number', array('@number' => $correct_number)));
+ $this->assertEqual(count($data->names), $correct_number, format_string('Correct number of records returned by pager: @number', array('@number' => $correct_number)));
}
}
@@ -2329,7 +2382,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
$correct_number = $count - ($limit * $page);
}
- $this->assertEqual(count($data->names), $correct_number, t('Correct number of records returned by pager: @number', array('@number' => $correct_number)));
+ $this->assertEqual(count($data->names), $correct_number, format_string('Correct number of records returned by pager: @number', array('@number' => $correct_number)));
}
}
@@ -2351,7 +2404,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
$ages = $outer_query
->execute()
->fetchCol();
- $this->assertEqual($ages, array(25, 26, 27, 28), t('Inner pager query returned the correct ages.'));
+ $this->assertEqual($ages, array(25, 26, 27, 28), 'Inner pager query returned the correct ages.');
}
/**
@@ -2371,7 +2424,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
$ages = $query
->execute()
->fetchCol();
- $this->assertEqual($ages, array('George', 'Ringo'), t('Pager query with having expression returned the correct ages.'));
+ $this->assertEqual($ages, array('George', 'Ringo'), 'Pager query with having expression returned the correct ages.');
}
/**
@@ -2387,7 +2440,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
->limit(1)
->execute()
->fetchField();
- $this->assertEqual($name, 'Paul', t('Pager query #1 with a specified element ID returned the correct results.'));
+ $this->assertEqual($name, 'Paul', 'Pager query #1 with a specified element ID returned the correct results.');
// Setting an element smaller than the previous one
// should not overwrite the pager $maxElement with a smaller value.
@@ -2398,7 +2451,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
->limit(1)
->execute()
->fetchField();
- $this->assertEqual($name, 'George', t('Pager query #2 with a specified element ID returned the correct results.'));
+ $this->assertEqual($name, 'George', 'Pager query #2 with a specified element ID returned the correct results.');
$name = db_select('test', 't')->extend('PagerDefault')
->fields('t', array('name'))
@@ -2406,7 +2459,7 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
->limit(1)
->execute()
->fetchField();
- $this->assertEqual($name, 'John', t('Pager query #3 with a generated element ID returned the correct results.'));
+ $this->assertEqual($name, 'John', 'Pager query #3 with a generated element ID returned the correct results.');
unset($_GET['page']);
}
@@ -2446,8 +2499,8 @@ class DatabaseSelectTableSortDefaultTestCase extends DatabaseTestCase {
$first = array_shift($data->tasks);
$last = array_pop($data->tasks);
- $this->assertEqual($first->task, $sort['first'], t('Items appear in the correct order.'));
- $this->assertEqual($last->task, $sort['last'], t('Items appear in the correct order.'));
+ $this->assertEqual($first->task, $sort['first'], 'Items appear in the correct order.');
+ $this->assertEqual($last->task, $sort['last'], 'Items appear in the correct order.');
}
}
@@ -2472,8 +2525,8 @@ class DatabaseSelectTableSortDefaultTestCase extends DatabaseTestCase {
$first = array_shift($data->tasks);
$last = array_pop($data->tasks);
- $this->assertEqual($first->task, $sort['first'], t('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));
- $this->assertEqual($last->task, $sort['last'], t('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));
+ $this->assertEqual($first->task, $sort['first'], format_string('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));
+ $this->assertEqual($last->task, $sort['last'], format_string('Items appear in the correct order sorting by @field @sort.', array('@field' => $sort['field'], '@sort' => $sort['sort'])));
}
}
@@ -2513,8 +2566,8 @@ class DatabaseTaggingTestCase extends DatabaseTestCase {
$query->addTag('test');
- $this->assertTrue($query->hasTag('test'), t('hasTag() returned true.'));
- $this->assertFalse($query->hasTag('other'), t('hasTag() returned false.'));
+ $this->assertTrue($query->hasTag('test'), 'hasTag() returned true.');
+ $this->assertFalse($query->hasTag('other'), 'hasTag() returned false.');
}
/**
@@ -2528,8 +2581,8 @@ class DatabaseTaggingTestCase extends DatabaseTestCase {
$query->addTag('test');
$query->addTag('other');
- $this->assertTrue($query->hasAllTags('test', 'other'), t('hasAllTags() returned true.'));
- $this->assertFalse($query->hasAllTags('test', 'stuff'), t('hasAllTags() returned false.'));
+ $this->assertTrue($query->hasAllTags('test', 'other'), 'hasAllTags() returned true.');
+ $this->assertFalse($query->hasAllTags('test', 'stuff'), 'hasAllTags() returned false.');
}
/**
@@ -2542,8 +2595,8 @@ class DatabaseTaggingTestCase extends DatabaseTestCase {
$query->addTag('test');
- $this->assertTrue($query->hasAnyTag('test', 'other'), t('hasAnyTag() returned true.'));
- $this->assertFalse($query->hasAnyTag('other', 'stuff'), t('hasAnyTag() returned false.'));
+ $this->assertTrue($query->hasAnyTag('test', 'other'), 'hasAnyTag() returned true.');
+ $this->assertFalse($query->hasAnyTag('other', 'stuff'), 'hasAnyTag() returned false.');
}
/**
@@ -2564,10 +2617,10 @@ class DatabaseTaggingTestCase extends DatabaseTestCase {
$query->addMetaData('test', $data);
$return = $query->getMetaData('test');
- $this->assertEqual($data, $return, t('Corect metadata returned.'));
+ $this->assertEqual($data, $return, 'Corect metadata returned.');
$return = $query->getMetaData('nothere');
- $this->assertNull($return, t('Non-existent key returned NULL.'));
+ $this->assertNull($return, 'Non-existent key returned NULL.');
}
}
@@ -2602,7 +2655,7 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$num_records++;
}
- $this->assertEqual($num_records, 2, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 2, 'Returned the correct number of rows.');
}
/**
@@ -2619,14 +2672,14 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$records = $result->fetchAll();
- $this->assertEqual(count($records), 2, t('Returned the correct number of rows.'));
+ $this->assertEqual(count($records), 2, 'Returned the correct number of rows.');
- $this->assertEqual($records[0]->name, 'George', t('Correct data retrieved.'));
- $this->assertEqual($records[0]->$tid_field, 4, t('Correct data retrieved.'));
- $this->assertEqual($records[0]->$task_field, 'sing', t('Correct data retrieved.'));
- $this->assertEqual($records[1]->name, 'George', t('Correct data retrieved.'));
- $this->assertEqual($records[1]->$tid_field, 5, t('Correct data retrieved.'));
- $this->assertEqual($records[1]->$task_field, 'sleep', t('Correct data retrieved.'));
+ $this->assertEqual($records[0]->name, 'George', 'Correct data retrieved.');
+ $this->assertEqual($records[0]->$tid_field, 4, 'Correct data retrieved.');
+ $this->assertEqual($records[0]->$task_field, 'sing', 'Correct data retrieved.');
+ $this->assertEqual($records[1]->name, 'George', 'Correct data retrieved.');
+ $this->assertEqual($records[1]->$tid_field, 5, 'Correct data retrieved.');
+ $this->assertEqual($records[1]->$task_field, 'sleep', 'Correct data retrieved.');
}
/**
@@ -2647,11 +2700,11 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$records = $result->fetchAll();
- $this->assertEqual(count($records), 1, t('Returned the correct number of rows.'));
- $this->assertEqual($records[0]->$name_field, 'John', t('Correct data retrieved.'));
- $this->assertEqual($records[0]->$tid_field, 2, t('Correct data retrieved.'));
- $this->assertEqual($records[0]->$pid_field, 1, t('Correct data retrieved.'));
- $this->assertEqual($records[0]->$task_field, 'sleep', t('Correct data retrieved.'));
+ $this->assertEqual(count($records), 1, 'Returned the correct number of rows.');
+ $this->assertEqual($records[0]->$name_field, 'John', 'Correct data retrieved.');
+ $this->assertEqual($records[0]->$tid_field, 2, 'Correct data retrieved.');
+ $this->assertEqual($records[0]->$pid_field, 1, 'Correct data retrieved.');
+ $this->assertEqual($records[0]->$task_field, 'sleep', 'Correct data retrieved.');
}
/**
@@ -2665,8 +2718,8 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$query->addTag('database_test_alter_change_fields');
$record = $query->execute()->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Correct data retrieved.'));
- $this->assertFalse(isset($record->$age_field), t('Age field not found, as intended.'));
+ $this->assertEqual($record->$name_field, 'George', 'Correct data retrieved.');
+ $this->assertFalse(isset($record->$age_field), 'Age field not found, as intended.');
}
/**
@@ -2683,8 +2736,8 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
// Ensure that we got the right record.
$record = $result->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
- $this->assertEqual($record->$age_field, 27*3, t('Fetched age expression is correct.'));
+ $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');
+ $this->assertEqual($record->$age_field, 27*3, 'Fetched age expression is correct.');
}
/**
@@ -2699,7 +2752,7 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$num_records = count($query->execute()->fetchAll());
- $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+ $this->assertEqual($num_records, 4, 'Returned the correct number of rows.');
}
/**
@@ -2723,8 +2776,8 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
$name_field = $query->addField('pq', 'name');
$record = $query->execute()->fetch();
- $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
- $this->assertEqual($record->$age_field, 27*3, t('Fetched age expression is correct.'));
+ $this->assertEqual($record->$name_field, 'George', 'Fetched name is correct.');
+ $this->assertEqual($record->$age_field, 27*3, 'Fetched age expression is correct.');
}
}
@@ -2758,31 +2811,31 @@ class DatabaseRegressionTestCase extends DatabaseTestCase {
))->execute();
$from_database = db_query('SELECT name FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();
- $this->assertIdentical($name, $from_database, t("The database handles UTF-8 characters cleanly."));
+ $this->assertIdentical($name, $from_database, "The database handles UTF-8 characters cleanly.");
}
/**
* Test the db_table_exists() function.
*/
function testDBTableExists() {
- $this->assertIdentical(TRUE, db_table_exists('node'), t('Returns true for existent table.'));
- $this->assertIdentical(FALSE, db_table_exists('nosuchtable'), t('Returns false for nonexistent table.'));
+ $this->assertIdentical(TRUE, db_table_exists('node'), 'Returns true for existent table.');
+ $this->assertIdentical(FALSE, db_table_exists('nosuchtable'), 'Returns false for nonexistent table.');
}
/**
* Test the db_field_exists() function.
*/
function testDBFieldExists() {
- $this->assertIdentical(TRUE, db_field_exists('node', 'nid'), t('Returns true for existent column.'));
- $this->assertIdentical(FALSE, db_field_exists('node', 'nosuchcolumn'), t('Returns false for nonexistent column.'));
+ $this->assertIdentical(TRUE, db_field_exists('node', 'nid'), 'Returns true for existent column.');
+ $this->assertIdentical(FALSE, db_field_exists('node', 'nosuchcolumn'), 'Returns false for nonexistent column.');
}
/**
* Test the db_index_exists() function.
*/
function testDBIndexExists() {
- $this->assertIdentical(TRUE, db_index_exists('node', 'node_created'), t('Returns true for existent index.'));
- $this->assertIdentical(FALSE, db_index_exists('node', 'nosuchindex'), t('Returns false for nonexistent index.'));
+ $this->assertIdentical(TRUE, db_index_exists('node', 'node_created'), 'Returns true for existent index.');
+ $this->assertIdentical(FALSE, db_index_exists('node', 'nosuchindex'), 'Returns false for nonexistent index.');
}
}
@@ -2813,10 +2866,10 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
$queries = Database::getLog('testing', 'default');
- $this->assertEqual(count($queries), 3, t('Correct number of queries recorded.'));
+ $this->assertEqual(count($queries), 3, 'Correct number of queries recorded.');
foreach ($queries as $query) {
- $this->assertEqual($query['caller']['function'], __FUNCTION__, t('Correct function in query log.'));
+ $this->assertEqual($query['caller']['function'], __FUNCTION__, 'Correct function in query log.');
}
}
@@ -2835,8 +2888,8 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
$queries1 = Database::getLog('testing1');
$queries2 = Database::getLog('testing2');
- $this->assertEqual(count($queries1), 2, t('Correct number of queries recorded for log 1.'));
- $this->assertEqual(count($queries2), 1, t('Correct number of queries recorded for log 2.'));
+ $this->assertEqual(count($queries1), 2, 'Correct number of queries recorded for log 1.');
+ $this->assertEqual(count($queries2), 1, 'Correct number of queries recorded for log 2.');
}
/**
@@ -2856,9 +2909,9 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
$queries1 = Database::getLog('testing1');
- $this->assertEqual(count($queries1), 2, t('Recorded queries from all targets.'));
- $this->assertEqual($queries1[0]['target'], 'default', t('First query used default target.'));
- $this->assertEqual($queries1[1]['target'], 'slave', t('Second query used slave target.'));
+ $this->assertEqual(count($queries1), 2, 'Recorded queries from all targets.');
+ $this->assertEqual($queries1[0]['target'], 'default', 'First query used default target.');
+ $this->assertEqual($queries1[1]['target'], 'slave', 'Second query used slave target.');
}
/**
@@ -2882,9 +2935,9 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
$queries1 = Database::getLog('testing1');
- $this->assertEqual(count($queries1), 2, t('Recorded queries from all targets.'));
- $this->assertEqual($queries1[0]['target'], 'default', t('First query used default target.'));
- $this->assertEqual($queries1[1]['target'], 'default', t('Second query used default target as fallback.'));
+ $this->assertEqual(count($queries1), 2, 'Recorded queries from all targets.');
+ $this->assertEqual($queries1[0]['target'], 'default', 'First query used default target.');
+ $this->assertEqual($queries1[1]['target'], 'default', 'Second query used default target as fallback.');
}
/**
@@ -2910,8 +2963,8 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
$queries1 = Database::getLog('testing1');
$queries2 = Database::getLog('testing1', 'test2');
- $this->assertEqual(count($queries1), 1, t('Correct number of queries recorded for first connection.'));
- $this->assertEqual(count($queries2), 1, t('Correct number of queries recorded for second connection.'));
+ $this->assertEqual(count($queries1), 1, 'Correct number of queries recorded for first connection.');
+ $this->assertEqual(count($queries2), 1, 'Correct number of queries recorded for second connection.');
}
}
@@ -2938,7 +2991,7 @@ class DatabaseSerializeQueryTestCase extends DatabaseTestCase {
// assertion.
$query = unserialize(serialize($query));
$results = $query->execute()->fetchCol();
- $this->assertEqual($results[0], 28, t('Query properly executed after unserialization.'));
+ $this->assertEqual($results[0], 28, 'Query properly executed after unserialization.');
}
}
@@ -2964,12 +3017,12 @@ class DatabaseRangeQueryTestCase extends DrupalWebTestCase {
function testRangeQuery() {
// Test if return correct number of rows.
$range_rows = db_query_range("SELECT name FROM {system} ORDER BY name", 2, 3)->fetchAll();
- $this->assertEqual(count($range_rows), 3, t('Range query work and return correct number of rows.'));
+ $this->assertEqual(count($range_rows), 3, 'Range query work and return correct number of rows.');
// Test if return target data.
$raw_rows = db_query('SELECT name FROM {system} ORDER BY name')->fetchAll();
$raw_rows = array_slice($raw_rows, 2, 3);
- $this->assertEqual($range_rows, $raw_rows, t('Range query work and return target data.'));
+ $this->assertEqual($range_rows, $raw_rows, 'Range query work and return target data.');
}
}
@@ -3003,19 +3056,19 @@ class DatabaseTemporaryQueryTestCase extends DrupalWebTestCase {
$this->drupalGet('database_test/db_query_temporary');
$data = json_decode($this->drupalGetContent());
if ($data) {
- $this->assertEqual($this->countTableRows("system"), $data->row_count, t('The temporary table contains the correct amount of rows.'));
- $this->assertFalse(db_table_exists($data->table_name), t('The temporary table is, indeed, temporary.'));
+ $this->assertEqual($this->countTableRows("system"), $data->row_count, 'The temporary table contains the correct amount of rows.');
+ $this->assertFalse(db_table_exists($data->table_name), 'The temporary table is, indeed, temporary.');
}
else {
- $this->fail(t("The creation of the temporary table failed."));
+ $this->fail("The creation of the temporary table failed.");
}
// Now try to run two db_query_temporary() in the same request.
$table_name_system = db_query_temporary('SELECT status FROM {system}', array());
$table_name_users = db_query_temporary('SELECT uid FROM {users}', array());
- $this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("system"), t('A temporary table was created successfully in this request.'));
- $this->assertEqual($this->countTableRows($table_name_users), $this->countTableRows("users"), t('A second temporary table was created successfully in this request.'));
+ $this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("system"), 'A temporary table was created successfully in this request.');
+ $this->assertEqual($this->countTableRows($table_name_users), $this->countTableRows("users"), 'A second temporary table was created successfully in this request.');
}
}
@@ -3050,7 +3103,7 @@ class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {
':a4' => ' a ',
':a5' => 'test.',
));
- $this->assertIdentical($result->fetchField(), 'This is a test.', t('Basic CONCAT works.'));
+ $this->assertIdentical($result->fetchField(), 'This is a test.', 'Basic CONCAT works.');
}
/**
@@ -3063,7 +3116,7 @@ class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {
':a3' => '.',
':age' => 25,
));
- $this->assertIdentical($result->fetchField(), 'The age of John is 25.', t('Field CONCAT works.'));
+ $this->assertIdentical($result->fetchField(), 'The age of John is 25.', 'Field CONCAT works.');
}
/**
@@ -3082,14 +3135,14 @@ class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {
->countQuery()
->execute()
->fetchField();
- $this->assertIdentical($num_matches, '2', t('Found 2 records.'));
+ $this->assertIdentical($num_matches, '2', 'Found 2 records.');
// Match only "Ring_" using a LIKE expression with no wildcards.
$num_matches = db_select('test', 't')
->condition('name', db_like('Ring_'), 'LIKE')
->countQuery()
->execute()
->fetchField();
- $this->assertIdentical($num_matches, '1', t('Found 1 record.'));
+ $this->assertIdentical($num_matches, '1', 'Found 1 record.');
}
/**
@@ -3113,14 +3166,14 @@ class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {
->countQuery()
->execute()
->fetchField();
- $this->assertIdentical($num_matches, '2', t('Found 2 records.'));
+ $this->assertIdentical($num_matches, '2', 'Found 2 records.');
// Match only the former using a LIKE expression with no wildcards.
$num_matches = db_select('test', 't')
->condition('name', db_like('abc%\_'), 'LIKE')
->countQuery()
->execute()
->fetchField();
- $this->assertIdentical($num_matches, '1', t('Found 1 record.'));
+ $this->assertIdentical($num_matches, '1', 'Found 1 record.');
}
}
@@ -3151,9 +3204,9 @@ class DatabaseCaseSensitivityTestCase extends DatabaseTestCase {
->execute();
$num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();
- $this->assertIdentical($num_records_before + 1, (int) $num_records_after, t('Record inserts correctly.'));
+ $this->assertIdentical($num_records_before + 1, (int) $num_records_after, 'Record inserts correctly.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'john'))->fetchField();
- $this->assertIdentical($saved_age, '2', t('Can retrieve after inserting.'));
+ $this->assertIdentical($saved_age, '2', 'Can retrieve after inserting.');
}
}
@@ -3196,7 +3249,7 @@ class DatabaseInvalidDataTestCase extends DatabaseTestCase {
'job' => 'Singer',
))
->execute();
- $this->fail(t('Insert succeedded when it should not have.'));
+ $this->fail('Insert succeedded when it should not have.');
}
catch (Exception $e) {
// Check if the first record was inserted.
@@ -3208,14 +3261,14 @@ class DatabaseInvalidDataTestCase extends DatabaseTestCase {
// Database engines that don't support transactions can leave partial
// inserts in place when an error occurs. This is the case for MySQL
// when running on a MyISAM table.
- $this->pass(t("The whole transaction has not been rolled-back when a duplicate key insert occurs, this is expected because the database doesn't support transactions"));
+ $this->pass("The whole transaction has not been rolled-back when a duplicate key insert occurs, this is expected because the database doesn't support transactions");
}
else {
- $this->fail(t('The whole transaction is rolled back when a duplicate key insert occurs.'));
+ $this->fail('The whole transaction is rolled back when a duplicate key insert occurs.');
}
}
else {
- $this->pass(t('The whole transaction is rolled back when a duplicate key insert occurs.'));
+ $this->pass('The whole transaction is rolled back when a duplicate key insert occurs.');
}
// Ensure the other values were not inserted.
@@ -3224,7 +3277,7 @@ class DatabaseInvalidDataTestCase extends DatabaseTestCase {
->condition('age', array(17, 75), 'IN')
->execute()->fetchObject();
- $this->assertFalse($record, t('The rest of the insert aborted as expected.'));
+ $this->assertFalse($record, 'The rest of the insert aborted as expected.');
}
}
@@ -3252,7 +3305,7 @@ class DatabaseQueryTestCase extends DatabaseTestCase {
function testArraySubstitution() {
$names = db_query('SELECT name FROM {test} WHERE age IN (:ages) ORDER BY age', array(':ages' => array(25, 26, 27)))->fetchAll();
- $this->assertEqual(count($names), 3, t('Correct number of names returned'));
+ $this->assertEqual(count($names), 3, 'Correct number of names returned');
}
}
@@ -3320,19 +3373,19 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
))
->execute();
- $this->assertTrue($connection->inTransaction(), t('In transaction before calling nested transaction.'));
+ $this->assertTrue($connection->inTransaction(), 'In transaction before calling nested transaction.');
// We're already in a transaction, but we call ->transactionInnerLayer
// to nest another transaction inside the current one.
$this->transactionInnerLayer($suffix, $rollback, $ddl_statement);
- $this->assertTrue($connection->inTransaction(), t('In transaction after calling nested transaction.'));
+ $this->assertTrue($connection->inTransaction(), 'In transaction after calling nested transaction.');
if ($rollback) {
// Roll back the transaction, if requested.
// This rollback should propagate to the last savepoint.
$txn->rollback();
- $this->assertTrue(($connection->transactionDepth() == $depth), t('Transaction has rolled back to the last savepoint after calling rollback().'));
+ $this->assertTrue(($connection->transactionDepth() == $depth), 'Transaction has rolled back to the last savepoint after calling rollback().');
}
}
@@ -3358,7 +3411,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
$txn = db_transaction();
$depth2 = $connection->transactionDepth();
- $this->assertTrue($depth < $depth2, t('Transaction depth is has increased with new transaction.'));
+ $this->assertTrue($depth < $depth2, 'Transaction depth is has increased with new transaction.');
// Insert a single row into the testing table.
db_insert('test')
@@ -3368,7 +3421,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
))
->execute();
- $this->assertTrue($connection->inTransaction(), t('In transaction inside nested transaction.'));
+ $this->assertTrue($connection->inTransaction(), 'In transaction inside nested transaction.');
if ($ddl_statement) {
$table = array(
@@ -3383,14 +3436,14 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
);
db_create_table('database_test_1', $table);
- $this->assertTrue($connection->inTransaction(), t('In transaction inside nested transaction.'));
+ $this->assertTrue($connection->inTransaction(), 'In transaction inside nested transaction.');
}
if ($rollback) {
// Roll back the transaction, if requested.
// This rollback should propagate to the last savepoint.
$txn->rollback();
- $this->assertTrue(($connection->transactionDepth() == $depth), t('Transaction has rolled back to the last savepoint after calling rollback().'));
+ $this->assertTrue(($connection->transactionDepth() == $depth), 'Transaction has rolled back to the last savepoint after calling rollback().');
}
}
@@ -3411,9 +3464,9 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// Neither of the rows we inserted in the two transaction layers
// should be present in the tables post-rollback.
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidB'))->fetchField();
- $this->assertNotIdentical($saved_age, '24', t('Cannot retrieve DavidB row after commit.'));
+ $this->assertNotIdentical($saved_age, '24', 'Cannot retrieve DavidB row after commit.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielB'))->fetchField();
- $this->assertNotIdentical($saved_age, '19', t('Cannot retrieve DanielB row after commit.'));
+ $this->assertNotIdentical($saved_age, '19', 'Cannot retrieve DanielB row after commit.');
}
catch (Exception $e) {
$this->fail($e->getMessage());
@@ -3437,9 +3490,9 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// Because our current database claims to not support transactions,
// the inserted rows should be present despite the attempt to roll back.
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidB'))->fetchField();
- $this->assertIdentical($saved_age, '24', t('DavidB not rolled back, since transactions are not supported.'));
+ $this->assertIdentical($saved_age, '24', 'DavidB not rolled back, since transactions are not supported.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielB'))->fetchField();
- $this->assertIdentical($saved_age, '19', t('DanielB not rolled back, since transactions are not supported.'));
+ $this->assertIdentical($saved_age, '19', 'DanielB not rolled back, since transactions are not supported.');
}
catch (Exception $e) {
$this->fail($e->getMessage());
@@ -3459,9 +3512,9 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// Because we committed, both of the inserted rows should be present.
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidA'))->fetchField();
- $this->assertIdentical($saved_age, '24', t('Can retrieve DavidA row after commit.'));
+ $this->assertIdentical($saved_age, '24', 'Can retrieve DavidA row after commit.');
$saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielA'))->fetchField();
- $this->assertIdentical($saved_age, '19', t('Can retrieve DanielA row after commit.'));
+ $this->assertIdentical($saved_age, '19', 'Can retrieve DanielA row after commit.');
}
catch (Exception $e) {
$this->fail($e->getMessage());
@@ -3553,7 +3606,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// $this->fail(t('Rolling back a transaction containing DDL should fail.'));
}
catch (DatabaseTransactionNoActiveException $e) {
- $this->pass(t('Rolling back a transaction containing DDL should fail.'));
+ $this->pass('Rolling back a transaction containing DDL should fail.');
}
$this->assertRowPresent('row');
}
@@ -3606,7 +3659,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
*/
function assertRowPresent($name, $message = NULL) {
if (!isset($message)) {
- $message = t('Row %name is present.', array('%name' => $name));
+ $message = format_string('Row %name is present.', array('%name' => $name));
}
$present = (boolean) db_query('SELECT 1 FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();
return $this->assertTrue($present, $message);
@@ -3622,7 +3675,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
*/
function assertRowAbsent($name, $message = NULL) {
if (!isset($message)) {
- $message = t('Row %name is absent.', array('%name' => $name));
+ $message = format_string('Row %name is absent.', array('%name' => $name));
}
$present = (boolean) db_query('SELECT 1 FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();
return $this->assertFalse($present, $message);
@@ -3646,10 +3699,10 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
$this->insertRow('inner');
// Pop the inner transaction.
unset($transaction2);
- $this->assertTrue($database->inTransaction(), t('Still in a transaction after popping the inner transaction'));
+ $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the inner transaction');
// Pop the outer transaction.
unset($transaction);
- $this->assertFalse($database->inTransaction(), t('Transaction closed after popping the outer transaction'));
+ $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the outer transaction');
$this->assertRowPresent('outer');
$this->assertRowPresent('inner');
@@ -3662,10 +3715,10 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// Pop the outer transaction, nothing should happen.
unset($transaction);
$this->insertRow('inner-after-outer-commit');
- $this->assertTrue($database->inTransaction(), t('Still in a transaction after popping the outer transaction'));
+ $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');
// Pop the inner transaction, the whole transaction should commit.
unset($transaction2);
- $this->assertFalse($database->inTransaction(), t('Transaction closed after popping the inner transaction'));
+ $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');
$this->assertRowPresent('outer');
$this->assertRowPresent('inner');
$this->assertRowPresent('inner-after-outer-commit');
@@ -3679,11 +3732,11 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
// Now rollback the inner transaction.
$transaction2->rollback();
unset($transaction2);
- $this->assertTrue($database->inTransaction(), t('Still in a transaction after popping the outer transaction'));
+ $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');
// Pop the outer transaction, it should commit.
$this->insertRow('outer-after-inner-rollback');
unset($transaction);
- $this->assertFalse($database->inTransaction(), t('Transaction closed after popping the inner transaction'));
+ $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');
$this->assertRowPresent('outer');
$this->assertRowAbsent('inner');
$this->assertRowPresent('outer-after-inner-rollback');
@@ -3696,11 +3749,11 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
$this->insertRow('inner');
// Pop the outer transaction, nothing should happen.
unset($transaction);
- $this->assertTrue($database->inTransaction(), t('Still in a transaction after popping the outer transaction'));
+ $this->assertTrue($database->inTransaction(), 'Still in a transaction after popping the outer transaction');
// Now rollback the inner transaction, it should rollback.
$transaction2->rollback();
unset($transaction2);
- $this->assertFalse($database->inTransaction(), t('Transaction closed after popping the inner transaction'));
+ $this->assertFalse($database->inTransaction(), 'Transaction closed after popping the inner transaction');
$this->assertRowPresent('outer');
$this->assertRowAbsent('inner');
@@ -3718,23 +3771,23 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
try {
$transaction->rollback();
unset($transaction);
- $this->fail(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
+ $this->fail('Rolling back the outer transaction while the inner transaction is active resulted in an exception.');
}
catch (DatabaseTransactionOutOfOrderException $e) {
- $this->pass(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
+ $this->pass('Rolling back the outer transaction while the inner transaction is active resulted in an exception.');
}
- $this->assertFalse($database->inTransaction(), t('No more in a transaction after rolling back the outer transaction'));
+ $this->assertFalse($database->inTransaction(), 'No more in a transaction after rolling back the outer transaction');
// Try to commit one inner transaction.
unset($transaction3);
- $this->pass(t('Trying to commit an inner transaction resulted in an exception.'));
+ $this->pass('Trying to commit an inner transaction resulted in an exception.');
// Try to rollback one inner transaction.
try {
$transaction->rollback();
unset($transaction2);
- $this->fail(t('Trying to commit an inner transaction resulted in an exception.'));
+ $this->fail('Trying to commit an inner transaction resulted in an exception.');
}
catch (DatabaseTransactionNoActiveException $e) {
- $this->pass(t('Trying to commit an inner transaction resulted in an exception.'));
+ $this->pass('Trying to commit an inner transaction resulted in an exception.');
}
$this->assertRowAbsent('outer');
$this->assertRowAbsent('inner');
@@ -3764,9 +3817,9 @@ class DatabaseNextIdCase extends DrupalWebTestCase {
// We can test for exact increase in here because we know there is no
// other process operating on these tables -- normally we could only
// expect $second > $first.
- $this->assertEqual($first + 1, $second, t('The second call from a sequence provides a number increased by one.'));
+ $this->assertEqual($first + 1, $second, 'The second call from a sequence provides a number increased by one.');
$result = db_next_id(1000);
- $this->assertEqual($result, 1001, t('Sequence provides a larger number than the existing ID.'));
+ $this->assertEqual($result, 1001, 'Sequence provides a larger number than the existing ID.');
}
}
@@ -3788,8 +3841,8 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
function testEmpty() {
$result = new DatabaseStatementEmpty();
- $this->assertTrue($result instanceof DatabaseStatementInterface, t('Class implements expected interface'));
- $this->assertNull($result->fetchObject(), t('Null result returned.'));
+ $this->assertTrue($result instanceof DatabaseStatementInterface, 'Class implements expected interface');
+ $this->assertNull($result->fetchObject(), 'Null result returned.');
}
/**
@@ -3799,11 +3852,11 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
$result = new DatabaseStatementEmpty();
foreach ($result as $record) {
- $this->fail(t('Iterating empty result set should not iterate.'));
+ $this->fail('Iterating empty result set should not iterate.');
return;
}
- $this->pass(t('Iterating empty result set skipped iteration.'));
+ $this->pass('Iterating empty result set skipped iteration.');
}
/**
@@ -3812,6 +3865,225 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
function testEmptyFetchAll() {
$result = new DatabaseStatementEmpty();
- $this->assertEqual($result->fetchAll(), array(), t('Empty array returned from empty result set.'));
+ $this->assertEqual($result->fetchAll(), array(), 'Empty array returned from empty result set.');
+ }
+}
+
+/**
+ * Tests management of database connections.
+ */
+class ConnectionUnitTest extends DrupalUnitTestCase {
+
+ protected $key;
+ protected $target;
+
+ protected $monitor;
+ protected $originalCount;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Connection unit tests',
+ 'description' => 'Tests management of database connections.',
+ 'group' => 'Database',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+
+ $this->key = 'default';
+ $this->originalTarget = 'default';
+ $this->target = 'DatabaseConnectionUnitTest';
+
+ // Determine whether the database driver is MySQL. If it is not, the test
+ // methods will not be executed.
+ // @todo Make this test driver-agnostic, or find a proper way to skip it.
+ // @see http://drupal.org/node/1273478
+ $connection_info = Database::getConnectionInfo('default');
+ $this->skipTest = (bool) $connection_info['default']['driver'] != 'mysql';
+ if ($this->skipTest) {
+ // Insert an assertion to prevent Simpletest from interpreting the test
+ // as failure.
+ $this->pass('This test is only compatible with MySQL.');
+ }
+
+ // Create an additional connection to monitor the connections being opened
+ // and closed in this test.
+ // @see TestBase::changeDatabasePrefix()
+ $connection_info = Database::getConnectionInfo('default');
+ Database::addConnectionInfo('default', 'monitor', $connection_info['default']);
+ global $databases;
+ $databases['default']['monitor'] = $connection_info['default'];
+ $this->monitor = Database::getConnection('monitor');
+ }
+
+ /**
+ * Adds a new database connection info to Database.
+ */
+ protected function addConnection() {
+ // Add a new target to the connection, by cloning the current connection.
+ $connection_info = Database::getConnectionInfo($this->key);
+ Database::addConnectionInfo($this->key, $this->target, $connection_info[$this->originalTarget]);
+
+ // Verify that the new target exists.
+ $info = Database::getConnectionInfo($this->key);
+ // Note: Custom assertion message to not expose database credentials.
+ $this->assertIdentical($info[$this->target], $connection_info[$this->key], 'New connection info found.');
+ }
+
+ /**
+ * Returns the connection ID of the current test connection.
+ *
+ * @return integer
+ */
+ protected function getConnectionID() {
+ return (int) Database::getConnection($this->target, $this->key)->query('SELECT CONNECTION_ID()')->fetchField();
}
+
+ /**
+ * Asserts that a connection ID exists.
+ *
+ * @param integer $id
+ * The connection ID to verify.
+ */
+ protected function assertConnection($id) {
+ $list = $this->monitor->query('SHOW PROCESSLIST')->fetchAllKeyed(0, 0);
+ return $this->assertTrue(isset($list[$id]), format_string('Connection ID @id found.', array('@id' => $id)));
+ }
+
+ /**
+ * Asserts that a connection ID does not exist.
+ *
+ * @param integer $id
+ * The connection ID to verify.
+ */
+ protected function assertNoConnection($id) {
+ $list = $this->monitor->query('SHOW PROCESSLIST')->fetchAllKeyed(0, 0);
+ return $this->assertFalse(isset($list[$id]), format_string('Connection ID @id not found.', array('@id' => $id)));
+ }
+
+ /**
+ * Tests Database::closeConnection() without query.
+ *
+ * @todo getConnectionID() executes a query.
+ */
+ function testOpenClose() {
+ if ($this->skipTest) {
+ return;
+ }
+ // Add and open a new connection.
+ $this->addConnection();
+ $id = $this->getConnectionID();
+ Database::getConnection($this->target, $this->key);
+
+ // Verify that there is a new connection.
+ $this->assertConnection($id);
+
+ // Close the connection.
+ Database::closeConnection($this->target, $this->key);
+ // Wait 20ms to give the database engine sufficient time to react.
+ usleep(20000);
+
+ // Verify that we are back to the original connection count.
+ $this->assertNoConnection($id);
+ }
+
+ /**
+ * Tests Database::closeConnection() with a query.
+ */
+ function testOpenQueryClose() {
+ if ($this->skipTest) {
+ return;
+ }
+ // Add and open a new connection.
+ $this->addConnection();
+ $id = $this->getConnectionID();
+ Database::getConnection($this->target, $this->key);
+
+ // Verify that there is a new connection.
+ $this->assertConnection($id);
+
+ // Execute a query.
+ Database::getConnection($this->target, $this->key)->query('SHOW TABLES');
+
+ // Close the connection.
+ Database::closeConnection($this->target, $this->key);
+ // Wait 20ms to give the database engine sufficient time to react.
+ usleep(20000);
+
+ // Verify that we are back to the original connection count.
+ $this->assertNoConnection($id);
+ }
+
+ /**
+ * Tests Database::closeConnection() with a query and custom prefetch method.
+ */
+ function testOpenQueryPrefetchClose() {
+ if ($this->skipTest) {
+ return;
+ }
+ // Add and open a new connection.
+ $this->addConnection();
+ $id = $this->getConnectionID();
+ Database::getConnection($this->target, $this->key);
+
+ // Verify that there is a new connection.
+ $this->assertConnection($id);
+
+ // Execute a query.
+ Database::getConnection($this->target, $this->key)->query('SHOW TABLES')->fetchCol();
+
+ // Close the connection.
+ Database::closeConnection($this->target, $this->key);
+ // Wait 20ms to give the database engine sufficient time to react.
+ usleep(20000);
+
+ // Verify that we are back to the original connection count.
+ $this->assertNoConnection($id);
+ }
+
+ /**
+ * Tests Database::closeConnection() with a select query.
+ */
+ function testOpenSelectQueryClose() {
+ if ($this->skipTest) {
+ return;
+ }
+ // Add and open a new connection.
+ $this->addConnection();
+ $id = $this->getConnectionID();
+ Database::getConnection($this->target, $this->key);
+
+ // Verify that there is a new connection.
+ $this->assertConnection($id);
+
+ // Create a table.
+ $name = 'foo';
+ Database::getConnection($this->target, $this->key)->schema()->createTable($name, array(
+ 'fields' => array(
+ 'name' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ ),
+ ),
+ ));
+
+ // Execute a query.
+ Database::getConnection($this->target, $this->key)->select('foo', 'f')
+ ->fields('f', array('name'))
+ ->execute()
+ ->fetchAll();
+
+ // Drop the table.
+ Database::getConnection($this->target, $this->key)->schema()->dropTable($name);
+
+ // Close the connection.
+ Database::closeConnection($this->target, $this->key);
+ // Wait 20ms to give the database engine sufficient time to react.
+ usleep(20000);
+
+ // Verify that we are back to the original connection count.
+ $this->assertNoConnection($id);
+ }
+
}
diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test
index 3df31ba5f..ebaa0c034 100644
--- a/modules/simpletest/tests/file.test
+++ b/modules/simpletest/tests/file.test
@@ -2579,6 +2579,15 @@ class FileNameMungingTest extends FileTestCase {
}
/**
+ * Tests munging with a null byte in the filename.
+ */
+ function testMungeNullByte() {
+ $prefix = $this->randomName();
+ $filename = $prefix . '.' . $this->bad_extension . "\0.txt";
+ $this->assertEqual(file_munge_filename($filename, ''), $prefix . '.' . $this->bad_extension . '_.txt', 'A filename with a null byte is correctly munged to remove the null byte.');
+ }
+
+ /**
* If the allow_insecure_uploads variable evaluates to true, the file should
* come out untouched, no matter how evil the filename.
*/
diff --git a/modules/simpletest/tests/upgrade/upgrade.test b/modules/simpletest/tests/upgrade/upgrade.test
index 9df8ec779..cc849aa79 100644
--- a/modules/simpletest/tests/upgrade/upgrade.test
+++ b/modules/simpletest/tests/upgrade/upgrade.test
@@ -566,6 +566,20 @@ class BasicMinimalUpdatePath extends UpdatePathTestCase {
// Confirm that no {menu_links} entry exists for user/autocomplete.
$result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(':user_autocomplete' => 'user/autocomplete'))->fetchField();
$this->assertFalse($result, t('No {menu_links} entry exists for user/autocomplete'));
+
+ // Confirm that a date format that just differs in the case can be added.
+ $admin_date_format = 'j M y';
+ $edit = array('date_format' => $admin_date_format);
+ $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+
+ // Add a new date format which just differs in the case.
+ $admin_date_format_uppercase = 'j M Y';
+ $edit = array('date_format' => $admin_date_format_uppercase);
+ $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+ $this->assertText(t('Custom date format added.'));
+
+ // Verify that the unique key on {date_formats}.format still exists.
+ $this->assertTrue(db_index_exists('date_formats', 'formats'), 'Unique key on {date_formats} exists');
}
}
diff --git a/modules/system/language.api.php b/modules/system/language.api.php
index 671479309..d868b6fef 100644
--- a/modules/system/language.api.php
+++ b/modules/system/language.api.php
@@ -62,16 +62,22 @@ function hook_language_switch_links_alter(array &$links, $type, $path) {
}
/**
- * Allow modules to define their own language types.
+ * Define language types.
*
* @return
- * An array of language type definitions. Each language type has an identifier
- * key. The language type definition is an associative array that may contain
- * the following key-value pairs:
- * - "name": The human-readable language type identifier.
- * - "description": A description of the language type.
- * - "fixed": An array of language provider identifiers. Defining this key
- * makes the language type non-configurable.
+ * An associative array of language type definitions. The keys are the
+ * identifiers, which are also used as names for global variables representing
+ * the types in the bootstrap phase. The values are associative arrays that
+ * may contain the following elements:
+ * - name: The human-readable language type identifier.
+ * - description: A description of the language type.
+ * - fixed: A fixed array of language negotiation provider identifiers to use
+ * to initialize this language. Defining this key makes the language type
+ * non-configurable, so it will always use the specified providers in the
+ * given priority order. Omit to make the language type configurable.
+ *
+ * @see hook_language_types_info_alter()
+ * @ingroup language_negotiation
*/
function hook_language_types_info() {
return array(
@@ -90,6 +96,9 @@ function hook_language_types_info() {
*
* @param $language_types
* Array of language type definitions.
+ *
+ * @see hook_language_types_info()
+ * @ingroup language_negotiation
*/
function hook_language_types_info_alter(array &$language_types) {
if (isset($language_types['custom_language_type'])) {
@@ -98,31 +107,35 @@ function hook_language_types_info_alter(array &$language_types) {
}
/**
- * Allow modules to define their own language providers.
+ * Define language negotiation providers.
*
* @return
- * An array of language provider definitions. Each language provider has an
- * identifier key. The language provider definition is an associative array
- * that may contain the following key-value pairs:
- * - "types": An array of allowed language types. If a language provider does
- * not specify which language types it should be used with, it will be
- * available for all the configurable language types.
- * - "callbacks": An array of functions that will be called to perform various
- * tasks. Possible key-value pairs are:
- * - "language": Required. The callback that will determine the language
- * value.
- * - "switcher": The callback that will determine the language switch links
- * associated to the current language provider.
- * - "url_rewrite": The callback that will provide URL rewriting.
- * - "file": A file that will be included before the callback is invoked; this
- * allows callback functions to be in separate files.
- * - "weight": The default weight the language provider has.
- * - "name": A human-readable identifier.
- * - "description": A description of the language provider.
- * - "config": An internal path pointing to the language provider
- * configuration page.
- * - "cache": The value Drupal's page cache should be set to for the current
- * language provider to be invoked.
+ * An associative array of language negotiation provider definitions. The keys
+ * are provider identifiers, and the values are associative arrays definining
+ * each provider, with the following elements:
+ * - types: An array of allowed language types. If a language negotiation
+ * provider does not specify which language types it should be used with, it
+ * will be available for all the configurable language types.
+ * - callbacks: An associative array of functions that will be called to
+ * perform various tasks. Possible elements are:
+ * - negotiation: (required) Name of the callback function that determines
+ * the language value.
+ * - language_switch: (optional) Name of the callback function that
+ * determines links for a language switcher block associated with this
+ * provider. See language_switcher_url() for an example.
+ * - url_rewrite: (optional) Name of the callback function that provides URL
+ * rewriting, if needed by this provider.
+ * - file: The file where callback functions are defined (this file will be
+ * included before the callbacks are invoked).
+ * - weight: The default weight of the provider.
+ * - name: The translated human-readable name for the provider.
+ * - description: A translated longer description of the provider.
+ * - config: An internal path pointing to the provider's configuration page.
+ * - cache: The value Drupal's page cache should be set to for the current
+ * provider to be invoked.
+ *
+ * @see hook_language_negotiation_info_alter()
+ * @ingroup language_negotiation
*/
function hook_language_negotiation_info() {
return array(
@@ -135,18 +148,21 @@ function hook_language_negotiation_info() {
'file' => drupal_get_path('module', 'custom') . '/custom.module',
'weight' => -4,
'types' => array('custom_language_type'),
- 'name' => t('Custom language provider'),
- 'description' => t('This is a custom language provider.'),
+ 'name' => t('Custom language negotiation provider'),
+ 'description' => t('This is a custom language negotiation provider.'),
'cache' => 0,
),
);
}
/**
- * Perform alterations on language providers.
+ * Perform alterations on language negoiation providers.
*
* @param $language_providers
- * Array of language provider definitions.
+ * Array of language negotiation provider definitions.
+ *
+ * @see hook_language_negotiation_info()
+ * @ingroup language_negotiation
*/
function hook_language_negotiation_info_alter(array &$language_providers) {
if (isset($language_providers['custom_language_provider'])) {
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 061898c85..05543be6a 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -1594,6 +1594,7 @@ function system_site_information_settings_validate($form, &$form_state) {
* @ingroup forms
*/
function system_cron_settings() {
+ global $base_url;
$form['description'] = array(
'#markup' => '<p>' . t('Cron takes care of running periodic tasks like checking for updates and indexing content for search.') . '</p>',
);
@@ -1606,6 +1607,11 @@ function system_cron_settings() {
$form['status'] = array(
'#markup' => $status,
);
+
+ $form['cron_url'] = array(
+ '#markup' => '<p>' . t('To run cron from outside the site, go to <a href="!cron">!cron</a>', array('!cron' => url($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal')))))) . '</p>',
+ );
+
$form['cron'] = array(
'#type' => 'fieldset',
);
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index adef26141..195bc8354 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -154,7 +154,10 @@ function hook_hook_info_alter(&$hooks) {
* the name of the bundle object.
* - bundles: An array describing all bundles for this object type. Keys are
* bundles machine names, as found in the objects' 'bundle' property
- * (defined in the 'entity keys' entry above). Elements:
+ * (defined in the 'entity keys' entry above). This entry can be omitted if
+ * this entity type exposes a single bundle (all entities have the same
+ * collection of fields). The name of this single bundle will be the same as
+ * the entity type. Elements:
* - label: The human-readable name of the bundle.
* - uri callback: Same as the 'uri callback' key documented above for the
* entity type, but for the bundle only. When determining the URI of an
@@ -1201,6 +1204,10 @@ function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
* same weight are ordered alphabetically.
* - "menu_name": Optional. Set this to a custom menu if you don't want your
* item to be placed in Navigation.
+ * - "expanded": Optional. If set to TRUE, and if a menu link is provided for
+ * this menu item (as a result of other properties), then the menu link is
+ * always expanded, equivalent to its 'always expanded' checkbox being set
+ * in the UI.
* - "context": (optional) Defines the context a tab may appear in. By
* default, all tabs are only displayed as local tasks when being rendered
* in a page context. All tabs that should be accessible as contextual links
@@ -1412,7 +1419,7 @@ function hook_menu_link_delete($link) {
* - #link: An associative array containing:
* - title: The localized title of the link.
* - href: The system path to link to.
- * - localized_options: An array of options to pass to url().
+ * - localized_options: An array of options to pass to l().
* - #active: Whether the link should be marked as 'active'.
*
* @param $data
@@ -1929,8 +1936,9 @@ function hook_image_toolkits() {
* The drupal_mail() id of the message. Look at module source code or
* drupal_mail() for possible id values.
* - 'to':
- * The address or addresses the message will be sent to. The
- * formatting of this string must comply with RFC 2822.
+ * The address or addresses the message will be sent to. The formatting of
+ * this string will be validated with the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
* - 'from':
* The address the message will be marked as being from, which is
* either a custom address or the site-wide default email address.
@@ -2100,7 +2108,9 @@ function hook_permission() {
* specify how a particular render array is to be rendered as HTML (this is
* usually the case if the theme function is assigned to the render array's
* #theme property), or they return the HTML that should be returned by an
- * invocation of theme().
+ * invocation of theme(). See
+ * @link http://drupal.org/node/933976 Using the theme layer Drupal 7.x @endlink
+ * for more information on how to implement theme hooks.
*
* The following parameters are all optional.
*
@@ -2196,6 +2206,8 @@ function hook_permission() {
* 'module', 'theme_engine', or 'theme'.
* - theme path: (automatically derived) The directory path of the theme or
* module, so that it doesn't need to be looked up.
+ *
+ * @see hook_theme_registry_alter()
*/
function hook_theme($existing, $type, $theme, $path) {
return array(
@@ -2290,7 +2302,8 @@ function hook_theme_registry_alter(&$theme_registry) {
* @return
* The machine-readable name of the theme that should be used for the current
* page request. The value returned from this function will only have an
- * effect if it corresponds to a currently-active theme on the site.
+ * effect if it corresponds to a currently-active theme on the site. Do not
+ * return a value if you do not wish to set a custom theme.
*/
function hook_custom_theme() {
// Allow the user to request a particular theme via a query parameter.
@@ -2476,8 +2489,9 @@ function hook_watchdog(array $log_entry) {
* An array to be filled in. Elements in this array include:
* - id: An ID to identify the mail sent. Look at module source code
* or drupal_mail() for possible id values.
- * - to: The address or addresses the message will be sent to. The
- * formatting of this string must comply with RFC 2822.
+ * - to: The address or addresses the message will be sent to. The formatting
+ * of this string will be validated with the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
* - subject: Subject of the e-mail to be sent. This must not contain any
* newline characters, or the mail may not be sent properly. drupal_mail()
* sets this to an empty string when the hook is invoked.
@@ -3092,44 +3106,48 @@ function hook_schema() {
'description' => 'The primary identifier for a node.',
'type' => 'serial',
'unsigned' => TRUE,
- 'not null' => TRUE),
+ 'not null' => TRUE,
+ ),
'vid' => array(
'description' => 'The current {node_revision}.vid version identifier.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
- 'default' => 0),
+ 'default' => 0,
+ ),
'type' => array(
'description' => 'The {node_type} of this node.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
- 'default' => ''),
+ 'default' => '',
+ ),
'title' => array(
'description' => 'The title of this node, always treated as non-markup plain text.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
- 'default' => ''),
+ 'default' => '',
),
+ ),
'indexes' => array(
'node_changed' => array('changed'),
'node_created' => array('created'),
- ),
+ ),
'unique keys' => array(
'nid_vid' => array('nid', 'vid'),
- 'vid' => array('vid')
- ),
+ 'vid' => array('vid'),
+ ),
'foreign keys' => array(
'node_revision' => array(
'table' => 'node_revision',
'columns' => array('vid' => 'vid'),
- ),
+ ),
'node_author' => array(
'table' => 'users',
- 'columns' => array('uid' => 'uid')
- ),
- ),
+ 'columns' => array('uid' => 'uid'),
+ ),
+ ),
'primary key' => array('nid'),
);
return $schema;
@@ -3236,8 +3254,7 @@ function hook_query_TAG_alter(QueryAlterableInterface $query) {
* a hook_update_N() is added to the module, this function needs to be updated
* to reflect the current version of the database schema.
*
- * See the Schema API documentation at
- * @link http://drupal.org/node/146843 http://drupal.org/node/146843 @endlink
+ * See the @link http://drupal.org/node/146843 Schema API documentation @endlink
* for details on hook_schema and how database tables are defined.
*
* Note that since this function is called from a full bootstrap, all functions
@@ -3621,6 +3638,9 @@ function hook_registry_files_alter(&$files, $modules) {
* inspect later. It is important to remove any temporary variables using
* variable_del() before your last task has completed and control is handed
* back to the installer.
+ *
+ * @param array $install_state
+ * An array of information about the current installation state.
*
* @return
* A keyed array of tasks the profile will perform during the final stage of
@@ -3679,7 +3699,7 @@ function hook_registry_files_alter(&$files, $modules) {
* @see install_state_defaults()
* @see batch_set()
*/
-function hook_install_tasks() {
+function hook_install_tasks(&$install_state) {
// Here, we define a variable to allow tasks to indicate that a particular,
// processor-intensive batch process needs to be triggered later on in the
// installation.
diff --git a/modules/system/system.install b/modules/system/system.install
index 7b667678e..59bb2f14a 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -744,6 +744,7 @@ function system_schema() {
'type' => 'varchar',
'length' => 100,
'not null' => TRUE,
+ 'binary' => TRUE,
),
'type' => array(
'description' => 'The date format type, e.g. medium.',
@@ -3032,6 +3033,7 @@ function system_update_7073() {
'default' => '',
'binary' => TRUE,
));
+ db_drop_unique_key('file_managed', 'uri');
db_change_field('file_managed', 'uri', 'uri', array(
'description' => 'The URI to access the file (either local or remote).',
'type' => 'varchar',
@@ -3040,6 +3042,7 @@ function system_update_7073() {
'default' => '',
'binary' => TRUE,
));
+ db_add_unique_key('file_managed', 'uri', array('uri'));
}
/**
@@ -3086,6 +3089,21 @@ function system_update_7077() {
));
}
+
+/**
+ * Add binary to {date_formats}.format.
+ */
+function system_update_7078() {
+ db_drop_unique_key('date_formats', 'formats');
+ db_change_field('date_formats', 'format', 'format', array(
+ 'description' => 'The date format string.',
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ 'binary' => TRUE,
+ ), array('unique keys' => array('formats' => array('format', 'type'))));
+}
+
/**
* @} End of "defgroup updates-7.x-extra".
* The next series of updates should start at 8000.
diff --git a/modules/system/system.updater.inc b/modules/system/system.updater.inc
index 0df1ad955..a14d788b1 100644
--- a/modules/system/system.updater.inc
+++ b/modules/system/system.updater.inc
@@ -73,8 +73,12 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
return array();
}
+ /**
+ * Returns a list of post install actions.
+ */
public function postInstallTasks() {
return array(
+ l(t('Install another module'), 'admin/modules/install'),
l(t('Enable newly added modules'), 'admin/modules'),
l(t('Administration pages'), 'admin'),
);
diff --git a/modules/update/update.module b/modules/update/update.module
index 85c0968d5..d5728be3e 100644
--- a/modules/update/update.module
+++ b/modules/update/update.module
@@ -139,10 +139,10 @@ function update_init() {
if (!empty($verbose)) {
if (isset($status[$type]['severity'])) {
if ($status[$type]['severity'] == REQUIREMENT_ERROR) {
- drupal_set_message($status[$type]['description'], 'error');
+ drupal_set_message($status[$type]['description'], 'error', FALSE);
}
elseif ($status[$type]['severity'] == REQUIREMENT_WARNING) {
- drupal_set_message($status[$type]['description'], 'warning');
+ drupal_set_message($status[$type]['description'], 'warning', FALSE);
}
}
}
@@ -152,7 +152,7 @@ function update_init() {
if (isset($status[$type])
&& isset($status[$type]['reason'])
&& $status[$type]['reason'] === UPDATE_NOT_SECURE) {
- drupal_set_message($status[$type]['description'], 'error');
+ drupal_set_message($status[$type]['description'], 'error', FALSE);
}
}
}
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index 1cc2c4a24..932c20593 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -5,6 +5,21 @@
* Admin page callback file for the user module.
*/
+/**
+ * Page callback: Generates the appropriate user administration form.
+ *
+ * This function generates the user registration, multiple user cancellation,
+ * or filtered user list admin form, depending on the argument and the POST
+ * form values.
+ *
+ * @param string $callback_arg
+ * (optional) Indicates which form to build. Defaults to '', which will
+ * trigger the user filter form. If the POST value 'op' is present, this
+ * function uses that value as the callback argument.
+ *
+ * @return string
+ * A renderable form array for the respective request.
+ */
function user_admin($callback_arg = '') {
$op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
diff --git a/modules/user/user.module b/modules/user/user.module
index 622fe4d25..c1c7ec218 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -1517,15 +1517,33 @@ function theme_user_list($variables) {
return theme('item_list', array('items' => $items, 'title' => $title));
}
+/**
+ * Determines if the current user is anonymous.
+ *
+ * @return bool
+ * TRUE if the user is anonymous, FALSE if the user is authenticated.
+ */
function user_is_anonymous() {
// Menu administrators can see items for anonymous when administering.
return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']);
}
+/**
+ * Determines if the current user is logged in.
+ *
+ * @return bool
+ * TRUE if the user is logged in, FALSE if the user is anonymous.
+ */
function user_is_logged_in() {
return (bool) $GLOBALS['user']->uid;
}
+/**
+ * Determines if the current user has access to the user registration page.
+ *
+ * @return bool
+ * TRUE if the user is not already logged in and can register for an account.
+ */
function user_register_access() {
return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
}
@@ -3353,7 +3371,7 @@ function user_filters() {
$options = array();
foreach (module_implements('permission') as $module) {
$function = $module . '_permission';
- if ($permissions = $function('permission')) {
+ if ($permissions = $function()) {
asort($permissions);
foreach ($permissions as $permission => $description) {
$options[t('@module module', array('@module' => $module))][$permission] = t($permission);
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 2b207f224..40f552e1d 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -147,7 +147,7 @@
* 'authmap' => 'shared_',
* ),
* @endcode
- * You can also use a reference to a schema/database as a prefix. This maybe
+ * You can also use a reference to a schema/database as a prefix. This may be
* useful if your Drupal installation exists in a schema that is not the default
* or you want to access several databases from the same code base at the same
* time.
@@ -435,7 +435,7 @@ ini_set('session.cookie_lifetime', 2000000);
/**
* String overrides:
*
- * To override specific strings on your site with or without enabling locale
+ * To override specific strings on your site with or without enabling the Locale
* module, add an entry to this list. This functionality allows you to change
* a small number of your site's default English language interface strings.
*
diff --git a/update.php b/update.php
index 0c2aaf850..f9be98edf 100644
--- a/update.php
+++ b/update.php
@@ -1,7 +1,7 @@
<?php
/**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
@@ -27,6 +27,9 @@ define('DRUPAL_ROOT', getcwd());
*/
define('MAINTENANCE_MODE', 'update');
+/**
+ * Renders a form with a list of available database updates.
+ */
function update_selection_page() {
drupal_set_title('Drupal database update');
$elements = drupal_get_form('update_script_selection_form');
@@ -37,6 +40,9 @@ function update_selection_page() {
return $output;
}
+/**
+ * Form constructor for the list of available database module updates.
+ */
function update_script_selection_form($form, &$form_state) {
$count = 0;
$incompatible_count = 0;
@@ -141,6 +147,9 @@ function update_script_selection_form($form, &$form_state) {
return $form;
}
+/**
+ * Provides links to the homepage and administration pages.
+ */
function update_helpful_links() {
// NOTE: we can't use l() here because the URL would point to
// 'update.php?q=admin'.
@@ -151,6 +160,9 @@ function update_helpful_links() {
return $links;
}
+/**
+ * Displays results of the update script with any accompanying errors.
+ */
function update_results_page() {
drupal_set_title('Drupal database update');
$links = update_helpful_links();
@@ -231,6 +243,15 @@ function update_results_page() {
return $output;
}
+/**
+ * Provides an overview of the Drupal database update.
+ *
+ * This page provides cautionary suggestions that should happen before
+ * proceeding with the update to ensure data integrity.
+ *
+ * @return
+ * Rendered HTML form.
+ */
function update_info_page() {
// Change query-strings on css/js files to enforce reload for all users.
_drupal_flush_css_js();
@@ -256,6 +277,12 @@ function update_info_page() {
return $output;
}
+/**
+ * Renders a 403 access denied page for update.php.
+ *
+ * @return
+ * Rendered HTML warning with 403 status.
+ */
function update_access_denied_page() {
drupal_add_http_header('Status', '403 Forbidden');
watchdog('access denied', 'update.php', NULL, WATCHDOG_WARNING);
@@ -294,7 +321,7 @@ function update_access_allowed() {
}
/**
- * Add the update task list to the current page.
+ * Adds the update task list to the current page.
*/
function update_task_list($active = NULL) {
// Default list of tasks.
@@ -310,8 +337,7 @@ function update_task_list($active = NULL) {
}
/**
- * Returns (and optionally stores) extra requirements that only apply during
- * particular parts of the update.php process.
+ * Returns and stores extra requirements that apply during the update process.
*/
function update_extra_requirements($requirements = NULL) {
static $extra_requirements = array();
@@ -322,7 +348,7 @@ function update_extra_requirements($requirements = NULL) {
}
/**
- * Check update requirements and report any errors or (optionally) warnings.
+ * Checks update requirements and reports errors and (optionally) warnings.
*
* @param $skip_warnings
* (optional) If set to TRUE, requirement warnings will be ignored, and a