diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/field/modules/field_sql_storage/field_sql_storage.module | 53 | ||||
-rw-r--r-- | modules/field/modules/field_sql_storage/field_sql_storage.test | 145 | ||||
-rw-r--r-- | modules/field/tests/field_test.module | 11 | ||||
-rw-r--r-- | modules/file/file.field.inc | 1 | ||||
-rw-r--r-- | modules/node/node.api.php | 80 | ||||
-rw-r--r-- | modules/node/node.module | 5 | ||||
-rw-r--r-- | modules/simpletest/drupal_web_test_case.php | 6 | ||||
-rw-r--r-- | modules/simpletest/tests/file.test | 8 | ||||
-rw-r--r-- | modules/system/system.api.php | 2 | ||||
-rw-r--r-- | modules/update/update.compare.inc | 7 |
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]; |