? patches ? pathauto.api.php Index: pathauto.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto.admin.inc,v retrieving revision 1.20.2.12 diff -u -p -r1.20.2.12 pathauto.admin.inc --- pathauto.admin.inc 27 Jul 2010 04:35:43 -0000 1.20.2.12 +++ pathauto.admin.inc 28 Jul 2010 17:27:53 -0000 @@ -19,11 +19,8 @@ function pathauto_patterns_form($form_st // Call the hook on all modules - an array of 'settings' objects is returned $all_settings = module_invoke_all('pathauto', 'settings'); - $modulelist = array(); - $indexcount = 0; foreach ($all_settings as $settings) { $module = $settings->module; - $modulelist[] = $module; $patterndescr = $settings->patterndescr; $patterndefault = $settings->patterndefault; $groupheader = $settings->groupheader; @@ -84,22 +81,6 @@ function pathauto_patterns_form($form_st '#value' => theme('token_tree', array($settings->token_type), FALSE), ); - // If the module supports bulk updates, offer the update action here - if ($settings->bulkname) { - $variable = 'pathauto_' . $module . '_bulkupdate'; - if (variable_get($variable, FALSE)) { - variable_set($variable, FALSE); - $function = $module . '_pathauto_bulkupdate'; - call_user_func($function); - } - $form[$module][$variable] = array( - '#type' => 'checkbox', - '#title' => $settings->bulkname, - '#default_value' => FALSE, - '#description' => $settings->bulkdescr, - ); - } - // If the module supports feeds, offer to generate aliases for them if ($supportsfeeds) { $variable = 'pathauto_' . $module . '_applytofeeds'; @@ -112,18 +93,8 @@ function pathauto_patterns_form($form_st '#description' => t('The text to use for aliases for RSS feeds. Examples are "0/feed" (used throughout Drupal core) and "feed" (used by some contributed Drupal modules, like Views).'), ); } - - } - - if (isset($do_index_bulkupdate) && $do_index_bulkupdate) { - drupal_set_message(format_plural($indexcount, - 'Bulk generation of index aliases completed, one alias generated.', - 'Bulk generation of index aliases completed, @count aliases generated.')); } - // Keep track of which modules currently support pathauto - variable_set('pathauto_modulelist', $modulelist); - return system_settings_form($form); } @@ -187,17 +158,6 @@ function pathauto_settings_form() { '#element_validate' => array('_pathauto_validate_numeric_element'), ); - $form['pathauto_max_bulk_update'] = array( - '#type' => 'textfield', - '#title' => t('Maximum number of objects to alias in a bulk update'), - '#size' => 4, - '#maxlength' => 4, - '#default_value' => variable_get('pathauto_max_bulk_update', 50), - '#min_value' => 1, - '#description' => t('Maximum number of objects of a given type which should be aliased during a bulk update. The default is 50 and the recommended number depends on the speed of your server. If bulk updates "time out" or result in a "white screen" then reduce the number.'), - '#element_validate' => array('_pathauto_validate_numeric_element'), - ); - $form['pathauto_update_action'] = array( '#type' => 'radios', '#title' => t('Update action'), @@ -345,6 +305,113 @@ function pathauto_settings_form_validate } /** + * Form contructor for path alias bulk update form. + * + * @see pathauto_bulk_update_form_submit() + * @ingroup forms + */ +function pathauto_bulk_update_form() { + _pathauto_include(); + + $form['#update_callbacks'] = array(); + + $form['update'] = array( + '#type' => 'checkboxes', + '#title' => t('Select the types of un-aliased paths for which to generate URL aliases'), + '#options' => array(), + '#default_value' => array(), + ); + + $pathauto_settings = module_invoke_all('pathauto', 'settings'); + foreach ($pathauto_settings as $settings) { + if (!empty($settings->batch_update_callback)) { + $form['#update_callbacks'][$settings->batch_update_callback] = $settings; + $form['update']['#options'][$settings->batch_update_callback] = $settings->groupheader; + } + } + + $form['actions']['#weight'] = 100; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Update'), + ); + + return $form; +} + +/** + * Form submit handler for path alias bulk update form. + * + * @see pathauto_batch_update_form() + * @see pathauto_bulk_update_batch_finished() + */ +function pathauto_bulk_update_form_submit($form, &$form_state) { + $batch = array( + 'title' => t('Bulk updating URL aliases'), + 'operations' => array( + array('pathauto_bulk_update_batch_start', array()), + ), + 'finished' => 'pathauto_bulk_update_batch_finished', + 'file' => drupal_get_path('module', 'pathauto') . '/pathauto.admin.inc', + ); + + foreach ($form_state['values']['update'] as $callback) { + if (!empty($callback)) { + $settings = $form['#update_callbacks'][$callback]; + if (!empty($settings->batch_file)) { + $batch['operations'][] = array('pathauto_bulk_update_batch_process', array($callback, $settings)); + } + else { + $batch['operations'][] = array($callback, array()); + } + } + } + + batch_set($batch); +} + +/** + * Batch callback; count the current number of URL aliases for comparison later. + */ +function pathauto_bulk_update_batch_start(&$context) { + $context['results']['count_before'] = db_result(db_query("SELECT COUNT(*) FROM {url_alias}")); +} + +/** + * Common batch processing callback for all operations. + * + * Required to load our include the proper batch file. + */ +function pathauto_bulk_update_batch_process($callback, $settings, &$context) { + if (!empty($settings->batch_file)) { + require_once './' . $settings->batch_file; + } + return $callback($context); +} + +/** + * Batch finished callback. + */ +function pathauto_bulk_update_batch_finished($success, $results, $operations) { + if ($success) { + // Count the current number of URL aliases after the batch is completed + // and compare to the count before the batch started. + $results['count_after'] = db_result(db_query("SELECT COUNT(*) FROM {url_alias}")); + $results['count_changed'] = max($results['count_after'] - $results['count_before'], 0); + if ($results['count_changed']) { + drupal_set_message(format_plural($results['count_changed'], 'Generated 1 URL alias.', 'Generated @count URL aliases.')); + } + else { + drupal_set_message('No new URL aliases to generate.'); + } + } + else { + $error_operation = reset($operations); + drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE)))); + } +} + +/** * Menu callback; select certain alias types to delete. */ function pathauto_admin_delete() { Index: pathauto.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto.install,v retrieving revision 1.14.2.3 diff -u -p -r1.14.2.3 pathauto.install --- pathauto.install 27 Jul 2010 04:35:43 -0000 1.14.2.3 +++ pathauto.install 28 Jul 2010 17:27:53 -0000 @@ -14,24 +14,17 @@ function pathauto_install() { // Check to see if taxonomy module is enabled before we set those variables if (module_exists('taxonomy')) { - variable_set('pathauto_modulelist', array('node', 'user', 'taxonomy')); variable_set('pathauto_taxonomy_supportsfeeds', '0/feed'); variable_set('pathauto_taxonomy_pattern', 'category/[vocab-raw]/[catpath-raw]'); - variable_set('pathauto_taxonomy_bulkupdate', FALSE); - variable_set('pathauto_taxonomy_applytofeeds', FALSE); variable_set('pathauto_taxonomy_2_pattern', ''); variable_set('pathauto_taxonomy_1_pattern', ''); } - else { - // Node and user are required so we don't have to check - variable_set('pathauto_modulelist', array('node', 'user')); - } + // Set the rest of the pathauto default variables variable_set('pathauto_indexaliases', FALSE); variable_set('pathauto_indexaliases_bulkupdate', FALSE); variable_set('pathauto_max_component_length', '100'); variable_set('pathauto_max_length', '100'); - variable_set('pathauto_node_bulkupdate', FALSE); variable_set('pathauto_node_forum_pattern', ''); variable_set('pathauto_node_image_pattern', ''); variable_set('pathauto_node_page_pattern', ''); @@ -40,7 +33,6 @@ function pathauto_install() { variable_set('pathauto_punctuation_quotes', 0); variable_set('pathauto_separator', '-'); variable_set('pathauto_update_action', '2'); - variable_set('pathauto_user_bulkupdate', FALSE); variable_set('pathauto_user_pattern', 'users/[user-raw]'); variable_set('pathauto_user_supportsfeeds', NULL); variable_set('pathauto_verbose', FALSE); @@ -122,3 +114,17 @@ function pathauto_update_6200() { variable_del('pathauto_tracker_applytofeeds'); return array(); } + +/** + * Remove obsolete variable since batch API is now used. + */ +function pathauto_update_6201() { + variable_del('pathauto_max_bulk_update'); + variable_del('pathauto_node_bulkupdate'); + variable_del('pathauto_taxonomy_bulkupdate'); + variable_del('pathauto_forum_bulkupdate'); + variable_del('pathauto_user_bulkupdate'); + variable_del('pathauto_blog_bulkupdate'); + variable_del('pathauto_modulelist'); + return array(); +} Index: pathauto.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto.module,v retrieving revision 1.126.2.29 diff -u -p -r1.126.2.29 pathauto.module --- pathauto.module 25 Jul 2010 05:16:12 -0000 1.126.2.29 +++ pathauto.module 28 Jul 2010 17:27:53 -0000 @@ -75,13 +75,22 @@ function pathauto_menu() { 'weight' => 20, 'file' => 'pathauto.admin.inc', ); + $items['admin/build/path/update_bulk'] = array( + 'title' => 'Bulk update', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('pathauto_bulk_update_form'), + 'access arguments' => array('administer url aliases'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 30, + 'file' => 'pathauto.admin.inc', + ); $items['admin/build/path/delete_bulk'] = array( 'title' => 'Delete aliases', 'page callback' => 'drupal_get_form', 'page arguments' => array('pathauto_admin_delete'), 'access arguments' => array('administer url aliases'), 'type' => MENU_LOCAL_TASK, - 'weight' => 30, + 'weight' => 40, 'file' => 'pathauto.admin.inc', ); @@ -213,23 +222,13 @@ function pathauto_nodeapi(&$node, $op, $ break; case 'insert': case 'update': - // Only do work if there's a pattern. - $language = variable_get('language_content_type_' . $node->type, 0) ? $node->language : ''; - if ($pattern = pathauto_pattern_load_by_entity('node', $node->type, $language)) { - _pathauto_include(); - // Only create an alias if the checkbox was not provided or if the checkbox was provided and is checked - if (!isset($node->pathauto_perform_alias) || $node->pathauto_perform_alias) { - $placeholders = pathauto_get_placeholders('node', $node); - $src = "node/$node->nid"; - $node->path = pathauto_create_alias('node', $op, $placeholders, $src, $node->nid, $node->type, $node->language); - } + if (!isset($node->pathauto_perform_alias) || !empty($node->pathauto_perform_alias)) { + pathauto_node_update_alias($node, 'insert'); } break; case 'delete': pathauto_path_delete_all("node/{$node->nid}"); break; - default: - break; } } @@ -256,7 +255,7 @@ function pathauto_form_alter(&$form, $fo // If this is not a new node, compare it's current alias to the // alias that would be genereted by pathauto. If they are the same, // then keep the automatic alias enabled. - _pathauto_include(); + module_load_include('inc', 'pathauto'); $placeholders = pathauto_get_placeholders('node', $node); $pathauto_alias = pathauto_create_alias('node', 'return', $placeholders, "node/{$node->nid}", $node->nid, $node->type, $node->language); $node->pathauto_perform_alias = isset($node->path) && $node->path == $pathauto_alias; @@ -309,7 +308,7 @@ function pathauto_node_operations() { $operations['pathauto_update_alias'] = array( 'label' => t('Update URL alias'), 'callback' => 'pathauto_node_update_alias_multiple', - 'callback arguments' => array('bulkupdate', TRUE), + 'callback arguments' => array('bulkupdate', array('message' => TRUE)), ); return $operations; } @@ -321,11 +320,19 @@ function pathauto_node_operations() { * A node object. * @param $op * Operation being performed on the node ('insert', 'update' or 'bulkupdate'). + * @param $options + * An optional array of additional options. */ -function pathauto_node_update_alias($node, $op) { +function pathauto_node_update_alias($node, $op, $options = array()) { + // Skip processing if the term has no pattern. + $language = isset($node->language) ? $node->language : ''; + if (!pathauto_pattern_load_by_entity('node', $node->type, $language)) { + return; + } + module_load_include('inc', 'pathauto'); $placeholders = pathauto_get_placeholders('node', $node); - pathauto_create_alias('node', $op, $placeholders, "node/{$node->nid}", $node->nid, $node->type, $node->language); + pathauto_create_alias('node', $op, $placeholders, "node/{$node->nid}", $node->nid, $node->type, $language); } /** @@ -336,17 +343,19 @@ function pathauto_node_update_alias($nod * @param $op * Operation being performed on the nodes ('insert', 'update' or * 'bulkupdate'). - * @param $message - * A boolean if TRUE will display a message about how many nodes were - * updated. + * @param $options + * An optional array of additional options. */ -function pathauto_node_update_alias_multiple($nids, $op, $message = FALSE) { +function pathauto_node_update_alias_multiple($nids, $op, $options = array()) { + $options += array('message' => FALSE); + foreach ($nids as $nid) { if ($node = node_load($nid, NULL, TRUE)) { - pathauto_node_update_alias($node, $op); + pathauto_node_update_alias($node, $op, $options); } } - if ($message) { + + if (!empty($options['message'])) { drupal_set_message(format_plural(count($nids), 'Updated URL alias for 1 node.', 'Updated URL aliases for @count nodes.')); } } @@ -363,28 +372,12 @@ function pathauto_taxonomy($op, $type, $ switch ($op) { case 'insert': case 'update': - $category = (object) $object; - - // Only do work if there's a pattern. - if ($pattern = pathauto_pattern_load_by_entity('taxonomy', $category->vid)) { - _pathauto_include(); - - // Clear the taxonomy term's static cache. - if ($op == 'update') { - taxonomy_get_term($category->tid, TRUE); - } - - // Use the category info to automatically create an alias - if ($category->name) { - $count = _taxonomy_pathauto_alias($category, $op); - } - - // For all children generate new alias (important if [catpath] used) - foreach (taxonomy_get_tree($category->vid, $category->tid) as $subcategory) { - $count = _taxonomy_pathauto_alias($subcategory, $op); - } + $term = (object) $object; + // Clear the taxonomy term's static cache. + if ($op == 'update') { + taxonomy_get_term($term->tid, TRUE); } - + pathauto_taxonomy_term_update_alias($term, $op); break; case 'delete': // If the category is deleted, remove the path aliases @@ -395,12 +388,70 @@ function pathauto_taxonomy($op, $type, $ pathauto_path_delete_all("taxonomy/term/{$category->tid}"); } break; - default: - break; } break; - default: - break; + } +} + +/** + * Update the URL aliases for an individual taxonomy term. + * + * @param $term + * A taxonomy term object. + * @param $op + * Operation being performed on the term ('insert', 'update' or 'bulkupdate'). + * @param $options + * An optional array of additional options. + */ +function pathauto_taxonomy_term_update_alias($term, $op, $options = array()) { + $options += array('alias children' => FALSE); + + $module = 'taxonomy'; + if (module_exists('forum') && $term->vid == variable_get('forum_nav_vocabulary', '')) { + $module = 'forum'; + } + + // Skip processing if the term has no pattern. + if (!pathauto_pattern_load_by_entity($module, $term->vid)) { + return; + } + + module_load_include('inc', 'pathauto'); + $source = taxonomy_term_path($term); + $placeholders = pathauto_get_placeholders('taxonomy', $term); + pathauto_create_alias($module, $op, $placeholders, $source, $term->tid, $term->vid); + + if (!empty($options['alias children'])) { + // For all children generate new alias. + $options['alias children'] = FALSE; + foreach (taxonomy_get_tree($term->vid, $term->tid) as $subterm) { + pathauto_taxonomy_term_update_alias($subterm, $op, $options); + } + } +} + +/** + * Update the URL aliases for multiple taxonomy terms. + * + * @param $tids + * An array of term IDs. + * @param $op + * Operation being performed on the nodes ('insert', 'update' or + * 'bulkupdate'). + * @param $options + * An optional array of additional options. + */ +function pathauto_taxonomy_term_update_alias_multiple(array $tids, $op, array $options = array()) { + $options += array('message' => FALSE); + + foreach ($tids as $tid) { + if ($term = taxonomy_get_term($tid, TRUE)) { + pathauto_taxonomy_term_update_alias($term, $op, $options); + } + } + + if (!empty($options['message'])) { + drupal_set_message(format_plural(count($tids), 'Updated URL alias for 1 term.', 'Updated URL aliases for @count terms.')); } } @@ -414,10 +465,10 @@ function pathauto_user($op, &$edit, &$us switch ($op) { case 'insert': case 'update': - _pathauto_include(); // Use the username to automatically create an alias $pathauto_user = (object) array_merge((array) $user, $edit); if ($user->name) { + module_load_include('inc', 'pathauto'); $placeholders = pathauto_get_placeholders('user', $pathauto_user); $src = 'user/'. $user->uid; $alias = pathauto_create_alias('user', $op, $placeholders, $src, $user->uid); @@ -457,7 +508,7 @@ function pathauto_user_operations() { $operations['pathauto_update_alias'] = array( 'label' => t('Update URL alias'), 'callback' => 'pathauto_user_update_alias_multiple', - 'callback arguments' => array('bulkupdate', TRUE), + 'callback arguments' => array('bulkupdate', array('message' => TRUE)), ); return $operations; } @@ -470,21 +521,26 @@ function pathauto_user_operations() { * @param $op * Operation being performed on the account ('insert', 'update' or * 'bulkupdate'). - * - * @todo Remove support for any sub-path aliases. + * @param $options + * An optional array of additional options. */ -function pathauto_user_update_alias($account, $op) { +function pathauto_user_update_alias($account, $op, $options = array()) { + $options += array('alias blog' => module_exists('blog')); + + // Skip processing if the account has no pattern. + if (!pathauto_pattern_load_by_entity('user')) { + return; + } + module_load_include('inc', 'pathauto'); $placeholders = pathauto_get_placeholders('user', $account); pathauto_create_alias('user', $op, $placeholders, "user/{$account->uid}", $account->uid); - if (module_exists('blog')) { - if (node_access('create', 'blog', $account)) { - pathauto_create_alias('blog', $op, $placeholders, "blog/{$account->uid}", $account->uid); - } - else { - pathauto_path_delete_all("blog/{$user->uid}"); - } + // Because blogs are also associated with users, also generate the blog paths. + if (!empty($options['alias blog'])) { + // Allow placeholders to be re-used. + $options['placeholders'] = $placeholders; + pathauto_blog_update_alias($account, $op); } } @@ -496,17 +552,46 @@ function pathauto_user_update_alias($acc * @param $op * Operation being performed on the accounts ('insert', 'update' or * 'bulkupdate'). - * @param $message - * A boolean if TRUE will display a message about how many accounts were - * updated. + * @param $options + * An optional array of additional options. */ -function pathauto_user_update_alias_multiple($uids, $op, $message = FALSE) { +function pathauto_user_update_alias_multiple($uids, $op, $options = array()) { + $options += array('message' => FALSE); + foreach ($uids as $uid) { if ($account = user_load($uid)) { - pathauto_user_update_alias($account, $op); + pathauto_user_update_alias($account, $op, $options); } } - if ($message) { + + if (!empty($options['message'])) { drupal_set_message(format_plural(count($uids), 'Updated URL alias for 1 user account.', 'Updated URL aliases for @count user accounts.')); } } + +/** + * Update the blog URL aliases for an individual user account. + * + * @param $account + * A user account object. + * @param $op + * Operation being performed on the blog ('insert', 'update' or + * 'bulkupdate'). + * @param $options + * An optional array of additional options. + */ +function pathauto_blog_update_alias($account, $op, $options = array()) { + // Skip processing if the blog has no pattern. + if (!pathauto_pattern_load_by_entity('blog')) { + return; + } + + module_load_include('inc', 'pathauto'); + $placeholders = isset($options['placeholders']) ? $options['placeholders'] : pathauto_get_placeholders('user', $account); + if (node_access('create', 'blog', $account)) { + pathauto_create_alias('blog', $op, $placeholders, "blog/{$account->uid}", $account->uid); + } + else { + pathauto_path_delete_all("blog/{$user->uid}"); + } +} Index: pathauto.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto.test,v retrieving revision 1.1.4.21 diff -u -p -r1.1.4.21 pathauto.test --- pathauto.test 28 Jul 2010 15:45:34 -0000 1.1.4.21 +++ pathauto.test 28 Jul 2010 17:27:53 -0000 @@ -53,11 +53,21 @@ class PathautoTestHelper extends DrupalW $this->assertAlias($uri['path'], $expected_alias, $language); } + function assertEntityAliasExists($entity_type, $entity) { + $uri = $this->entity_uri($entity_type, $entity); + $this->assertAliasExists(array('source' => $uri['path'])); + } + function assertNoEntityAlias($entity_type, $entity, $expected_alias, $language = '') { $uri = $this->entity_uri($entity_type, $entity); $this->assertEntityAlias($entity_type, $entity, $uri['path'], $language); } + function assertNoEntityAliasExists($entity_type, $entity) { + $uri = $this->entity_uri($entity_type, $entity); + $this->assertNoAliasExists(array('source' => $uri['path'])); + } + function assertAlias($source, $expected_alias, $language = '') { drupal_clear_path_cache(); $alias = drupal_get_path_alias($source, $language); @@ -138,6 +148,11 @@ class PathautoTestHelper extends DrupalW $sql = "SELECT * FROM {url_alias} WHERE " . implode(' AND ', $conditions); return db_fetch_array(db_query_range($sql, $args, 0, 1)); } + + function deleteAllAliases() { + db_query("DELETE FROM {url_alias}"); + drupal_clear_path_cache(); + } } /** @@ -611,3 +626,53 @@ class PathautoLocaleTestCase extends Pat $this->assertAliasExists(array('pid' => $english_alias['pid'], 'alias' => 'content/english-node-0')); } } + +/** + * Bulk update functionality tests. + */ +class PathautoBulkUpdateTestCase extends PathautoFunctionalTestHelper { + private $nodes; + + public static function getInfo() { + return array( + 'name' => 'Pathauto bulk updating', + 'description' => 'Tests bulk updating of URL aliases.', + 'group' => 'Pathauto', + ); + } + + function testBulkUpdate() { + // Create some nodes. + $this->nodes = array(); + for ($i = 1; $i <= 5; $i++) { + $node = $this->drupalCreateNode(); + $this->nodes[$node->nid] = $node; + } + + // Clear out all aliases. + $this->deleteAllAliases(); + + // Bulk create aliases. + $edit = array( + 'update[node_pathauto_bulk_update_batch_process]' => TRUE, + 'update[user_pathauto_bulk_update_batch_process]' => TRUE, + ); + $this->drupalPost('admin/build/path/update_bulk', $edit, t('Update')); + $this->assertText('Generated 7 URL aliases.'); // 5 nodes + 2 users + + // Check that aliases have actually been created. + foreach ($this->nodes as $node) { + $this->assertEntityAliasExists('node', $node); + } + $this->assertEntityAliasExists('user', $this->admin_user); + + // Add a new node. + $new_node = $this->drupalCreateNode(array('alias' => '', 'pathauto_perform_alias' => FALSE)); + + // Run the update again which should only run against the new node. + $this->drupalPost('admin/build/path/update_bulk', $edit, t('Update')); + $this->assertText('Generated 1 URL alias.'); // 1 node + 0 users + + $this->assertEntityAliasExists('node', $new_node); + } +} Index: pathauto_node.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto_node.inc,v retrieving revision 1.48.2.2 diff -u -p -r1.48.2.2 pathauto_node.inc --- pathauto_node.inc 9 Jun 2010 02:18:17 -0000 1.48.2.2 +++ pathauto_node.inc 28 Jul 2010 17:27:53 -0000 @@ -20,26 +20,20 @@ function node_pathauto($op) { $settings['groupheader'] = t('Node paths'); $settings['patterndescr'] = t('Default path pattern (applies to all node types with blank patterns below)'); $settings['patterndefault'] = t('content/[title-raw]'); - $settings['bulkname'] = t('Bulk generate aliases for nodes that are not aliased'); - $settings['bulkdescr'] = t('Generate aliases for all existing nodes which do not already have aliases.'); + $settings['batch_update_callback'] = 'node_pathauto_bulk_update_batch_process'; + $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto_node.inc'; $settings['supportsfeeds'] = 'feed'; + $languages = array(); if (module_exists('locale')) { - $languages = array('' => t('Language neutral')) + locale_language_list('name'); - } - else { - $languages = array(); + $languages = array('' => t('language neutral')) + locale_language_list('name'); } + foreach (node_get_types('names') as $node_type => $node_name) { - if (variable_get('language_content_type_'. $node_type, 0) && count($languages)) { + if (count($languages) && variable_get('language_content_type_'. $node_type, 0)) { $settings['patternitems'][$node_type] = t('Default path pattern for @node_type (applies to all @node_type node types with blank patterns below)', array('@node_type' => $node_name)); foreach ($languages as $lang_code => $lang_name) { - if (!empty($lang_code)) { - $settings['patternitems'][$node_type .'_'. $lang_code] = t('Pattern for all @node_type paths in @language', array('@node_type' => $node_name, '@language' => $lang_name)); - } - else { - $settings['patternitems'][$node_type .'_'. $lang_code] = t('Pattern for all language neutral @node_type paths', array('@node_type' => $node_name)); - } + $settings['patternitems'][$node_type . '_' . $lang_code] = t('Pattern for all @language @node_type paths', array('@node_type' => $node_name, '@language' => $lang_name)); } } else { @@ -53,63 +47,41 @@ function node_pathauto($op) { } /** - * Generate aliases for all nodes without aliases. + * Batch processing callback; Generate aliases for nodes. */ -function node_pathauto_bulkupdate() { - // From all node types, only attempt to update those with patterns - $pattern_types = array(); - - // If there's a default pattern we assume all types might be updated. - if (trim(variable_get('pathauto_node_pattern', ''))) { - $pattern_types = array_keys(node_get_types('names')); +function node_pathauto_bulk_update_batch_process(&$context) { + if (!isset($context['sandbox']['current'])) { + $context['sandbox']['count'] = 0; + $context['sandbox']['current'] = 0; } - else { - // Check first for a node specific pattern... - $languages = array(); - if (module_exists('locale')) { - $languages = array('' => t('Language neutral')) + locale_language_list('name'); - } - foreach (array_keys(node_get_types('names')) as $type) { - if (trim(variable_get('pathauto_node_'. $type .'_pattern', ''))) { - $pattern_types[$type] = $type; - continue; - } - // ...then for a node-language pattern. - if (variable_get('language_content_type_'. $type, 0) && $languages) { - foreach ($languages as $lang_code => $lang_name) { - if (trim(variable_get('pathauto_node_'. $type .'_'. $lang_code .'_pattern', ''))) { - $pattern_types[$type] = $type; - continue 2; - } - } - } + + $sql = "SELECT n.nid FROM {node} n LEFT JOIN {url_alias} ua ON CONCAT('node/', CAST(n.nid AS CHAR)) = ua.src WHERE ua.src IS NULL AND n.nid > %d ORDER BY n.nid"; + $args = array($context['sandbox']['current']); + + // Get the total amount of items to process. + if (!isset($context['sandbox']['total'])) { + $count_sql = str_replace('SELECT n.nid', 'SELECT COUNT(n.nid)', $sql); + $context['sandbox']['total'] = db_result(db_query($count_sql, $args)); + + // If there are no nodes to update, the stop immediately. + if (!$context['sandbox']['total']) { + $context['finished'] = 1; + return; } } - $count = 0; - if (count($pattern_types)) { - $query = "SELECT n.nid, n.vid, n.type, n.title, n.uid, n.created, n.language, alias.src, alias.dst FROM {node} n LEFT JOIN {url_alias} alias ON CONCAT('node/', CAST(n.nid AS CHAR)) = alias.src WHERE alias.src IS NULL AND n.type IN (". db_placeholders($pattern_types, 'varchar') .')'; - $result = db_query_range($query, $pattern_types, 0, variable_get('pathauto_max_bulk_update', 50)); - - $placeholders = array(); - while ($node_ref = db_fetch_object($result)) { - $node = node_load($node_ref->nid, NULL, TRUE); - $node->src = $node_ref->src; - $node->dst = $node_ref->dst; - if (module_exists('taxonomy')) { - // Must populate the terms for the node here for the category - // placeholders to work - $node->taxonomy = array_keys(taxonomy_node_get_terms($node)); - } - $placeholders = pathauto_get_placeholders('node', $node); - $source = "node/$node->nid"; - if (pathauto_create_alias('node', 'bulkupdate', $placeholders, $source, $node->nid, $node->type, $node->language)) { - $count++; - } - } + $query = db_query_range($sql, $args, 0, 5); + $nids = array(); + while ($nid = db_result($query)) { + $nids[] = $nid; } - drupal_set_message(format_plural($count, - 'Bulk generation of nodes completed, one alias generated.', - 'Bulk generation of nodes completed, @count aliases generated.')); + pathauto_node_update_alias_multiple($nids, 'bulkupdate'); + $context['sandbox']['count'] += count($nids); + $context['sandbox']['current'] = max($nids); + $context['message'] = t('Updated alias for node @nid.', array('@nid' => end($nids))); + + if ($context['sandbox']['count'] != $context['sandbox']['total']) { + $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total']; + } } Index: pathauto_taxonomy.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto_taxonomy.inc,v retrieving revision 1.41.2.4 diff -u -p -r1.41.2.4 pathauto_taxonomy.inc --- pathauto_taxonomy.inc 9 Jun 2010 02:18:17 -0000 1.41.2.4 +++ pathauto_taxonomy.inc 28 Jul 2010 17:27:53 -0000 @@ -21,8 +21,8 @@ function taxonomy_pathauto($op) { $settings['patterndescr'] = t('Default path pattern (applies to all vocabularies with blank patterns below)'); $settings['patterndefault'] = t('category/[vocab-raw]/[catpath-raw]'); $settings['supportsfeeds'] = '0/feed'; - $settings['bulkname'] = t('Bulk generate aliases for terms that are not aliased'); - $settings['bulkdescr'] = t('Generate aliases for all existing terms which do not already have aliases.'); + $settings['batch_update_callback'] = 'taxonomy_pathauto_bulk_update_batch_process'; + $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto_taxonomy.inc'; $vocabularies = taxonomy_get_vocabularies(); if (sizeof($vocabularies) > 0) { @@ -43,69 +43,44 @@ function taxonomy_pathauto($op) { } /** - * Generate aliases for all categories without aliases. + * Batch processing callback; Generate aliases for taxonomy terms. */ -function taxonomy_pathauto_bulkupdate() { - // From all node types, only attempt to update those with patterns - $pattern_vids = array(); - foreach (taxonomy_get_vocabularies() as $vid => $info) { - // TODO - If there's a default we shouldn't do this crazy where statement because all vocabularies get aliases. - // TODO - Special casing to exclude the forum vid (and the images vid and...?). - if (pathauto_pattern_load_by_entity('taxonomy', $vid)) { - $pattern_vids[] = $vid; - if (empty($vid_where)) { - $vid_where = " AND (vid = '%s' "; - } - else { - $vid_where .= " OR vid = '%s'"; - } - } +function taxonomy_pathauto_bulk_update_batch_process(&$context) { + if (!isset($context['sandbox']['current'])) { + $context['sandbox']['count'] = 0; + $context['sandbox']['current'] = 0; } - $vid_where .= ')'; - - // Exclude the forums and join all the args into one array so they can be passed to db_query - $forum_vid[] = variable_get('forum_nav_vocabulary', ''); - $query_args = array_merge($forum_vid, $pattern_vids); - $query = "SELECT tid, vid, name, description, src, dst FROM {term_data} LEFT JOIN {url_alias} ON CONCAT('taxonomy/term/', CAST(tid AS CHAR)) = src WHERE src IS NULL AND vid <> %d ". $vid_where; - $result = db_query_range($query, $query_args, 0, variable_get('pathauto_max_bulk_update', 50)); - - $count = 0; - $placeholders = array(); - while ($category = db_fetch_object($result)) { - $count += _taxonomy_pathauto_alias($category, 'bulkupdate'); - } - - drupal_set_message(format_plural($count, - 'Bulk generation of terms completed, one alias generated.', - 'Bulk generation of terms completed, @count aliases generated.')); -} - -/** - * Create aliases for taxonomy objects. - * - * @param $category - * A taxonomy object. - */ -function _taxonomy_pathauto_alias($category, $op) { - $count = 0; - - $placeholders = pathauto_get_placeholders('taxonomy', $category); $forum_vid = variable_get('forum_nav_vocabulary', ''); - // If we're in a forum vocabulary, also create a forum container, forum, or forum topic alias. - if (module_exists('forum') && $forum_vid == (int)$category->vid) { - $source = 'forum/'. $category->tid; - if (pathauto_create_alias('forum', $op, $placeholders, $source, $category->tid, $category->vid)) { - $count++; + $sql = "SELECT t.tid FROM {term_data} t LEFT JOIN {url_alias} ua ON CONCAT('taxonomy/term/', CAST(t.tid AS CHAR)) = ua.src WHERE ua.src IS NULL AND t.tid > %d AND t.vid <> %d ORDER BY t.tid"; + $args = array($context['sandbox']['current'], $forum_vid); + + // Get the total amount of items to process. + if (!isset($context['sandbox']['total'])) { + $count_sql = str_replace('SELECT t.tid', 'SELECT COUNT(t.tid)', $sql); + $context['sandbox']['total'] = db_result(db_query($count_sql, $args)); + + // If there are no nodes to update, the stop immediately. + if (!$context['sandbox']['total']) { + $context['finished'] = 1; + return; } } - else { - $source = taxonomy_term_path($category); - if (pathauto_create_alias('taxonomy', $op, $placeholders, $source, $category->tid, $category->vid)) { - $count++; - } + + $query = db_query_range($sql, $args, 0, 25); + $tids = array(); + while ($tid = db_result($query)) { + $tids[] = $tid; + } + + pathauto_taxonomy_term_update_alias_multiple($tids, 'bulkupdate'); + $context['sandbox']['count'] += count($tids); + $context['sandbox']['current'] = max($tids); + $context['message'] = t('Updated alias for term @tid.', array('@tid' => end($tids))); + + if ($context['sandbox']['count'] != $context['sandbox']['total']) { + $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total']; } - return $count; } /** @@ -121,8 +96,8 @@ function forum_pathauto($op) { $settings['patterndescr'] = t('Pattern for forums and forum containers'); $settings['patterndefault'] = t('[vocab-raw]/[catpath-raw]'); $settings['supportsfeeds'] = '0/feed'; - $settings['bulkname'] = t('Bulk generate aliases for forum paths that are not aliased'); - $settings['bulkdescr'] = t('Generate aliases for all existing forums and forum containers which do not already have aliases.'); + $settings['batch_update_callback'] = 'forum_pathauto_bulk_update_batch_process'; + $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto_taxonomy.inc'; return (object) $settings; default: break; @@ -130,20 +105,42 @@ function forum_pathauto($op) { } /** - * Generate aliases for all forums and forum containers without aliases. + * Batch processing callback; Generate aliases for forums. */ -function forum_pathauto_bulkupdate() { +function forum_pathauto_bulk_update_batch_process(&$context) { + if (!isset($context['sandbox']['current'])) { + $context['sandbox']['count'] = 0; + $context['sandbox']['current'] = 0; + } + $forum_vid = variable_get('forum_nav_vocabulary', ''); - $query = "SELECT tid, vid, name, description, src, dst FROM {term_data} LEFT JOIN {url_alias} ON CONCAT('forum/', CAST(tid AS CHAR)) = src WHERE vid = %d AND src IS NULL"; - $result = db_query_range($query, $forum_vid, 0, variable_get('pathauto_max_bulk_update', 50)); + $sql = "SELECT t.tid FROM {term_data} t LEFT JOIN {url_alias} ua ON CONCAT('forum/', CAST(t.tid AS CHAR)) = ua.src WHERE ua.src IS NULL AND t.tid > %d AND t.vid = %d ORDER BY t.tid"; + $args = array($context['sandbox']['current'], $forum_vid); - $count = 0; - $placeholders = array(); - while ($category = db_fetch_object($result)) { - $count = _taxonomy_pathauto_alias($category, 'bulkupdate') + $count; + // Get the total amount of items to process. + if (!isset($context['sandbox']['total'])) { + $count_sql = str_replace('SELECT t.tid', 'SELECT COUNT(t.tid)', $sql); + $context['sandbox']['total'] = db_result(db_query($count_sql, $args)); + + // If there are no nodes to update, the stop immediately. + if (!$context['sandbox']['total']) { + $context['finished'] = 1; + return; + } + } + + $query = db_query_range($sql, $args, 0, 25); + $tids = array(); + while ($tid = db_result($query)) { + $tids[] = $tid; } - drupal_set_message(format_plural($count, - 'Bulk update of forums and forum containers completed, one alias generated.', - 'Bulk update of forums and forum containers completed, @count aliases generated.')); + pathauto_taxonomy_term_update_alias_multiple($tids, 'bulkupdate'); + $context['sandbox']['count'] += count($tids); + $context['sandbox']['current'] = max($tids); + $context['message'] = t('Updated alias for forum @tid.', array('@tid' => end($tids))); + + if ($context['sandbox']['count'] != $context['sandbox']['total']) { + $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total']; + } } Index: pathauto_user.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/pathauto/pathauto_user.inc,v retrieving revision 1.31.2.3 diff -u -p -r1.31.2.3 pathauto_user.inc --- pathauto_user.inc 22 Jul 2010 00:13:43 -0000 1.31.2.3 +++ pathauto_user.inc 28 Jul 2010 17:27:53 -0000 @@ -20,8 +20,8 @@ function user_pathauto($op) { $settings['groupheader'] = t('User paths'); $settings['patterndescr'] = t('Pattern for user account page paths'); $settings['patterndefault'] = t('users/[user-raw]'); - $settings['bulkname'] = t('Bulk generate aliases for users that are not aliased'); - $settings['bulkdescr'] = t('Generate aliases for all existing user account pages which do not already have aliases.'); + $settings['batch_update_callback'] = 'user_pathauto_bulk_update_batch_process'; + $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto_user.inc'; return (object) $settings; default: break; @@ -29,6 +29,46 @@ function user_pathauto($op) { } /** + * Batch processing callback; Generate aliases for users. + */ +function user_pathauto_bulk_update_batch_process(&$context) { + if (!isset($context['sandbox']['current'])) { + $context['sandbox']['count'] = 0; + $context['sandbox']['current'] = 0; + } + + $sql = "SELECT u.uid FROM {users} u LEFT JOIN {url_alias} ua ON CONCAT('user/', CAST(u.uid AS CHAR)) = ua.src WHERE ua.src IS NULL AND u.uid > %d ORDER BY u.uid"; + $args = array($context['sandbox']['current']); + + // Get the total amount of items to process. + if (!isset($context['sandbox']['total'])) { + $count_sql = str_replace('SELECT u.uid', 'SELECT COUNT(u.uid)', $sql); + $context['sandbox']['total'] = db_result(db_query($count_sql, $args)); + + // If there are no nodes to update, the stop immediately. + if (!$context['sandbox']['total']) { + $context['finished'] = 1; + return; + } + } + + $query = db_query_range($sql, $args, 0, 25); + $uids = array(); + while ($uid = db_result($query)) { + $uids[] = $uid; + } + + pathauto_user_update_alias_multiple($uids, 'bulkupdate', array('alias blog' => FALSE)); + $context['sandbox']['count'] += count($uids); + $context['sandbox']['current'] = max($uids); + $context['message'] = t('Updated alias for user @uid.', array('@uid' => end($uids))); + + if ($context['sandbox']['count'] != $context['sandbox']['total']) { + $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total']; + } +} + +/** * Implements hook_pathauto(). */ function blog_pathauto($op) { @@ -41,8 +81,8 @@ function blog_pathauto($op) { $settings['patterndescr'] = t('Pattern for blog page paths'); $settings['patterndefault'] = t('blogs/[user-raw]'); $settings['supportsfeeds'] = 'feed'; - $settings['bulkname'] = t('Bulk generate aliases for blogs that are not aliased'); - $settings['bulkdescr'] = t('Generate aliases for all existing blog pages which do not already have aliases.'); + $settings['batch_update_callback'] = 'blog_pathauto_bulk_update_batch_process'; + $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto_user.inc'; return (object) $settings; default: break; @@ -50,45 +90,42 @@ function blog_pathauto($op) { } /** - * Bulk generate aliases for all users without aliases. + * Batch processing callback; Generate aliases for blogs. */ -function user_pathauto_bulkupdate() { - $query = "SELECT uid, name, src, dst FROM {users} LEFT JOIN {url_alias} ON CONCAT('user/', CAST(uid AS CHAR)) = src WHERE uid > 0 AND src IS NULL"; - $result = db_query_range($query, 0, variable_get('pathauto_max_bulk_update', 50)); - - $count = 0; - $placeholders = array(); - while ($user = db_fetch_object($result)) { - $placeholders = pathauto_get_placeholders('user', $user); - $source = 'user/'. $user->uid; - if (pathauto_create_alias('user', 'bulkupdate', $placeholders, $source, $user->uid)) { - $count++; - } +function blog_pathauto_bulk_update_batch_process(&$context) { + if (!isset($context['sandbox']['current'])) { + $context['sandbox']['count'] = 0; + $context['sandbox']['current'] = 0; } - drupal_set_message(format_plural($count, - 'Bulk generation of users completed, one alias generated.', - 'Bulk generation of users completed, @count aliases generated.')); -} + $sql = "SELECT u.uid FROM {users} u LEFT JOIN {url_alias} ua ON CONCAT('blog/', CAST(u.uid AS CHAR)) = ua.src WHERE ua.src IS NULL AND u.uid > %d ORDER BY u.uid"; + $args = array($context['sandbox']['current']); -/** - * Bulk generate aliases for all blogs without aliases. - */ -function blog_pathauto_bulkupdate() { - $query = "SELECT uid, name, src, dst FROM {users} LEFT JOIN {url_alias} ON CONCAT('blog/', CAST(uid AS CHAR)) = src WHERE uid > 0 AND src IS NULL"; - $result = db_query_range($query, 0, variable_get('pathauto_max_bulk_update', 50)); - - $count = 0; - $placeholders = array(); - while ($user = db_fetch_object($result)) { - $placeholders = pathauto_get_placeholders('user', $user); - $source = 'blog/'. $user->uid; - if (pathauto_create_alias('blog', 'bulkupdate', $placeholders, $source, $user->uid)) { - $count++; + // Get the total amount of items to process. + if (!isset($context['sandbox']['total'])) { + $count_sql = str_replace('SELECT u.uid', 'SELECT COUNT(u.uid)', $sql); + $context['sandbox']['total'] = db_result(db_query($count_sql, $args)); + + // If there are no nodes to update, the stop immediately. + if (!$context['sandbox']['total']) { + $context['finished'] = 1; + return; } } - drupal_set_message(format_plural($count, - 'Bulk generation of user blogs completed, one alias generated.', - 'Bulk generation of user blogs completed, @count aliases generated.')); + $query = db_query_range($sql, $args, 0, 25); + $uids = array(); + while ($uid = db_result($query)) { + $uids[] = $uid; + $account = user_load($uid); + pathauto_blog_update_alias($account, 'bulkupdate'); + } + + $context['sandbox']['count'] += count($uids); + $context['sandbox']['current'] = max($uids); + $context['message'] = t('Updated alias for blog user @uid.', array('@uid' => end($uids))); + + if ($context['sandbox']['count'] != $context['sandbox']['total']) { + $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total']; + } }