From 509f03673e938f389c5cbd3ae55680b4d910e6c3 Mon Sep 17 00:00:00 2001 From: Logan Smyth Date: Thu, 15 Sep 2011 15:09:04 -0400 Subject: [PATCH] Issue #361597: API tests to load and save a source and a translation string set --- modules/locale/locale.module | 251 ++++++++++++++++++++++++++++++++++++++++++ modules/locale/locale.test | 90 +++++++++++++++ 2 files changed, 341 insertions(+), 0 deletions(-) diff --git a/modules/locale/locale.module b/modules/locale/locale.module index 4a15ed9..b54ee4a 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -970,6 +970,257 @@ function locale_library_alter(&$libraries, $module) { } } +// -------------------------------------------------------------------------------- +// Locale CRUD API + +/** + * @defgroup locale-api Locale CRUD API + * @{ + * API for managing Locale sources and targets + */ + +/** + * Load a source string record. + * + * @param $lid + * A source lid. + * @return + * Source string. + */ +function locale_source_load($lid) { + $records = locale_source_load_multiple(array('lid' => $lid)); + return !empty($records) ? current($records) : FALSE; +} + +/** + * Get source for a string, given key/value conditions. + * + * @param $conditions + * An array of source lids, or an array of key => value pairs. + * @return + * Array of source strings (objects) that meet the condtions, indexed by lid. + */ +function locale_source_load_multiple(array $conditions) { + // Allow list of lids as arguments. + if (is_numeric(key($conditions))) { + $conditions = array('lid' => $conditions); + } + + // Build basic query on locales_source. + $query = db_select('locales_source', 's'); + $query->fields('s'); + foreach ($conditions as $field => $value) { + $query->condition($field, $value, is_array($value) ? 'IN' : '='); + } + return $query->execute()->fetchAllAssoc('lid'); +} + +/** + * Save / update a source string record. + * + * @param $source + * Object representing a source string. + * 'lid' property used for updates. + */ +function locale_source_save(&$source) { + // Ensure we're working with an object. + $source = (object)$source; + if (!empty($source->lid)) { + return drupal_write_record('locales_source', $source, 'lid'); + } + else { + return drupal_write_record('locales_source', $source); + } +} + +/** + * Delete a specific source record from the database. + * + * @param $lid + * The lid of source string to delete. + */ +function locale_source_delete($lid, $delete_translations = TRUE) { + locale_source_delete_multiple(array('lid' => $lid), $delete_translations); +} + + +/** + * Delete one or more locale source records from the database. Optionally, also + * delete associated target strings. + * + * @param $conditions + * An array of lids, or an array field-value pairs to match. + * Values may be arrays, in which case matching will use the 'IN' operator. + * @param $delete_translations + * Boolean, whether to delete all associated target strings. + */ +function locale_source_delete_multiple(array $conditions, $delete_translations = TRUE) { + // Accept a single lid or an array of lids. + if (is_numeric(key($conditions))) { + $conditions = array('lid' => $conditions); + } + // If requested and deleting by ID, remove all associated targets. + if ($delete_translations) { + locale_translation_delete_multiple($conditions); + } + // Remove the sources. + $query = db_delete('locales_source'); + foreach ($conditions as $field => $value) { + $query->condition($field, $value, is_array($value) ? 'IN' : '='); + } + $query->execute(); +} + +/** + * Load a translation string record. + * + * @param $lid + * The source id of the translation. + * @param $langcode + * The language code of the translation. + * @param $plural + * The plural of the translation. + * @param $get_source + * Whether to get source data only in case there's no translation. + * + * @return + * The first translation object matching the given conditions. + */ +function locale_translation_load($lid, $langcode, $plural = 0, $get_source = FALSE) { + $records = locale_translation_load_multiple(array('lid' => $lid, 'language' => $langcode, 'plural' => $plural), $get_source); + return !empty($records) ? current($records) : FALSE; +} + +/** + * Load one or more translations. + * + * @param $conditions + * An array of source lids or an array of key => value pairs. + * @param $get_source + * Whether to get source data only in case there's no translation. + * @return + * The full translation object. + */ +function locale_translation_load_multiple(array $conditions, $get_source = FALSE) { + // Get target fields to check which table each condition is in. + $target_schema = drupal_get_schema('locales_target'); + $target_field_info = $target_schema['fields']; + + // Check for an array of lids. + if (is_numeric(key($conditions))) { + $conditions = array('lid' => $conditions); + } + + $query = db_select('locales_source', 's'); + // If we want source data too, add fields and LEFT JOIN, otherwise no fields + // and INNER JOIN. + if ($get_source) { + $query->fields('s'); + $join = 'leftJoin'; + + // exclude lid because that is ALSO in locales_source + unset($target_field_info['lid']); + } + else { + $join = 'join'; + } + $target_fields = array_keys($target_field_info); + + // Join localse_target table, and add all fields except 'lid'. + $query->$join('locales_target', 't', 's.lid = t.lid'); + + // Not using '*' because then target lid overrides source lid. + $query->fields('t', $target_fields); + + foreach ($conditions as $field => $value) { + $table_alias = in_array($field, $target_fields) ? 't' : 's'; + $query->condition($table_alias . '.' . $field, $value, is_array($value) ? 'IN' : '='); + } + + $translations = array(); + foreach ($query->execute() as $row) { + // Make uniqe identifier by appending primary-key items. + $translations[$row->lid . '-' . $row->language . '-' . $row->plural] = $row; + } + return $translations; +} + +/** + * Save a translation. + * + * @param $translation + * Object representing a string translation. + * @return + * SAVED_NEW or SAVED_UPDATED. + */ +function locale_translation_save(&$translation) { + $translation = (object)$translation; + + // Check again for existing source and translation. + $existing = locale_translation_load($translation->lid, $translation->language, $translation->plural); + if (!empty($existing)) { + return drupal_write_record('locales_target', $translation, array('lid', 'language', 'plural')); + } + else { + return drupal_write_record('locales_target', $translation); + } +} + +/** + * Delete one locale target record from database. + * + * @param $translation + * Object representing a string translation. + */ +function locale_translation_delete($lid, $langcode, $plural = 0) { + locale_translation_delete_multiple(array( + 'lid' => $lid, + 'language' => $langcode, + 'plural' => $plural, + )); +} + +/** + * Delete one or more locale target records from the database. + * + * @param $conditions + * An array of lids, or an array field-value pairs to match. + * Values may be arrays, in which case matching will use the 'IN' operator. + */ +function locale_translation_delete_multiple(array $conditions) { + $target_schema = drupal_get_schema('locales_target'); + $target_fields = array_keys($target_schema['fields']); + + // Accept an array of lids. + if (is_numeric(key($conditions))) { + $conditions = array('lid' => $conditions); + } + + // Build the query which may have conditions for the source table and the + // target table. + $query = db_delete('locales_target'); + $subquery = db_select('locales_source', 's'); + foreach ($conditions as $field => $value) { + if (in_array($field, $target_fields)) { + $query->condition($field, $value, is_array($value) ? 'IN' : '='); + } + else { + $subquery->condition($field, $value, is_array($value) ? 'IN' : '='); + } + } + // If we have conditions for the target table we need to build a IN subquery. + if ($subquery->conditions()) { + $subquery->addField('s', 'lid'); + $query->condition('lid', $subquery, 'IN'); + } + + $query->execute(); +} + +/** + * @} End of "locale-api" + */ + // --------------------------------------------------------------------------------- // Language switcher block diff --git a/modules/locale/locale.test b/modules/locale/locale.test index 90e313d..5607fcb 100644 --- a/modules/locale/locale.test +++ b/modules/locale/locale.test @@ -591,6 +591,96 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase { } /** + * Tests for locale CRUD API functions. + */ +class LocaleApiTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => t('Locale API functions'), + 'description' => t('Tests the performance of locale CRUD APIs.'), + 'group' => t('Locale'), + ); + } + + function setUp() { + parent::setUp('locale', 'locale_test'); + include_once DRUPAL_ROOT . '/includes/locale.inc'; + // Create and login user. + $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer languages', 'translate interface', 'access administration pages')); + $this->drupalLogin($admin_user); + } + + /** + * Test locale source APIs. + */ + function testApis() { + // Insert an initial source string. + $source = (object)array( + 'location' => 'test', + 'source' => 'new', + 'context' => 'context', + 'version' => 'none', + ); + $insert_result = locale_source_save($source); + $this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when new locale source string saved')); + + // Update the initial source string after changing a property. + $source->source = 'changed'; + $update_result = locale_source_save($source); + $this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when new locale source string updated')); + + // Load the source string. + $id_loaded_source = locale_source_load($source->lid); + $this->assertTrue(isset($id_loaded_source->lid) && $id_loaded_source->lid == $source->lid, t('Source loaded by ID')); + $this->assertTrue(isset($id_loaded_source->source) && $id_loaded_source->source == 'changed', t('Source updated')); + + // Save a second source string. + $lids = array($source->lid); + unset($source->lid); + locale_source_save($source); + $lids[] = $source->lid; + // Load multiple strings. + $multiple = locale_source_load_multiple($lids); + $this->assertTrue(count($multiple) == 2, t('Multiple locale source strings loaded by ID')); + + // Add language. + $edit = array( + 'langcode' => 'fr', + ); + $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); + + // Create a locale target string. + $target = (object)array( + 'lid' => current($lids), + 'translation' => 'analyse', + 'language' => 'fr', + 'plural' => 0, + ); + $insert_result = locale_translation_save($target); + $this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when new locale target string saved')); + + // Update the initial target string. + $target->translation = 'tester'; + $update_result = locale_translation_save($target); + $this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when new locale target string updated')); + + // Load the target string. + $id_loaded_target = locale_translation_load($target->lid, $target->language); + $this->assertTrue(isset($id_loaded_target->lid) && $id_loaded_target->lid == $target->lid, t('Target loaded by ID')); + $this->assertTrue(isset($id_loaded_target->translation) && $id_loaded_target->translation == 'tester', t('Target updated')); + + // Delete source and target strings. + locale_source_delete($lids); + $sources = locale_source_load_multiple($lids); + $this->assertTrue(empty($sources), t('Locale source strings deleted')); + + $translations = locale_translation_load_multiple($lids); + $this->assertTrue(empty($translations), t('Locale target strings deleted')); + } +} + + +/** * Functional tests for the import of translation files. */ class LocaleImportFunctionalTest extends DrupalWebTestCase { -- 1.7.5.3