Creating a very specific custom Views argument handler I've been employed to help fix and finish a D6 site. It's already late so any answers like "you need to change the underlying DB structure" - well, we can't we're stuck with it. (It was built by idiots and we're doing the best we can.)

This is for an educational establishment with a curriculum that has changed in the past (we're migrating from an older system and all the data has to come over) and will change in the future. Each version of the curriculum has a version number. Every student is on one of those versions depending on when they started, so they are all active.

There's a taxonomy term for each of the three versions (D6 remember) which is attached to each Course Module. Each user has a User Profile node which has the user's version.

I am trying to create a Views 3 argument handler which takes a user's UID and delivers the NIDs of all the Course Modules tagged with it.

UID -> User Profile node -> TID -> Course Module NIDs

The complexity comes for example where the TID must be from the Version taxonomy (user profile's have other tags).

Now I accept I may be overthinking this, maybe it can be done with relationships, but I feel using this would be so much easier to understand for any future developers because the views concerned are complicated and already have lots of relationships in them.

A solution would be great (I know, presumptuous) but I have contributed quite a bit to the community including modules and bug-fixes (lots on Search API last year). I have produced Views handlers before but it's never easy, and I have read most if not all the various websites and documentation.

Any help would be much appreciated.
Well this is what I ended up with, it's not entirely pretty - and I've never really grasped how the Views structure works, but it works.

/**
 * Implementation of hook_views_data().
 */
function msc_cc_vc_views_data() {
  return array('msc_cc_vc' =&gt; array(
    'table' =&gt; array(
      'group' =&gt; t('MSC Version Control'),
      'base' =&gt; array(
        'title' =&gt; t('MSC Version Control'),
      ),
      'join' =&gt; array(
        'node' =&gt; array(
          // links directly to node via vid
          'table' =&gt; 'node',
          'left_table' =&gt; 'node',
          'left_field' =&gt; 'vid',
          'field' =&gt; 'vid',
        ),
      ),
    ),
    'users_version_tid' =&gt; array(
      'title' =&gt; t('User\'s Version Term ID'),
      'help' =&gt; t('The taxonomy term ID (from the Version vocabulary) of the supplied user UID.'),
      'argument' =&gt; array(
        'field' =&gt; 'uid',
        'handler' =&gt; 'msc_cc_vc_views_handler_argument_users_version',
        'numeric' =&gt; TRUE,
      ),
    ),
  ));
}

/**
 * Implementation of hook_views_handlers().
 */
function msc_cc_vc_views_handlers() {
  return array(
    'info' =&gt; array(
      'path' =&gt; drupal_get_path('module', 'msc_cc_vc') . '/views',
    ),
    'handlers' =&gt; array(
      // argument handlers
      'msc_cc_vc_views_handler_argument_users_version' =&gt; array(
        'parent' =&gt; 'views_handler_argument_many_to_one',
      ),
      // field handlers
      // filter handlers
      // relationship handlers
      // sort handlers
    ),
  );
}


And then the handler itself. Here I have hard-coded the Taxonomy VID because for this application it doesn't matter. You could steal the code for selecting vocabularies from other handlers, you might also want to allow multiple TIDs.

class msc_cc_vc_views_handler_argument_users_version extends views_handler_argument_many_to_one {

  /**
   * Called to implement a relationship in a query.
   */
  function query() {
    $this-&gt;ensure_my_table();

    // This is the supplied UID
    $uid = $this-&gt;value[0];

    // Not great Drupal but let's do some easy processing:
    $profile = content_profile_load('profile', $uid);
    $terms = taxonomy_node_get_terms_by_vocabulary($profile, 8);
    $version  = reset($terms);
    if (empty($version)) {
      drupal_set_message(t('The selected user does not have curriculum version.'), 'warning');
      return;
    }

    $def = $this-&gt;definition;

    // Rebuild the definition to create a unique relationship
    // that forces all results to have the selected version TID.

    $def['table'] = 'term_data';
    $def['type'] = 'INNER';
    $def['left_table'] = $this-&gt;table_alias;
    $def['left_field'] = 'vid';
    $def['field'] = 'revision';

    $def['table formula'] = "(SELECT td.*, tn.vid AS revision FROM {term_data} td INNER JOIN {term_node} tn ON tn.tid = td.tid WHERE td.tid={$version-&gt;tid})";

    $join = new views_join();

    $join-&gt;definition = $def;
    $join-&gt;construct();
    $join-&gt;adjusted = TRUE;

    // use a short alias for this:
    $alias = $def['table'] . '_' . $this-&gt;table;

    $this-&gt;alias = $this-&gt;query-&gt;add_relationship($alias, $join, 'term_data', $this-&gt;relationship);
  }
}


Enjoy.