summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/field/modules/field_sql_storage/field_sql_storage.module53
-rw-r--r--modules/field/modules/field_sql_storage/field_sql_storage.test145
-rw-r--r--modules/field/tests/field_test.module11
-rw-r--r--modules/file/file.field.inc1
-rw-r--r--modules/node/node.api.php80
-rw-r--r--modules/node/node.module5
-rw-r--r--modules/simpletest/drupal_web_test_case.php6
-rw-r--r--modules/simpletest/tests/file.test8
-rw-r--r--modules/system/system.api.php2
-rw-r--r--modules/update/update.compare.inc7
10 files changed, 273 insertions, 45 deletions
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 93f207710..7ab4ee5c9 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -65,6 +65,49 @@ function _field_sql_storage_revision_tablename($field) {
}
/**
+ * Generates a table alias for a field data table.
+ *
+ * The table alias is unique for each unique combination of field name
+ * (represented by $tablename), delta_group and language_group.
+ *
+ * @param $tablename
+ * The name of the data table for this field.
+ * @param $field_key
+ * The numeric key of this field in this query.
+ * @param $query
+ * The EntityFieldQuery that is executed.
+ *
+ * @return
+ * A string containing the generated table alias.
+ */
+function _field_sql_storage_tablealias($tablename, $field_key, EntityFieldQuery $query) {
+ // No conditions present: use a unique alias.
+ if (empty($query->fieldConditions[$field_key])) {
+ return $tablename . $field_key;
+ }
+
+ // Find the delta and language condition values and append them to the alias.
+ $condition = $query->fieldConditions[$field_key];
+ $alias = $tablename;
+ $has_group_conditions = FALSE;
+
+ foreach (array('delta', 'language') as $column) {
+ if (isset($condition[$column . '_group'])) {
+ $alias .= '_' . $column . '_' . $condition[$column . '_group'];
+ $has_group_conditions = TRUE;
+ }
+ }
+
+ // Return the alias when it has delta/language group conditions.
+ if ($has_group_conditions) {
+ return $alias;
+ }
+
+ // Return a unique alias in other cases.
+ return $tablename . $field_key;
+}
+
+/**
* Generate a column name for a field data table.
*
* @param $name
@@ -504,17 +547,21 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
$id_key = 'revision_id';
}
$table_aliases = array();
+ $query_tables = NULL;
// Add tables for the fields used.
foreach ($query->fields as $key => $field) {
$tablename = $tablename_function($field);
- // Every field needs a new table.
- $table_alias = $tablename . $key;
+ $table_alias = _field_sql_storage_tablealias($tablename, $key, $query);
$table_aliases[$key] = $table_alias;
if ($key) {
- $select_query->join($tablename, $table_alias, "$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key");
+ if (!isset($query_tables[$table_alias])) {
+ $select_query->join($tablename, $table_alias, "$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key");
+ }
}
else {
$select_query = db_select($tablename, $table_alias);
+ // Store a reference to the list of joined tables.
+ $query_tables =& $select_query->getTables();
// Allow queries internal to the Field API to opt out of the access
// check, for situations where the query's results should not depend on
// the access grants for the current user.
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.test b/modules/field/modules/field_sql_storage/field_sql_storage.test
index 12c54ba29..072739cbb 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.test
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.test
@@ -438,4 +438,149 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
$this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema');
$this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema');
}
+
+ /**
+ * Test handling multiple conditions on one column of a field.
+ *
+ * Tests both the result and the complexity of the query.
+ */
+ function testFieldSqlStorageMultipleConditionsSameColumn() {
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$this->field_name}[LANGUAGE_NONE][0] = array('value' => 1);
+ field_test_entity_save($entity);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$this->field_name}[LANGUAGE_NONE][0] = array('value' => 2);
+ field_test_entity_save($entity);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$this->field_name}[LANGUAGE_NONE][0] = array('value' => 3);
+ field_test_entity_save($entity);
+
+ $query = new EntityFieldQuery();
+ // This tag causes field_test_query_store_global_test_query_alter() to be
+ // invoked so that the query can be tested.
+ $query->addTag('store_global_test_query');
+ $query->entityCondition('entity_type', 'test_entity');
+ $query->entityCondition('bundle', 'test_bundle');
+ $query->fieldCondition($this->field_name, 'value', 1, '<>', 0, LANGUAGE_NONE);
+ $query->fieldCondition($this->field_name, 'value', 2, '<>', 0, LANGUAGE_NONE);
+ $result = field_sql_storage_field_storage_query($query);
+
+ // Test the results.
+ $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array('@count' => count($result))));
+
+ // Test the complexity of the query.
+ $query = $GLOBALS['test_query'];
+ $this->assertNotNull($query, 'Precondition: the query should be available');
+ $tables = $query->getTables();
+ $this->assertEqual(1, count($tables), 'The query contains just one table.');
+
+ // Clean up.
+ unset($GLOBALS['test_query']);
+ }
+
+ /**
+ * Test handling multiple conditions on multiple columns of one field.
+ *
+ * Tests both the result and the complexity of the query.
+ */
+ function testFieldSqlStorageMultipleConditionsDifferentColumns() {
+ // Create the multi-column shape field
+ $field_name = strtolower($this->randomName());
+ $field = array('field_name' => $field_name, 'type' => 'shape', 'cardinality' => 4);
+ $field = field_create_field($field);
+ $instance = array(
+ 'field_name' => $field_name,
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle'
+ );
+ $instance = field_create_instance($instance);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$field_name}[LANGUAGE_NONE][0] = array('shape' => 'A', 'color' => 'X');
+ field_test_entity_save($entity);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$field_name}[LANGUAGE_NONE][0] = array('shape' => 'B', 'color' => 'X');
+ field_test_entity_save($entity);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$field_name}[LANGUAGE_NONE][0] = array('shape' => 'A', 'color' => 'Y');
+ field_test_entity_save($entity);
+
+ $query = new EntityFieldQuery();
+ // This tag causes field_test_query_store_global_test_query_alter() to be
+ // invoked so that the query can be tested.
+ $query->addTag('store_global_test_query');
+ $query->entityCondition('entity_type', 'test_entity');
+ $query->entityCondition('bundle', 'test_bundle');
+ $query->fieldCondition($field_name, 'shape', 'B', '=', 'something', LANGUAGE_NONE);
+ $query->fieldCondition($field_name, 'color', 'X', '=', 'something', LANGUAGE_NONE);
+ $result = field_sql_storage_field_storage_query($query);
+
+ // Test the results.
+ $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array('@count' => count($result))));
+
+ // Test the complexity of the query.
+ $query = $GLOBALS['test_query'];
+ $this->assertNotNull($query, 'Precondition: the query should be available');
+ $tables = $query->getTables();
+ $this->assertEqual(1, count($tables), 'The query contains just one table.');
+
+ // Clean up.
+ unset($GLOBALS['test_query']);
+ }
+
+ /**
+ * Test handling multiple conditions on multiple columns of one field for multiple languages.
+ *
+ * Tests both the result and the complexity of the query.
+ */
+ function testFieldSqlStorageMultipleConditionsDifferentColumnsMultipleLanguages() {
+ field_test_entity_info_translatable('test_entity', TRUE);
+
+ // Create the multi-column shape field
+ $field_name = strtolower($this->randomName());
+ $field = array('field_name' => $field_name, 'type' => 'shape', 'cardinality' => 4, 'translatable' => TRUE);
+ $field = field_create_field($field);
+ $instance = array(
+ 'field_name' => $field_name,
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ 'settings' => array(
+ // Prevent warning from field_test_field_load().
+ 'test_hook_field_load' => FALSE,
+ ),
+ );
+ $instance = field_create_instance($instance);
+
+ $entity = field_test_create_stub_entity(NULL, NULL);
+ $entity->{$field_name}[LANGUAGE_NONE][0] = array('shape' => 'A', 'color' => 'X');
+ $entity->{$field_name}['en'][0] = array('shape' => 'B', 'color' => 'Y');
+ field_test_entity_save($entity);
+ $entity = field_test_entity_test_load($entity->ftid);
+
+ $query = new EntityFieldQuery();
+ // This tag causes field_test_query_store_global_test_query_alter() to be
+ // invoked so that the query can be tested.
+ $query->addTag('store_global_test_query');
+ $query->entityCondition('entity_type', 'test_entity');
+ $query->entityCondition('bundle', 'test_bundle');
+ $query->fieldCondition($field_name, 'color', 'X', '=', NULL, LANGUAGE_NONE);
+ $query->fieldCondition($field_name, 'shape', 'B', '=', NULL, 'en');
+ $result = field_sql_storage_field_storage_query($query);
+
+ // Test the results.
+ $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array('@count' => count($result))));
+
+ // Test the complexity of the query.
+ $query = $GLOBALS['test_query'];
+ $this->assertNotNull($query, 'Precondition: the query should be available');
+ $tables = $query->getTables();
+ $this->assertEqual(2, count($tables), 'The query contains two tables.');
+
+ // Clean up.
+ unset($GLOBALS['test_query']);
+ }
}
diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module
index dc2023a74..9daa2c305 100644
--- a/modules/field/tests/field_test.module
+++ b/modules/field/tests/field_test.module
@@ -267,3 +267,14 @@ function field_test_query_efq_table_prefixing_test_alter(&$query) {
// exception if the EFQ does not properly prefix the base table.
$query->join('test_entity','te2','%alias.ftid = test_entity.ftid');
}
+
+/**
+ * Implements hook_query_TAG_alter() for tag 'store_global_test_query'.
+ */
+function field_test_query_store_global_test_query_alter($query) {
+ // Save the query in a global variable so that it can be examined by tests.
+ // This can be used by any test which needs to check a query, but see
+ // FieldSqlStorageTestCase::testFieldSqlStorageMultipleConditionsSameColumn()
+ // for an example.
+ $GLOBALS['test_query'] = $query;
+}
diff --git a/modules/file/file.field.inc b/modules/file/file.field.inc
index 59b547a77..b26d7e457 100644
--- a/modules/file/file.field.inc
+++ b/modules/file/file.field.inc
@@ -92,6 +92,7 @@ function file_field_instance_settings_form($field, $instance) {
'#description' => t('Separate extensions with a space or comma and do not include the leading dot.'),
'#element_validate' => array('_file_generic_settings_extensions'),
'#weight' => 1,
+ '#maxlength' => 256,
// By making this field required, we prevent a potential security issue
// that would allow files of any type to be uploaded.
'#required' => TRUE,
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index 950267614..a83dee943 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -17,11 +17,14 @@
* During node operations (create, update, view, delete, etc.), there are
* several sets of hooks that get invoked to allow modules to modify the base
* node operation:
- * - Node-type-specific hooks: These hooks are only invoked on the primary
- * module, using the "base" return component of hook_node_info() as the
- * 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().
+ * - Node-type-specific hooks: When defining a node type, hook_node_info()
+ * returns a 'base' component. Node-type-specific hooks are named
+ * base_hookname() instead of mymodule_hookname() (in a module called
+ * 'mymodule' for example). Only the node type's corresponding implementation
+ * is invoked. For example, poll_node_info() in poll.module defines the base
+ * for the 'poll' node type as 'poll'. So when a poll node is created,
+ * hook_insert() is invoked on poll_insert() only.
+ * Hooks that are node-type-specific are noted below.
* - 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
@@ -195,7 +198,7 @@ function hook_node_grants($account, $op) {
if (user_access('access private content', $account)) {
$grants['example'] = array(1);
}
- $grants['example_owner'] = array($account->uid);
+ $grants['example_author'] = array($account->uid);
return $grants;
}
@@ -885,11 +888,10 @@ function hook_node_view_alter(&$build) {
* name as the key. Each sub-array has up to 10 attributes. Possible
* attributes:
* - 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.
+ * - base: (required) The base name for implementations of node-type-specific
+ * hooks that respond to this node type. Base is usually the name of the
+ * module or 'node_content', but not always. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
* - description: (required) A brief description of the node type.
* - help: (optional) Help information shown to the user when creating a node
* of this type.
@@ -1030,8 +1032,11 @@ function hook_node_type_delete($info) {
/**
* Respond to node deletion.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_delete() to respond to all node deletions).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_delete() to respond to node deletion of all node types.
*
* This hook is invoked from node_delete_multiple() before hook_node_delete()
* is invoked and before field_attach_delete() is called.
@@ -1059,8 +1064,11 @@ function hook_delete($node) {
/**
* Act on a node object about to be shown on the add/edit form.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_prepare() to act on all node preparations).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_prepare() to respond to node preparation of all node types.
*
* This hook is invoked from node_object_prepare() before the general
* hook_node_prepare() is invoked.
@@ -1089,6 +1097,13 @@ function hook_prepare($node) {
/**
* Display a node editing form.
*
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_form_BASE_FORM_ID_alter(), with base form ID 'node_form', to alter
+ * node forms for all node types.
+ *
* This hook, implemented by node modules, is called to retrieve the form
* that is displayed to create or edit a node. This form is displayed at path
* node/add/[node type] or node/[node ID]/edit.
@@ -1144,8 +1159,11 @@ function hook_form($node, &$form_state) {
/**
* Respond to creation of a new node.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_insert() to act on all node insertions).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_insert() to respond to node insertion of all node types.
*
* This hook is invoked from node_save() after the node is inserted into the
* node table in the database, before field_attach_insert() is called, and
@@ -1168,8 +1186,11 @@ function hook_insert($node) {
/**
* Act on nodes being loaded from the database.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_load() to respond to all node loads).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_load() to respond to node load of all node types.
*
* This hook is invoked during node loading, which is handled by entity_load(),
* via classes NodeController and DrupalDefaultEntityController. After the node
@@ -1202,8 +1223,11 @@ function hook_load($nodes) {
/**
* Respond to updates to a node.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_update() to act on all node updates).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_update() to respond to node update of all node types.
*
* This hook is invoked from node_save() after the node is updated in the
* node table in the database, before field_attach_update() is called, and
@@ -1224,8 +1248,11 @@ function hook_update($node) {
/**
* Perform node validation before a node is created or updated.
*
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_validate() to act on all node validations).
+ * This is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_validate() to respond to node validation of all node types.
*
* This hook is invoked from node_validate(), after a user has finished
* editing the node and is previewing or submitting it. It is invoked at the end
@@ -1258,8 +1285,11 @@ function hook_validate($node, $form, &$form_state) {
/**
* Display a node.
*
- * 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 is a node-type-specific hook, which is invoked only for the node type
+ * being affected. See
+ * @link node_api_hooks Node API hooks @endlink for more information.
+ *
+ * Use hook_node_view() to respond to node view of all node types.
*
* 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
diff --git a/modules/node/node.module b/modules/node/node.module
index 5a4e01947..acca83ecb 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -210,7 +210,7 @@ function node_entity_info() {
'custom settings' => FALSE,
),
'search_result' => array(
- 'label' => t('Search result'),
+ 'label' => t('Search result highlighting input'),
'custom settings' => FALSE,
),
);
@@ -3629,7 +3629,8 @@ function node_access_rebuild($batch_mode = FALSE) {
// Try to allocate enough time to rebuild node grants
drupal_set_time_limit(240);
- $nids = db_query("SELECT nid FROM {node}")->fetchCol();
+ // Rebuild newest nodes first so that recent content becomes available quickly.
+ $nids = db_query("SELECT nid FROM {node} ORDER BY nid DESC")->fetchCol();
foreach ($nids as $nid) {
$node = node_load($nid, NULL, TRUE);
// To preserve database integrity, only acquire grants if the node
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 8022bf325..a46e171dd 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -435,10 +435,10 @@ abstract class DrupalTestCase {
}
/**
- * Logs verbose message in a text file.
+ * Logs a verbose message in a text file.
*
- * The a link to the vebose message will be placed in the test results via
- * as a passing assertion with the text '[verbose message]'.
+ * The link to the verbose message will be placed in the test results as a
+ * passing assertion with the text '[verbose message]'.
*
* @param $message
* The verbose message to be stored.
diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test
index 20dd27376..0e66775a9 100644
--- a/modules/simpletest/tests/file.test
+++ b/modules/simpletest/tests/file.test
@@ -484,14 +484,6 @@ class FileValidatorTest extends DrupalWebTestCase {
$original_user = $user;
drupal_save_session(FALSE);
- // Run these test as uid = 1.
- $user = user_load(1);
-
- $file = new stdClass();
- $file->filesize = 999999;
- $errors = file_validate_size($file, 1, 1);
- $this->assertEqual(count($errors), 0, 'No size limits enforced on uid=1.', 'File');
-
// Run these tests as a regular user.
$user = $this->drupalCreateUser();
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index 22175b130..b60f50deb 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -247,7 +247,7 @@ function hook_entity_info() {
'custom settings' => FALSE,
),
'search_result' => array(
- 'label' => t('Search result'),
+ 'label' => t('Search result highlighting input'),
'custom settings' => FALSE,
),
);
diff --git a/modules/update/update.compare.inc b/modules/update/update.compare.inc
index 6e0c5feee..072a0daaa 100644
--- a/modules/update/update.compare.inc
+++ b/modules/update/update.compare.inc
@@ -417,14 +417,15 @@ function update_calculate_project_data($available) {
* version (e.g., 5.x-1.5-beta1, 5.x-1.5-beta2, and 5.x-1.5). Development
* snapshots for a given major version are always listed last.
*
- * @param $project
- * An array containing information about a specific project.
+ * @param $unused
+ * Input is not being used, but remains in function for API compatibility
+ * reasons.
* @param $project_data
* An array containing information about a specific project.
* @param $available
* Data about available project releases of a specific project.
*/
-function update_calculate_project_update_status($project, &$project_data, $available) {
+function update_calculate_project_update_status($unused, &$project_data, $available) {
foreach (array('title', 'link') as $attribute) {
if (!isset($project_data[$attribute]) && isset($available[$attribute])) {
$project_data[$attribute] = $available[$attribute];