3

This question is somewhat similar to How to redirect based on views results? which I think gives me part of the answer I want. Basically my situation is this:

I am migrating from an old xoops system which had its own set of content ids. I want to seamlessly make the switch to this new drupal system, meaning the old urls work, but redirect to their new pathauto equivalents.

By way of explanation, say the old url was /view.php?docid=6252 and the new address should be /pubs/capacity_building_climate_change_impact_assessment which has been generated by pathauto.

I can do a redirect at the web server level to get from /view.php?docid=6252' to/pub/6252`.

I have brought over the legacy document id, as a field on the new nodes, and I have a view working where I can visit /pub/6252 and get the right content. Now I want to make sure that the pathauto url is the definitive one url to rule them all for that particular node. How can I redirect to the proper url based on that url segment matching the legacy document id field in a node. It would be nice if it could be done without bringing all of the overhead of a views lookup into it, but if redirecting from that view is the best way, so be it. Hopefully I can aggressively cache that view since that data should almost never change.

I downloaded the Redirect module, hoping that it provided some of that, especially since it claims integration with the views api, but I didn't immediately see anything helpful there, and there doesn't seem to be any documentation for it.

2 Answers 2

2

Non-Views Answer

I finally figured out how this can be done without incurring the overhead of views. I'll leave the views answer below in case it is useful for someone, but this version seems snappier to me. As always, critique very welcome!

/**
 * Implements hook_menu().
 */
function MYMODULE_menu()
{
    $items = array();
    $items['pub'] = array(
        'title' => 'publications by Docid',
        'access callback' => TRUE,
        'page callback' => '_MYMODULE_pub_to_docid',
    );
    return $items;
}


/**
 * Redirect to a publication page based on its legacy_docid
 */
function _MYMODULE_pub_to_docid() {
    $path = current_path();
    $path = str_ireplace('pub/', '', $path);
    $args = explode('/', $path);
    $query = new EntityFieldQuery();
    if (_MYMODULE_isInteger($args[0])) { // Sanity check, local helper function just to check that the value is an integer.
        $query->entityCondition('entity_type', 'node')
            ->fieldCondition('field_doc_legacy_docid', 'value', $args[0]);
        $result = $query->execute();
        if (isset($result['node']) && count($result['node'] == 1)) {
            $node_holder = array_slice($result['node'],0,1)[0];
            $node = node_load($node_holder->nid);
            $language = language_list()[$node->language];
            drupal_goto(drupal_get_path_alias('node/'.$node_holder->nid, $node->language), array('language' => $language), 301);
        } else {
            return MENU_NOT_FOUND;
        }
    }
    return MENU_NOT_FOUND;

}

Views Answer

Here is a views answer, but I'd still like to know if there is a better or preferred way of doing this. I added a function in my_module:

function my_module_views_pre_render(&$view) {

  if ($view->name=='staff_views') { // user redirect
    drupal_goto(drupal_get_path_alias('user/'.$view->result[0]->uid));
  }
  if ($view->name=='pub_by_docid') {
      if (count($view->result) == 1) {
          $node = node_load($view->result[0]->nid);
          $language = language_list()[$node->language];
          drupal_goto(drupal_get_path_alias('node/'.$view->result[0]->nid, $node->language), array('language' => $language), 301);
      }

  }
}

Note that this function is actually redirecting for a view that matches users based on their legacy user id first, and then for a view that matches document id as mentioned originally in my question.

Update: I've updated the code here to reflect the suggestion from J. Reynolds that I include a http response code of 301 to avoid drupals default of 302.

I also found that to get things to work for non-English publications, I needed to add a language option to drupal_goto(), which needs to be a language object. That is the reason for the line creating the $language variable.

3
  • Should you not add an http response code of 301 as well? Default is 302. Commented Mar 29, 2016 at 15:30
  • Yes apologies. Just deleted my comment before I saw your reply. Just wondering if there is no earlier hook you could call and perform a manual SQL lookup on wherein to do the redirect. Commented Mar 30, 2016 at 6:42
  • I'll delete mine too then ;)
    – UltraBob
    Commented Mar 30, 2016 at 7:13
0

You could use the the Rules module to get this to work, together with the Rules URL Argument module. It will make the value of the URL argument available as new variable to Rules. Here is a quote about the Rules URL Argument module (from its project page):

... provides two rules conditions based on URL arguments:

  • check if a URL argument is present.
  • compare the value of an URL argument.

It also provides an action that makes the value of an URL argument available as new variable to Rules.

The newly provided Rules actions and conditions can be found under the "URL Argument" conditions and actions groups in the rule configuration interface.

For an example of how to use it, refer to Comment # 3 in issue # 1686360 which is about "Pass an amount to the url, ie; site/content/node-title?amount=10 or /node-title?=amount:10". Here is the relevant part of it:

  • add a "Check if URL argument exist" condition to your rule and set the "ARGUMENT" value to "amount".
  • add "Provide URL argument value" action to the rule and set "URL ARGUMENT NAME" value to "amount" and in the "Provided variables" section "ARGUMENT FROM URL - Variable name" to e.g. "amount_from_url".

You will now be able to use the amount value as a variable "amount-from-url" for other actions in this rule.

So with that, and specific to your question here, you could make the Rules module perform a redirect of an URL like /view.php?docid=6252 to '/pub/6252'. Combined with your "I have a view working where I can visit /pub/6252 and get the right content." you should be OK to go.

7
  • Thank you for your answer! I guess I left something out of my question, my apologies! I can create a redirect from /view.php?docid=([0-9]+) to /pub/$1 in the web server before the request ever reaches Drupal. The part I need help with is getting from there to the correct alias. I'll edit my question soon!
    – UltraBob
    Commented Mar 29, 2016 at 22:08
  • Even with your extra edit, I still do not understand what your "remaining" question is. Can you try to summarize your question details in like 1 single question? As a variation, can you add an example to your question like "if this happens, and assuming that and that, then I want so and so to happen."? Commented Mar 30, 2016 at 8:01
  • I want a request to /pub/662 to end up at /pub/alias-for-legacy-I'd-662 as efficiently as possible. I want this to happen for all legacy Ids.
    – UltraBob
    Commented Mar 30, 2016 at 8:03
  • If "somebody" performs a request to /pub/682, how do they actually do that (and how do they know that specific link)? Is that link shown in the view you mentioned (on which they click)? Or is there any other way such link is entered? For short: can you add some more details about how the actual request comes in? Commented Mar 30, 2016 at 8:10
  • The request would come in via a redirect in apache. If someone had bookmarked /views.php?docid=682 for example, apache would send that on to /pub/682 at which point drupal would need to do its thing because apache doesn't know anything about the aliases drupal has assigned. (I can easily tell apache to send /views.php?docid=CAPTURE_THIS_INTEGER to /pub/CAPTURED_INTEGER, but I don't know of an easy way for apache to know what alias was assigned.
    – UltraBob
    Commented Mar 30, 2016 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.