Index: modules/path/path.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v
retrieving revision 1.34
diff -u -p -r1.34 path.admin.inc
--- modules/path/path.admin.inc	15 Oct 2009 17:53:34 -0000	1.34
+++ modules/path/path.admin.inc	17 Oct 2009 14:52:58 -0000
@@ -8,6 +8,7 @@
 
 /**
  * Return a listing of all defined URL aliases.
+ *
  * When filter key passed, perform a standard search on the given key,
  * and return the list of matching URL aliases.
  */
@@ -156,11 +157,11 @@ function path_admin_form_validate($form,
   $language = isset($form_state['values']['language']) ? $form_state['values']['language'] : '';
 
   $has_alias = db_query("SELECT COUNT(alias) FROM {url_alias} WHERE pid <> :pid AND alias = :alias AND language = :language", array(
-    ':pid'      => $pid,
-    ':alias'    => $alias,
-    ':language' => $language,
-  ))
-  ->fetchField();
+      ':pid' => $pid,
+      ':alias' => $alias,
+      ':language' => $language,
+    ))
+    ->fetchField();
 
   if ($has_alias) {
     form_set_error('alias', t('The alias %alias is already in use in this language.', array('%alias' => $alias)));
@@ -175,17 +176,13 @@ function path_admin_form_validate($form,
  * Save a URL alias to the database.
  */
 function path_admin_form_submit($form, &$form_state) {
-  $path = array();
-  foreach (array('source', 'alias', 'pid', 'language') as $key) {
-    if (isset($form_state['values'][$key])) {
-      $path[$key] = $form_state['values'][$key];
-    }
-  }
-  path_save($path);
+  // Remove unnecessary values.
+  form_state_values_clean($form_state);
+
+  path_save($form_state['values']);
 
   drupal_set_message(t('The alias has been saved.'));
   $form_state['redirect'] = 'admin/config/search/path';
-  return;
 }
 
 /**
@@ -211,7 +208,6 @@ function path_admin_delete_confirm_submi
   if ($form_state['values']['confirm']) {
     path_delete($form_state['path']['pid']);
     $form_state['redirect'] = 'admin/config/search/path';
-    return;
   }
 }
 
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.171
diff -u -p -r1.171 path.module
--- modules/path/path.module	15 Oct 2009 17:53:34 -0000	1.171
+++ modules/path/path.module	17 Oct 2009 19:10:03 -0000
@@ -22,14 +22,32 @@ function path_help($path, $arg) {
       $output .= '<p>' . t('This module also provides user-defined mass URL aliasing capabilities, which is useful if you wish to uniformly use URLs different from the default. For example, you may want to have your URLs presented in a different language. Access to the Drupal source code on the web server is required to set up mass URL aliasing.') . ' </p>';
       $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@path">Path module</a>.', array('@path' => 'http://drupal.org/handbook/modules/path/')) . '</p>';
       return $output;
+
     case 'admin/config/search/path':
       return '<p>' . t("An alias defines a different name for an existing URL path - for example, the alias 'about' for the URL path 'node/1'. A URL path can have multiple aliases.") . '</p>';
+
     case 'admin/config/search/path/add':
       return '<p>' . t('Enter the path you wish to create the alias for, followed by the name of the new alias.') . '</p>';
   }
 }
 
 /**
+ * Implement hook_permission().
+ */
+function path_permission() {
+  return array(
+    'administer url aliases' => array(
+      'title' => t('Administer URL aliases'),
+      'description' => t('Manage URL aliases across the entire website.'),
+    ),
+    'create url aliases' => array(
+      'title' => t('Create URL aliases'),
+      'description' => t('Manage URL aliases on content.'),
+    ),
+  );
+}
+
+/**
  * Implement hook_menu().
  */
 function path_menu() {
@@ -83,10 +101,10 @@ function path_load($criteria) {
   if (is_numeric($criteria)) {
     $criteria = array('pid' => $criteria);
   }
-  else if (is_string($criteria)) {
+  elseif (is_string($criteria)) {
     $criteria = array('source' => $criteria);
   }
-  else if (!is_array($criteria)) {
+  elseif (!is_array($criteria)) {
     return FALSE;
   }
   $select = db_select('url_alias');
@@ -94,7 +112,7 @@ function path_load($criteria) {
     $select->condition($field, $value);
   }
   return $select
-    ->fields('url_alias', array('source', 'alias', 'language', 'pid'))
+    ->fields('url_alias')
     ->execute()
     ->fetchAssoc();
 }
@@ -103,38 +121,28 @@ function path_load($criteria) {
  * Save a path alias to the database.
  *
  * @param $path
- *   A path array containing the following keys:
- *   - source: the initial path.
- *   - alias: the aliased path.
- *   - language: the language of the alias.
- *   - pid: unique path alias identifier (optional).
- */
-function path_save($path) {
-  $path += array('language' => '', 'pid' => 0);
-  $pid = empty($path['pid']) ? 0 : $path['pid'];
-  $new = (bool) $pid;
-  unset($path['pid']);
-  // Make sure that this combination of source, alias, language wasn't save before.
-  $loaded_path = path_load($path);
-  if ($loaded_path) {
-    return $loaded_path;
-  }
-  if ($pid) {
-    db_update('url_alias')
-      ->fields($path)
-      ->condition('pid', $pid)
-      ->execute();
-  }
-  else {
-   $pid = db_insert('url_alias')
-     ->fields($path)
-     ->execute();
+ *   An associative array containing the following keys:
+ *   - source: The internal system path.
+ *   - alias: The URL alias.
+ *   - pid: (optional) Unique path alias identifier.
+ *   - language: (optional) The language of the alias.
+ */
+function path_save(&$path) {
+  $path += array('pid' => NULL, 'language' => '');
+
+  // Insert or update the alias.
+  $status = drupal_write_record('url_alias', $path, (!empty($path['pid']) ? 'pid' : NULL));
+
+  // Verify that a record as written.
+  if (isset($status) && $status) {
+    if ($status === SAVED_NEW) {
+      module_invoke_all('path_insert', $path);
+    }
+    else {
+      module_invoke_all('path_update', $path);
+    }
+    drupal_clear_path_cache();
   }
-  $path['pid'] = $pid;
-  module_invoke_all('path_' . ($new ? 'insert' : 'update'), $path);
-
-  drupal_clear_path_cache();
-  return $path;
 }
 
 /**
@@ -158,30 +166,6 @@ function path_delete($criteria) {
 }
 
 /**
- * Implement hook_node_validate().
- */
-function path_node_validate($node, $form) {
-  if (user_access('create url aliases') || user_access('administer url aliases')) {
-    if (isset($node->path)) {
-      if (!is_array($node->path)) {
-        $node->path = array('alias' => $node->path);
-      }
-      $select = db_select('url_alias')->condition('alias', trim($node->path['alias']));
-      $select->addExpression('COUNT(alias)');
-      if ($node->nid) {
-        $select->condition('source', 'node/' . $node->nid, '<>');
-      }
-      if (isset($node->language)) {
-        $select->condition('language', $node->language);
-      }
-      if ($select->execute()->fetchField()) {
-        form_set_error('path', t('The path is already in use.'));
-      }
-    }
-  }
-}
-
-/**
  * Implement hook_node_load().
  */
 function path_node_load($nodes, $types) {
@@ -198,191 +182,203 @@ function path_node_load($nodes, $types) 
 }
 
 /**
- * Implement hook_node_insert().
- */
-function path_node_insert($node) {
-  if ((user_access('create url aliases') || user_access('administer url aliases')) && isset($node->path)) {
-    if (!is_array($node->path)) {
-      $node->path = array('alias' => $node->path);
-    }
-    
-    $node->path += array(
-      'source' => 'node/' . $node->nid,
-      'language' => isset($node->language) ? $node->language : '',
-    );
-    $node->path = path_save($node->path);
-  }
-}
-
-/**
- * Implement hook_node_update().
- */
-function path_node_update($node) {
-  if ((user_access('create url aliases') || user_access('administer url aliases')) && isset($node->path)) {
-    if (!is_array($node->path)) {
-      $node->path = array('alias' => $node->path);
-    }
-    if (isset($node->pid)) {
-      $node->path['pid'] = $node->pid;
-    }
-    $node->path += array(
-      'source' => 'node/' . $node->nid,
-      'language' => isset($node->language) ? $node->language : '',
-    );
-    path_save($node->path);
-  }
-}
-
-/**
- * Implement hook_node_delete().
- */
-function path_node_delete($node) {
-  if (isset($node->path)) {
-    if (!is_array($node->path)) {
-      $node->path = path_load(array('alias' => $node->path));
-    }
-    path_delete($node->path['pid']);
-    unset($node->path);
-  }
-}
-
-/**
- * Implement hook_taxonomy_term_delete().
- */
-function path_taxonomy_term_delete($term) {
-  path_delete(path_load('taxonomy/term/' . $term->tid));
-}
-
-/**
  * Implement hook_form_alter().
  */
 function path_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
-    $path = NULL;
-    if (isset($form['#node']->path)) {
-      if (is_array($form['#node']->path)) {
-        $path = $form['#node']->path['alias'];
-      }
-      else {
-        $path = $form['#node']->path;
-      }
-    }
+    $path = (isset($form['#node']->path) ? $form['#node']->path : array());
+    $path += array(
+      'pid' => NULL,
+      'source' => isset($form['#node']->nid) ? 'node/' . $form['#node']->nid : NULL,
+      'alias' => '',
+      'language' => isset($form['#node']->language) ? $form['#node']->language : '',
+    );
     $form['path'] = array(
       '#type' => 'fieldset',
       '#title' => t('URL path settings'),
       '#collapsible' => TRUE,
-      '#collapsed' => empty($path),
+      '#collapsed' => empty($path['alias']),
       '#group' => 'additional_settings',
       '#attached' => array(
         'js' => array(drupal_get_path('module', 'path') . '/path.js'),
       ),
-      '#access' => user_access('create url aliases'),
+      '#access' => user_access('create url aliases') || user_access('administer url aliases'),
       '#weight' => 30,
+      '#tree' => TRUE,
+      '#element_validate' => array('path_form_element_validate'),
     );
-    $form['path']['path'] = array(
+    $form['path']['alias'] = array(
       '#type' => 'textfield',
       '#title' => t('URL alias'),
-      '#default_value' => $path,
+      '#default_value' => $path['alias'],
       '#maxlength' => 255,
       '#collapsible' => TRUE,
       '#collapsed' => TRUE,
       '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
     );
-    if ($path) {
-      $form['path']['pid'] = array(
-        '#type' => 'value',
-        '#value' => $form['#node']->path['pid'],
+    $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
+    $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
+    $form['path']['language'] = array('#type' => 'value', '#value' => $path['language']);
+  }
+}
+
+/**
+ * Form element validation handler for URL alias form element.
+ */
+function path_form_element_validate($element, &$form_state, $complete_form) {
+  if (!empty($form_state['values']['path']['alias'])) {
+    // Trim the submitted value.
+    $alias = trim($form_state['values']['path']['alias']);
+    form_set_value($element['alias'], $alias, $form_state);
+    $path = $form_state['values']['path'];
+
+    // Ensure that the submitted alias does not exist yet.
+    $query = db_select('url_alias')
+      ->condition('alias', $path['alias'])
+      ->condition('language', $path['language']);
+    if (!empty($path['source'])) {
+      $query->condition('source', $path['source'], '<>');
+    }
+    $query->addExpression('COUNT(1)');
+    $query->range(0, 1);
+    if ($query->execute()->fetchField()) {
+      form_set_error('alias', t('The alias is already in use.'));
+    }
+  }
+}
+
+/**
+ * Implement hook_node_insert().
+ */
+function path_node_insert($node) {
+  if (isset($node->path)) {
+    $path = $node->path;
+    $path['alias'] = trim($path['alias']);
+    // Only save a non-empty alias.
+    if (!empty($path['alias'])) {
+      // Ensure fields for programmatic executions.
+      $path += array(
+        'source' => 'node/' . $node->nid,
+        'language' => isset($node->language) ? $node->language : '',
       );
+      path_save($path);
     }
   }
 }
 
 /**
+ * Implement hook_node_update().
+ */
+function path_node_update($node) {
+  if (isset($node->path)) {
+    $path = $node->path;
+    $path['alias'] = trim($path['alias']);
+    // Delete old alias if user erased it.
+    if (!empty($path['pid']) && empty($path['alias'])) {
+      path_delete($path['pid']);
+    }
+    // Only save a non-empty alias.
+    if (!empty($path['alias'])) {
+      // Ensure fields for programmatic executions.
+      $path += array(
+        'source' => 'node/' . $node->nid,
+        'language' => isset($node->language) ? $node->language : '',
+      );
+      path_save($path);
+    }
+  }
+}
+
+/**
+ * Implement hook_node_delete().
+ */
+function path_node_delete($node) {
+  // Delete all aliases associated with this node.
+  path_delete(array('source' => 'node/' . $node->nid));
+}
+
+/**
  * Implement hook_form_FORM_ID_alter().
  */
 function path_form_taxonomy_form_term_alter(&$form, $form_state) {
   // Make sure this does not show up on the delete confirmation form.
   if (empty($form_state['confirm_delete'])) {
-    // After a new term is added, populate the path field if it was set.
-    if (!empty($form['#term']['path'])) {
-      $path = $form['#term']['path'];
-      if (!is_array($path)) {
-        $path = path_load(array('alias' => $path));
-      }
-    }
-    else {
-      $alias = path_load('taxonomy/term/' . $form['#term']['tid']);
-      // Since drupal_get_path_alias() can return the default path, check if we really have an alias.
-      if ($alias['alias'] != 'taxonomy/term/' . $form['#term']['tid']) {
-        $path = $alias;
-      }
-      else {
-        $path = NULL;
-      }
-    }
-    $form['#validate'][] = 'path_taxonomy_term_validate';
-    $form['#submit'][] = 'path_taxonomy_term_submit';
+    $path = (isset($form['#term']['tid']) ? path_load('taxonomy/term/' . $form['#term']['tid']) : array());
+    if ($path === FALSE) {
+      $path = array();
+    }
+    $path += array(
+      'pid' => NULL,
+      'source' => isset($form['#term']['tid']) ? 'taxonomy/term/' . $form['#term']['tid'] : NULL,
+      'alias' => '',
+      'language' => '',
+    );
     $form['identification']['path'] = array(
+      '#access' => user_access('create url aliases') || user_access('administer url aliases'),
+      '#tree' => TRUE,
+      '#element_validate' => array('path_form_element_validate'),
+    );
+    $form['identification']['path']['alias'] = array(
       '#type' => 'textfield',
       '#title' => t('URL alias'),
       '#default_value' => $path['alias'],
       '#maxlength' => 255,
       '#weight' => 0,
-      '#access' => (user_access('create url aliases') || user_access('administer url aliases')),
       '#description' => t("Optionally specify an alternative URL by which this term can be accessed. Use a relative path and don't add a trailing slash or the URL alias won't work."),
     );
-    if ($path) {
-      // Populate with pid so we can update existing path entry instead of creating a new one.
-      $form['identification']['path']['pid'] = array(
-        '#type' => 'value',
-        '#access' => (user_access('create url aliases') || user_access('administer url aliases')),
-        '#value' => db_query("SELECT pid FROM {url_alias} WHERE alias = :alias", array(':alias' => $path['alias']))->fetchField(),
-      );
-    }
+    $form['identification']['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
+    $form['identification']['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
+    $form['identification']['path']['language'] = array('#type' => 'value', '#value' => $path['language']);
   }
 }
 
 /**
- * Path validation callback for taxonomy_form_term.
+ * Implement hook_taxonomy_term_insert().
  */
-function path_taxonomy_term_validate($form, &$form_state) {
-  $path = path_load(array('alias' => $form_state['values']['path']));
-  if ($path) {
-    // If the pid matches the one in use for this term then we are fine.
-    if (isset($form_state['values']['pid']) && $path['pid'] == $form_state['values']['pid']) {
-      return;
+function path_taxonomy_term_insert($term) {
+  if (isset($term->path)) {
+    $path = $term->path;
+    $path['alias'] = trim($path['alias']);
+    // Only save a non-empty alias.
+    if (!empty($path['alias'])) {
+      // Ensure fields for programmatic executions.
+      $path += array(
+        'source' => 'taxonomy/term/' . $term->tid,
+        'language' => '',
+      );
+      path_save($path);
     }
-    form_set_error('path', t('The URL alias is already in use.'));
   }
 }
 
 /**
- * Path submission callback for taxonomy_form_term.
+ * Implement hook_taxonomy_term_update().
  */
-function path_taxonomy_term_submit($form, &$form_state) {
-  // Make sure this is not triggered on the delete confirmation form.
-  if (empty($form_state['confirm_delete'])) {
-    $path = array(
-      'source' => 'taxonomy/term/' . $form_state['tid'],
-      'alias' => isset($form_state['values']['path']) ? $form_state['values']['path'] : NULL,
-      'pid' => isset($form_state['values']['pid']) ? $form_state['values']['pid'] : NULL,
-    );
-    path_save($path);
+function path_taxonomy_term_update($term) {
+  if (isset($term->path)) {
+    $path = $term->path;
+    $path['alias'] = trim($path['alias']);
+    // Delete old alias if user erased it.
+    if (!empty($path['pid']) && empty($path['alias'])) {
+      path_delete($path['pid']);
+    }
+    // Only save a non-empty alias.
+    if (!empty($path['alias'])) {
+      // Ensure fields for programmatic executions.
+      $path += array(
+        'source' => 'taxonomy/term/' . $term->tid,
+        'language' => '',
+      );
+      path_save($path);
+    }
   }
 }
 
 /**
- * Implement hook_permission().
+ * Implement hook_taxonomy_term_delete().
  */
-function path_permission() {
-  return array(
-    'administer url aliases' => array(
-      'title' => t('Administer URL aliases'),
-      'description' => t('Manage URL aliases across the entire website.'),
-    ),
-    'create url aliases' => array(
-      'title' => t('Create URL aliases'),
-      'description' => t('Manage URL aliases on content.'),
-    ),
-  );
+function path_taxonomy_term_delete($term) {
+  // Delete all aliases associated with this term.
+  path_delete(array('source' => 'taxonomy/term/' . $term->tid));
 }
+
