diff --git a/metatag.install b/metatag.install index 6881f17..b9bfd14 100644 --- a/metatag.install +++ b/metatag.install @@ -234,11 +234,177 @@ function metatag_update_7003() { } /** - * Update all records in the metatag table and assign each the correct language - * value, will also resolve problems created during the release of beta3. This - * might take a while, depending on how much data needs to be converted. + * Replaced by updates 7009, 7010, 7011, 7012 and 7013. */ -function metatag_update_7004(&$sandbox) { +function metatag_update_7004() { + // Do nothing. +} + +/** + * Removing wrong metatag watchdog entries that break the admin/reports/dblog + * page. + */ +function metatag_update_7005() { + db_delete('watchdog') + ->condition('type', 'metatag') + ->condition('variables', serialize('info')) + ->execute(); +} + +/** + * Remove metatag records that were added by old versions of the module for + * entities that don't actually support meta tags. A more complete version of + * this will be added later on after it's (hopefully) guaranteed that all + * modules have updated to the correct API usage. + */ +function metatag_update_7006() { + $types = array( + // Core. + 'comment', + 'menu_link', + 'taxonomy_vocabulary', + // Some contrib entities. + 'mailchimp_list', + 'profile2', + 'profile2_type', + 'redirect', + 'rules_config', + 'wysiwyg_profile', + ); + foreach ($types as $type) { + $num_deleted = db_delete('metatag') + ->condition('entity_type', $type) + ->execute(); + if ($num_deleted > 0) { + drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $type))); + } + } +} + +/** + * Remove metatag records for objects that have been deleted; older versions of + * Metatag may have failed to purge these. + */ +function metatag_update_7007() { + $result = db_query("DELETE m + FROM {metatag} m + LEFT OUTER JOIN {node} n + ON m.entity_id=n.nid + WHERE m.entity_type='node' + AND n.nid IS NULL"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $result->rowCount()))); + } + + $result = db_query("DELETE m + FROM {metatag} m + LEFT OUTER JOIN {users} u + ON m.entity_id=u.uid + WHERE m.entity_type='user' + AND u.uid IS NULL"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $result->rowCount()))); + } + + $result = db_query("DELETE m + FROM {metatag} m + LEFT OUTER JOIN {taxonomy_term_data} t + ON m.entity_id=t.tid + WHERE m.entity_type='taxonomy_term' + AND t.tid IS NULL"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $result->rowCount()))); + } +} + +/** + * Remove metatag any empty records that may be hanging around from old + * releases. + */ +function metatag_update_7008() { + $result = db_query("DELETE FROM {metatag} WHERE data IS NULL or data = '' OR data = 'a:0:{}'"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $result->rowCount()))); + } +} + +/** + * Fix metatags for taxonomy terms. + */ +function metatag_update_7009() { + // Remove duplicates. + _metatag_remove_dupes('taxonomy_term'); + + // Taxonomy entities don't support a 'language' option, so reset them to + // LANGUAGE_NONE. + $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='taxonomy_term'", array(':language' => LANGUAGE_NONE)); + if ($result->rowCount() > 0) { + drupal_set_message(t('Fixed language values for @count taxonomy terms.', array('@count' => $result->rowCount()))); + } +} + +/** + * Fix metatags for users. + */ +function metatag_update_7010() { + // Remove duplicates. + _metatag_remove_dupes('user'); + + // Update User values. + $result = db_query("UPDATE {metatag} AS m INNER JOIN {users} u ON m.entity_id=u.uid SET m.language = u.language WHERE m.entity_type='user' AND u.language!=''"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Fixed language values for @count users that had a language setting.', array('@count' => $result->rowCount()))); + } + $result = db_query("UPDATE {metatag} AS m INNER JOIN {users} u ON m.entity_id=u.uid SET m.language = :language WHERE m.entity_type='user' AND u.language=''", array(':language' => LANGUAGE_NONE)); + if ($result->rowCount() > 0) { + drupal_set_message(t('Fixed language values for @count users that didn\'t have a language setting.', array('@count' => $result->rowCount()))); + } +} + +/** + * Fix metatags for nodes. + */ +function metatag_update_7011() { + // Remove duplicates. + _metatag_remove_dupes('node'); + + // Update Node values. + $result = db_query("UPDATE {metatag} AS m INNER JOIN {node} n ON m.entity_id=n.nid AND m.entity_type='node' SET m.language = n.language"); + if ($result->rowCount() > 0) { + drupal_set_message(t('Fixed language values for @count nodes.', array('@count' => $result->rowCount()))); + } +} + +/** + * Fix metatags for nodes. + */ +function metatag_update_7012() { + $records = db_select('metatag', 'm') + ->fields('m', array('entity_type')) + ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN') + ->orderBy('m.entity_type', 'ASC') + ->orderBy('m.entity_id', 'ASC') + ->distinct() + ->execute(); + + $entity_types = array(); + foreach ($records as $record { + $entity_types[] = $record->entity_type; + // Remove duplicates. + _metatag_remove_dupes($record->entity_type); + } + + if (empty($entity_types)) { + drupal_set_message(t('There were no other records to fix.')); + } +} + +/** + * Fix the metatag language value for all entity records that don't already + * have a language fixed above; this should mainly cover custom entity types. + * It might take a while, depending on how much data needs to be converted. + */ +function metatag_update_7013(&$sandbox) { // Use the sandbox at your convenience to store the information needed // to track progression between successive calls to the function. if (!isset($sandbox['progress'])) { @@ -249,9 +415,10 @@ function metatag_update_7004(&$sandbox) { // way to do this, so we're going to cache all record keys and manually // step through them. $records = db_select('metatag', 'm') - ->fields('m', array('entity_type', 'entity_id', 'language')) - ->orderBy('entity_type', 'ASC') - ->orderBy('entity_id', 'ASC') + ->fields('m', array('entity_type', 'entity_id')) + ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN') + ->orderBy('m.entity_type', 'ASC') + ->orderBy('m.entity_id', 'ASC') ->execute(); $sandbox['records'] = array(); foreach ($records as $record) { @@ -263,8 +430,11 @@ function metatag_update_7004(&$sandbox) { // A place to store messages during the run. $sandbox['messages'] = array(); - // An initial record of the number of records to be upgraded. - watchdog('metatag', 'Update 7004: !count records to upgrade.', array('!count' => $sandbox['max']), WATCHDOG_INFO); + // An initial record of the number of records to be updated. + watchdog('metatag', 'Update 7013: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO); + if (drupal_is_cli()) { + drupal_set_message(t('Update 7013: !count records to update.', array('!count' => $sandbox['max']))); + } // Last record processed. $sandbox['current_record'] = -1; @@ -272,16 +442,19 @@ function metatag_update_7004(&$sandbox) { // If there's no data, don't bother with the extra work. if (empty($sandbox['max'])) { - return t('No records needed to be updated.'); + if (drupal_is_cli()) { + drupal_set_message(t('Update 7013: No records need updating.')); + } + return t('No records need updating.'); } // Proceed as normal. else { - // Process records by groups of 50 (arbitrary value). + // Process records by groups of 10 (arbitrary value). // When a group is processed, the batch update engine determines // whether it should continue processing in the same request or provide // progress feedback to the user and wait for the next request. - $limit = 50; + $limit = 10; // The for loop will run as normal when ran via update.php, but when ran // via Drush it'll just run 'til it's finished. @@ -291,7 +464,7 @@ function metatag_update_7004(&$sandbox) { } // Set default values. - for ($x = 0; $x < $limit; $x += $increment) { + for ($ctr = 0; $ctr < $limit; $ctr += $increment) { $sandbox['current_record']++; if (empty($sandbox['records'][$sandbox['current_record']])) { break; @@ -300,7 +473,7 @@ function metatag_update_7004(&$sandbox) { // Shortcuts for later. $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type; $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id; - $language = $sandbox['records'][$sandbox['current_record']]->language; + $language = ''; // Load the entity. $entities = entity_load($entity_type, array($entity_id)); @@ -310,53 +483,23 @@ function metatag_update_7004(&$sandbox) { // Make sure that the entity has a language set and that it isn't the // same as the meta tag record's language. if (!empty($entity)) { - // If the record has multiple values already, i.e. someone saved a - // new record because they thought the records were missing. - try { - // If there's a (non-empty) language value, use it. - if (!empty($entity->language)) { - // The language values are different. - if ($entity->language != $language) { - // Update the record with the entity's language value. - db_update('metatag') - ->fields(array('language' => $entity->language)) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->condition('language', $language) - ->execute(); - } - // The language values are the same. - else { - // Do nothing. - } - } - // There's no language value. - else { - // Assign the global 'no language' value. - db_update('metatag') - ->fields(array('language' => LANGUAGE_NONE)) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->condition('language', $language) - ->execute(); - } + // If there's a (non-empty) language value, use it. + if (function_exists('entity_language')) { + $new_language = entity_language($entity_type, $entity); } - catch (Exception $e) { - // Delete the newer record. - db_delete('metatag') - ->condition('language', $entity->language) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->execute(); - // Update the old one again. - db_update('metatag') - ->fields(array('language' => $entity->language)) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->condition('language', $language) - ->execute(); - $sandbox['messages'][] = t('The duplicate record for :type record #:id has been removed, leaving the older record in place.', array(':type' => $entity_type, ':id' => $entity_id)); + elseif (!empty($entity->language)) { + $new_language = $entity->language; } + if (empty($new_language)) { + $new_language = LANGUAGE_NONE; + } + // Update the 'language' value. + db_update('metatag') + ->fields(array('language' => $new_language)) + ->condition('entity_type', $entity_type) + ->condition('entity_id', $entity_id) + ->condition('language', $language) + ->execute(); } } @@ -366,7 +509,7 @@ function metatag_update_7004(&$sandbox) { // A per-iterationl message, only record if not running via Drush. if (!drupal_is_cli()) { - watchdog('metatag', 'Update 7004: !count records were updated.', array('!count' => $x), WATCHDOG_INFO); + watchdog('metatag', 'Update 7013: !count records were updated.', array('!count' => $ctr), WATCHDOG_INFO); } // Set the "finished" status, to tell batch engine whether this function @@ -379,7 +522,10 @@ function metatag_update_7004(&$sandbox) { cache_clear_all('*', 'cache_metatag', TRUE); // A final log of the number of records that were converted. - watchdog('metatag', 'Update 7004: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO); + watchdog('metatag', 'Update 7013: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO); + if (drupal_is_cli()) { + drupal_set_message(t('Update 7013: !count records were updated.', array('!count' => $sandbox['progress']))); + } // hook_update_N() may optionally return a string which will be displayed // to the user. @@ -389,89 +535,138 @@ function metatag_update_7004(&$sandbox) { } /** - * Removing wrong metatag watchdog entries that break the admin/reports/dblog - * page. + * Remove duplicate records for a given content type. + * + * @param $entity_type + * The name of an entity type to check for. */ -function metatag_update_7005() { - db_delete('watchdog') - ->condition('type', 'metatag') - ->condition('variables', serialize('info')) - ->execute(); -} +function _metatag_remove_dupes($entity_type) { + $purge_count = 0; + + // First step: fix the records. There should not be multiple records for the + // same entity_id with different languages. + $dupe_records = db_query("SELECT m.entity_id, count(m.language) AS the_count + FROM metatag m + WHERE + m.entity_type = :type + GROUP BY m.entity_id + HAVING the_count > 1", array(':type' => $entity_type)); + + if (!empty($dupe_records)) { + foreach ($dupe_records as $record) { + $entity_id = $record->entity_id; + $langs = db_query("SELECT m.entity_id, m.language, m.data FROM metatag m WHERE m.entity_type = :type AND m.entity_id = :id", array(':type' => $entity_type, ':id' => $entity_id))->fetchAll(); + + // Work out which language record to remove. Will need to store this as + // an array incase there are multiple records to purge. + $langs_to_remove = array(); + + // Check for duplicate records. + // Outer loop starts from the beginning. + for ($outer = 0; $outer < count($langs); $outer++) { + // This record may have been removed already. + if (isset($langs[$outer])) { + // Inner loop starts from the end. + for ($inner = count($langs) - 1; $inner > 0; $inner--) { + // Work out if the outer loop's data is the same as the inner + // loop's. + if (isset($langs[$inner]) && $langs[$outer]->data == $langs[$inner]->data) { + // Remove the second record. + $langs_to_remove[] = $langs[$inner]->language; + unset($langs[$inner]); + } + } + } + } -/** - * Remove metatag records that were added by old versions of the module for - * entities that don't actually support meta tags. A more complete version of - * this will be added later on after it's (hopefully) guaranteed that all - * modules have updated to the correct API usage. - */ -function metatag_update_7006() { - $types = array( - // Core. - 'comment', - 'menu_link', - 'taxonomy_vocabulary', - // Some contrib entities. - 'mailchimp_list', - 'profile2', - 'profile2_type', - 'redirect', - 'rules_config', - 'wysiwyg_profile', - ); - foreach ($types as $type) { - $num_deleted = db_delete('metatag') - ->condition('entity_type', $type) - ->execute(); - if ($num_deleted > 0) { - drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $type))); - } - } -} + // Only one record left. + if (count($langs) == 1) { + // This is how it should be, this record is fine. + } + // Two records, limited possibilities. + elseif (count($langs) == 2) { + // Work out the entity's language. + $entity = entity_load($entity_type, $entity_id); + $entity_language = NULL; + if (function_exists('entity_language')) { + $entity_language = entity_language($entity_type, $entity); + } + elseif (isset($entity->language)) { + $entity_language = $entity->language; + } + if (empty($language)) { + $entity_language = LANGUAGE_NONE; + } -/** - * Remove metatag records for objects that have been deleted; older versions of - * Metatag may have failed to purge these. - */ -function metatag_update_7007() { - $result = db_query("DELETE m - FROM {metatag} m - LEFT OUTER JOIN {node} n - ON m.entity_id=n.nid - WHERE m.entity_type='node' - AND n.nid IS NULL"); - if ($result->rowCount() > 0) { - drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $result->rowCount()))); - } + // Work out if the entity's language record exists. + $lang_pos = NULL; + foreach ($langs as $key => $record) { + if ($record->language == $entity_language) { + $lang_pos = $key; + break; + } + } + // If the language record exists, delete the others. + if (isset($lang_pos)) { + foreach ($langs as $key => $record) { + if ($record->language != $entity_language) { + $langs_to_remove[] = $record->language; + } + } + } + // Otherwise look for a record for the site's default language. + else { + foreach ($langs as $key => $record) { + if ($record->language == $GLOBALS['language']->language) { + $lang_pos = $key; + break; + } + } + if (isset($lang_pos)) { + foreach ($langs as $key => $record) { + if ($record->language != $GLOBALS['language']->language) { + $langs_to_remove[] = $record->language; + } + } + } + // Finally check for LANGUAGE_NONE. + else { + foreach ($langs as $key => $record) { + if ($record->language == LANGUAGE_NONE) { + $lang_pos = $key; + break; + } + } + if (isset($lang_pos)) { + foreach ($langs as $key => $record) { + if ($record->language != LANGUAGE_NONE) { + $langs_to_remove[] = $record->language; + } + } + } + } + } + } - $result = db_query("DELETE m - FROM {metatag} m - LEFT OUTER JOIN {users} u - ON m.entity_id=u.uid - WHERE m.entity_type='user' - AND u.uid IS NULL"); - if ($result->rowCount() > 0) { - drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $result->rowCount()))); - } + // Purge the redundant records. + if (!empty($langs_to_remove)) { + $purge_count += db_delete('metatag') + ->condition('entity_type', $entity_type) + ->condition('entity_id', $entity_id) + ->condition('language', $langs_to_remove) + ->execute(); + } + } - $result = db_query("DELETE m - FROM {metatag} m - LEFT OUTER JOIN {taxonomy_term_data} t - ON m.entity_id=t.tid - WHERE m.entity_type='taxonomy_term' - AND t.tid IS NULL"); - if ($result->rowCount() > 0) { - drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $result->rowCount()))); + if (!empty($purge_count)) { + drupal_set_message(t('Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type))); + watchdog('metatag', 'Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type)); + return; + } } -} -/** - * Remove metatag any empty records that may be hanging around from old - * releases. - */ -function metatag_update_7008() { - $result = db_query("DELETE FROM {metatag} WHERE data IS NULL or data = '' OR data = 'a:0:{}'"); - if ($result->rowCount() > 0) { - drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $result->rowCount()))); + if (empty($purge_count)) { + drupal_set_message(t('No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type))); + watchdog('metatag', 'No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type)); } }