Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.234 diff -u -p -r1.234 locale.module --- modules/locale/locale.module 16 Dec 2008 23:57:32 -0000 1.234 +++ modules/locale/locale.module 14 Jan 2009 22:24:31 -0000 @@ -277,6 +277,7 @@ function locale_form_alter(&$form, $form '#title' => t('Language'), '#options' => array('' => t('All languages')) + locale_language_list('name'), '#default_value' => $form['language']['#value'], + '#access' => $form['language']['#access'], '#weight' => -10, '#description' => t('A path alias set for a specific language will always be used when displaying this page in that language, and takes precedence over path aliases set for All languages.'), ); Index: modules/path/path.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v retrieving revision 1.17 diff -u -p -r1.17 path.admin.inc --- modules/path/path.admin.inc 13 Jan 2009 19:27:21 -0000 1.17 +++ modules/path/path.admin.inc 14 Jan 2009 22:24:31 -0000 @@ -30,7 +30,7 @@ function path_admin_overview($keys = NUL } $header = array( array('data' => t('Alias'), 'field' => 'dst', 'sort' => 'asc'), - array('data' => t('System'), 'field' => 'src'), + array('data' => t('System path'), 'field' => 'src'), array('data' => t('Operations'), 'colspan' => '2') ); if ($multilanguage) { @@ -42,6 +42,7 @@ function path_admin_overview($keys = NUL $rows = array(); $destination = drupal_get_destination(); while ($data = db_fetch_object($result)) { + $language = !empty($data->language) ? $data->language : 'all'; $row = array( // If the system path maps to a different URL alias, highlight this table // row to let the user know of old aliases. @@ -49,7 +50,7 @@ function path_admin_overview($keys = NUL 'data' => array( l($data->dst, $data->src), l($data->src, $data->src, array('alias' => TRUE)), - l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), + l(t('edit'), "admin/build/path/edit/$language/$data->pid", array('query' => $destination)), l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination)), ), ); @@ -71,126 +72,201 @@ function path_admin_overview($keys = NUL } /** - * Menu callback; handles pages for creating and editing URL aliases. + * Menu callback; Return a form for editing or creating an individual URL alias. + * + * @ingroup forms + * @see path_admin_form_validate() + * @see path_admin_form_submit() */ -function path_admin_edit($pid = 0) { - if ($pid) { - $alias = path_load($pid); - drupal_set_title($alias['dst']); - $output = drupal_get_form('path_admin_form', $alias); +function path_admin_form(&$form_state, $language = '', $path = array('src' => '', 'dst' => '', 'language' => '', 'pid' => NULL)) { + $aliases = array(); + $form = array(); + + if (isset($language) && module_exists('locale')) { + $language = ($language == 'all' ? '' : $language); } else { - $output = drupal_get_form('path_admin_form'); + $language = NULL; } - return $output; -} + if (!empty($path['pid']) && $path_data = path_load(NULL, $path['src'], $language)) { + $aliases = $path_data; + } -/** - * Return a form for editing or creating an individual URL alias. - * - * @ingroup forms - * @see path_admin_form_validate() - * @see path_admin_form_submit() - */ -function path_admin_form(&$form_state, $edit = array('src' => '', 'dst' => '', 'language' => '', 'pid' => NULL)) { + $field_prefix = url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='); - $form['#alias'] = $edit; + $form['#alias'] = $path; $form['src'] = array( '#type' => 'textfield', - '#title' => t('Existing system path'), - '#default_value' => $edit['src'], + '#title' => t('System path'), + '#default_value' => !empty($path['src']) ? $path['src'] : '', '#maxlength' => 128, '#size' => 45, '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.'), - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='), + '#field_prefix' => $field_prefix, '#required' => TRUE, ); - $form['dst'] = array( + + if (count($aliases)) { + // Disable system path field when editing. + foreach ($aliases as $alias) { + $form['alias'][$alias['pid']] = array( + '#type' => 'textfield', + '#title' => '', + '#default_value' => $alias['dst'], + '#maxlength' => 128, + '#size' => 45, + '#field_prefix' => $field_prefix, + ); + } + } + else { + $form['src']['#description'] = t('Specify the existing path which you wish to alias. For example: node/28, taxonomy/term/12.'); + } + + $form['new'] = array( '#type' => 'textfield', - '#title' => t('Path alias'), - '#default_value' => $edit['dst'], + '#title' => t('New path alias'), '#maxlength' => 128, '#size' => 45, - '#description' => t('Specify an alternative path by which this data 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.'), - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='), - '#required' => TRUE, + '#required' => empty($path['pid']), + '#weight' => 1, + '#description' => t('Specify an alternative path by which this data can be accessed. For example: about, faq, etc.'), + '#field_prefix' => $field_prefix, ); - // This will be a hidden value unless locale module is enabled + + // This will be hidden unless locale module is enabled. $form['language'] = array( '#type' => 'value', - '#value' => $edit['language'] + '#value' => !empty($language) ? $language : '', + '#access' => empty($path['pid']), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), ); - if ($edit['pid']) { - $form['pid'] = array('#type' => 'hidden', '#value' => $edit['pid']); - $form['submit'] = array('#type' => 'submit', '#value' => t('Update alias')); - } - else { - $form['submit'] = array('#type' => 'submit', '#value' => t('Create new alias')); - } + $form['alias']['#tree'] = TRUE; return $form; } +/** + * Theme the path creating and editing form. + */ +function theme_path_admin_form($form) { + $rows = array(); + $header = array(t('Aliases')); + + $output = theme('table', array(), array(array(drupal_render($form['src'])))); + + if (count(element_children($form['alias']))) { + foreach (element_children($form['alias']) as $key) { + $rows[] = array( + drupal_render($form['alias'][$key]), + ); + } + $output .= theme('table', $header, $rows); + } + $output .= theme('table', array(), array(array(drupal_render($form['new'])))); + $output .= drupal_render($form); + + return $output; +} /** * Verify that a new URL alias is valid */ function path_admin_form_validate($form, &$form_state) { - $src = $form_state['values']['src']; - $dst = $form_state['values']['dst']; - $pid = isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0; - // Language is only set if locale module is enabled, otherwise save for all languages. - $language = isset($form_state['values']['language']) ? $form_state['values']['language'] : ''; + $form_values = $form_state['values']; + $src = !empty($form_values['src']) ? $form_values['src'] : NULL; - if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $dst, $language))) { - form_set_error('dst', t('The alias %alias is already in use in this language.', array('%alias' => $dst))); - } $item = menu_get_item($src); if (!$item || !$item['access']) { - form_set_error('src', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $src))); + form_set_error('alias][0', t("The path '@link_path' is invalid.", array('@link_path' => $src))); } + + // Language is only set if locale module is enabled, otherwise save for all languages. + $language = isset($form_values['language']) ? $form_values['language'] : ''; + + // Validate new alias value. + $form_values['alias']['new'] = $form_values['new']; + if (!empty($form_values['alias'])) { + $locale_exists = module_exists('locale'); + foreach ($form_values['alias'] as $pid => $alias) { + $query = "SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s'"; + if ($locale_exists) { + $result = db_result(db_query($query . " AND language = '%s'", $pid, $alias, $language)); + } + else { + $result = db_result(db_query($query, $pid, $alias)); + } + if ($result) { + $error = $locale_exists ? t('The alias %alias is already in use in this language.', array('%alias' => $alias)) : t('The alias %alias is already in use.', array('%alias' => $alias)); + form_set_error('alias]['. $pid, $error); + } + } + } + unset($form_values['alias']['new']); } /** * Save a new URL alias to the database. */ function path_admin_form_submit($form, &$form_state) { - // Language is only set if locale module is enabled - path_set_alias($form_state['values']['src'], $form_state['values']['dst'], isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0, isset($form_state['values']['language']) ? $form_state['values']['language'] : ''); + $form_values = $form_state['values']; + $src = !empty($form_values['src']) ? $form_values['src'] : NULL; + $new = !empty($form_values['new']) ? $form_values['new'] : NULL; - drupal_set_message(t('The alias has been saved.')); - $form_state['redirect'] = 'admin/build/path'; + // Language is only set if locale module is enabled, otherwise save for all languages. + $language = isset($form_values['language']) ? $form_values['language'] : ''; + + if (!empty($form_values['alias'])) { + foreach ($form_values['alias'] as $pid => $alias) { + if (!empty($alias)) { + path_set_alias($src, $alias, $pid, $language); + } + else { + path_delete($pid); + } + } + drupal_clear_path_cache(); + } + + if (!empty($new)) { + path_set_alias($src, $new, NULL, $language); + } + menu_rebuild(); + drupal_set_message(t('The aliases have been saved.')); + + $pid = db_result(db_query("SELECT MAX(pid) FROM {url_alias} WHERE src = '%s'", $src)); + $language = !empty($language) ? $language : 'all'; + $form_state['redirect'] = 'admin/build/path' . (!empty($pid) ? "/edit/$language/$pid" : ''); return; } /** * Menu callback; confirms deleting an URL alias */ -function path_admin_delete_confirm($form_state, $pid) { - $path = path_load($pid); +function path_admin_delete_confirm(&$form_state, $path) { if (user_access('administer url aliases')) { - $form['pid'] = array('#type' => 'value', '#value' => $pid); + $form['pid'] = array('#type' => 'value', '#markup' => $path['pid']); $output = confirm_form($form, t('Are you sure you want to delete path alias %title?', array('%title' => $path['dst'])), isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/path'); } return $output; } - /** * Execute URL alias deletion */ function path_admin_delete_confirm_submit($form, &$form_state) { if ($form_state['values']['confirm']) { - path_admin_delete($form_state['values']['pid']); - $form_state['redirect'] = 'admin/build/path'; - return; + path_delete($form['pid']['#markup']); + drupal_set_message(t('The alias has been deleted.')); } } - /** * Return a form to filter URL aliases. * @@ -239,7 +315,6 @@ function path_admin_filter_form_submit_r $form_state['redirect'] = 'admin/build/path/list'; } - /** * Helper function for grabbing filter keys. */ Index: modules/path/path.module =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.module,v retrieving revision 1.152 diff -u -p -r1.152 path.module --- modules/path/path.module 9 Dec 2008 11:30:24 -0000 1.152 +++ modules/path/path.module 14 Jan 2009 22:24:32 -0000 @@ -30,6 +30,17 @@ function path_help($path, $arg) { } /** + * Implementation of hook_theme(). + */ +function path_theme() { + return array( + 'path_admin_form' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + +/** * Implementation of hook_menu(). */ function path_menu() { @@ -39,16 +50,51 @@ function path_menu() { 'page callback' => 'path_admin_overview', 'access arguments' => array('administer url aliases'), ); + $items['admin/build/path/%menu_tail'] = array( + 'page callback' => 'path_admin_overview', + 'access arguments' => array('administer url aliases'), + ); $items['admin/build/path/edit'] = array( 'title' => 'Edit alias', - 'page callback' => 'path_admin_edit', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('path_admin_form'), 'access arguments' => array('administer url aliases'), 'type' => MENU_CALLBACK, ); - $items['admin/build/path/delete'] = array( + if (module_exists('locale')) { + $items['admin/build/path/edit/all/%path'] = array( + 'title' => 'All languages', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('path_admin_form', 4, 5), + 'access arguments' => array('administer url aliases'), + 'type' => MENU_LOCAL_TASK, + 'weight' => -1, + ); + foreach (locale_language_list('name') as $key => $language) { + $items['admin/build/path/edit/' . $key . '/%path'] = array( + 'title' => '!language', + 'title arguments' => array('!language' => $language), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('path_admin_form', 4, 5), + 'access arguments' => array('administer url aliases'), + 'type' => MENU_LOCAL_TASK, + ); + } + } + else { + $items['admin/build/path/edit/%/%path'] = array( + 'title' => 'All languages', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('path_admin_form', 4, 5), + 'access arguments' => array('administer url aliases'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -1, + ); + } + $items['admin/build/path/delete/%path'] = array( 'title' => 'Delete alias', 'page callback' => 'drupal_get_form', - 'page arguments' => array('path_admin_delete_confirm'), + 'page arguments' => array('path_admin_delete_confirm', 4), 'access arguments' => array('administer url aliases'), 'type' => MENU_CALLBACK, ); @@ -59,7 +105,8 @@ function path_menu() { ); $items['admin/build/path/add'] = array( 'title' => 'Add alias', - 'page callback' => 'path_admin_edit', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('path_admin_form'), 'access arguments' => array('administer url aliases'), 'type' => MENU_LOCAL_TASK, ); @@ -68,11 +115,27 @@ function path_menu() { } /** - * Post-confirmation; delete an URL alias. + * Post-confirmation; delete a URL alias. */ -function path_admin_delete($pid = 0) { - db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid); - drupal_set_message(t('The alias has been deleted.')); +function path_delete($pid = NULL, $src = '', $language = NULL) { + // Delete based on path ID. + if (isset($pid) && is_numeric($pid)) { + db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid); + } + // Delete based on system path. + else if (!empty($src)) { + // Let the user delete aliases based on an empty (not every), or + // a particular language. + if ($language !== NULL) { + // Delete for a specified language. e.g. 'en', 'de', or even ''. + db_query("DELETE FROM {url_alias} WHERE src = '%s' AND language = '%s'", $src, $language); + } + else { + // Delete for every language. e.g. 'en', 'de', AND even ''. + db_query("DELETE FROM {url_alias} WHERE src = '%s'", $src); + } + } + drupal_clear_path_cache(); } /** @@ -166,7 +229,15 @@ function path_nodeapi_insert($node) { function path_nodeapi_update($node) { if (user_access('create url aliases') || user_access('administer url aliases')) { $language = isset($node->language) ? $node->language : ''; - path_set_alias('node/' . $node->nid, isset($node->path) ? $node->path : NULL, isset($node->pid) ? $node->pid : NULL, $language); + $pid = isset($node->pid) ? $node->pid : NULL; + if (!empty($node->path)) { + // Update alias data. + path_set_alias("node/$node->nid", $node->path, $pid, $language); + } + else if (!empty($pid)) { + // Delete the alias if path was emptied. + path_delete($pid); + } } } @@ -178,7 +249,7 @@ function path_nodeapi_delete($node) { $language = isset($node->language) ? $node->language : ''; $path = 'node/' . $node->nid; if (drupal_get_path_alias($path) != $path) { - path_set_alias($path); + path_delete(NULL, $path); } } } @@ -233,6 +304,25 @@ function path_perm() { /** * Fetch a specific URL alias from the database. */ -function path_load($pid) { - return db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid)); +function path_load($pid = NULL, $src = '', $language = NULL) { + $output = ''; + if (isset($pid) && is_numeric($pid)) { + $output = db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid)); + } + else if (!empty($src)) { + // Let the user load aliases based on an empty (not every), or + // a particular language. + if ($language !== NULL) { + // Load for a specified language. e.g. 'en', 'de', or even ''. + $result = db_query("SELECT * FROM {url_alias} WHERE src = '%s' AND language = '%s' ORDER BY pid", $src, $language); + } + else { + // Load for every language. e.g. 'en', 'de', AND even ''. + $result = db_query("SELECT * FROM {url_alias} WHERE src = '%s' ORDER BY pid", $src); + } + while ($row = db_fetch_array($result)) { + $output[] = $row; + } + } + return $output; } Index: modules/path/path.test =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.test,v retrieving revision 1.6 diff -u -p -r1.6 path.test --- modules/path/path.test 9 Jan 2009 07:44:00 -0000 1.6 +++ modules/path/path.test 14 Jan 2009 22:24:32 -0000 @@ -30,22 +30,23 @@ class PathTestCase extends DrupalWebTest // Create alias. $edit = array(); $edit['src'] = 'node/' . $node1->nid; - $edit['dst'] = $this->randomName(8); - $this->drupalPost('admin/build/path/add', $edit, t('Create new alias')); + $edit['new'] = $this->randomName(8); + $this->drupalPost('admin/build/path/add', $edit, t('Save')); // Confirm that the alias works. - $this->drupalGet($edit['dst']); + $this->drupalGet($edit['new']); $this->assertText($node1->title, 'Alias works.'); // Change alias. - $pid = $this->getPID($edit['dst']); + $pid = $this->getPID($edit['new']); - $previous = $edit['dst']; - $edit['dst'] = $this->randomName(8); - $this->drupalPost('admin/build/path/edit/' . $pid, $edit, t('Update alias')); + $previous = $edit['new']; + $edit['alias[' . $pid . ']'] = $edit['new'] = $this->randomName(8); + $this->drupalPost('admin/build/path/edit/all/' . $pid, $edit, t('Save')); + unset($edit['alias[' . $pid . ']']); // Confirm that the alias works. - $this->drupalGet($edit['dst']); + $this->drupalGet($edit['new']); $this->assertText($node1->title, 'Changed alias works.'); // Confirm that previous alias no longer works. @@ -58,17 +59,17 @@ class PathTestCase extends DrupalWebTest // Set alias to second test node. $edit['src'] = 'node/' . $node2->nid; - // leave $edit['dst'] the same - $this->drupalPost('admin/build/path/add', $edit, t('Create new alias')); + // leave $edit['new'] the same + $this->drupalPost('admin/build/path/add', $edit, t('Save')); // Confirm no duplicate was created. - $this->assertRaw(t('The alias %alias is already in use in this language.', array('%alias' => $edit['dst'])), 'Attempt to move alias was rejected.'); + $this->assertRaw(t('The alias %alias is already in use', array('%alias' => $edit['new'])), 'Attempt to move alias was rejected.'); // Delete alias. $this->drupalPost('admin/build/path/delete/' . $pid, array(), t('Confirm')); // Confirm that the alias no longer works. - $this->drupalGet($edit['dst']); + $this->drupalGet($edit['new']); $this->assertNoText($node1->title, 'Alias was successfully deleted.'); }