More on modifying entity access queries in Drupal Commerce

This is a short follow up to a previous post that covered how to alter access restriction queries for Drupal Commerce entities.  This includes situations where you want to show information in a View but need to provide an alternate logic for allowing access to view the results.

My previous post details a function that utilizes hook_query_TAG_alter to include some checks to determine whether a certain “salesperson” should be able view line items in orders created by another user.  In my particular site, the association of the salesperson to an order is achieved through a reference to the salesperson user on a custom customer profile that is associated with the order.  (In Drupal Commerce, customer profiles are entities used primarily to identify billing and shipping addresses associated with the order.)  The relationship in my store is illustrated below:

 

A simple model illustrating how salesperson is referenced by a field added to a custom customer profile.
A simple model illustrating how salesperson is referenced by a field added to a custom customer profile.

 

Thus, for allowing access to line items, I determine the order associated with the first line item, load the associated custom customer profile and then determine whether the salesperson associated with the profile matches the current user in order to provide access.  This is done all within the function.

However for determining access to orders presented in the User Orders view, I can move the burden of this logic within the View itself by utilizing a contributed module, Views Contextual Filters OR.

The User Orders uses one contextual filter argument, the user id of the order owner, in order to determine which summary of orders to show to user.  Access restriction is built into the query to make sure that the current user matches the user id in the argument.  I could conceivably add additional query logic to Join data from the associated Field tables, but this seems pretty complex and something that I could spend a lot of time banging my head on to get to work.

My alternative is to utilize the Views Contextual Filters OR module and add additional contextual filters to be evaluated as alternative criteria for showing orders in the summary.  In my case, not only do I wish to show orders owned by the user, but also any orders where the user is referenced as a salesperson on the custom customer profile associated with the order.  To achieve this, I first add a Relationship to the custom customer profile and then add an additional contextual filter to match the sales representative associated with the custom customer profile.

 

Under the "Advanced" section of the view, I've added a Relationship to my custom customer profile (Customer profile referenced by commerce_customer_customer) and an additional Contextual Filter (Commerce Customer profile: Sales Representative)
Under the “Advanced” section of the view, I add a Relationship to my custom customer profile (Customer profile referenced by commerce_customer_customer) and an additional Contextual Filter (Commerce Customer profile: Sales Representative)

 

I then set the default value of this argument (which will never be specified) to be the same as the first argument buy returning “return $view->args[0];” in the PHP Filter.

 

Here we add aa default contextual filter value for our second filter to match the first argument passed to the view. There will not be a second argument.
Here I add a default contextual filter value for the second filter to match the first argument passed to the view. There is no second argument.

 

With this OR logic included within the View contextual filters, I can now remove the query conditions that would have matched the user_id of the order to the current user.  I implement this within my function that is related to hook_query_TAG_alter.

<?php

function MY_MODULE_query_commerce_order_access_alter(QueryAlterableInterface $query) {
  if (!isset($account) && !$account = $query->getMetaData('account')) {
    global $user;
    $account = $user;
  }
 
  // If the user has the administration permission, nothing to do.
  if (user_access('administer commerce_order entities', $account)) {
    return;
  }
  if (user_access('view customer profile orders')) {
    if ($account->uid == $query->getMetaData('view')->args[0]) { // if user id matches the view argument
      $where =& $query->conditions();
      unset($where[1]); //removes conditional for access to order
    }
  }
}
?>

The end result is User Orders view that provides the order information to salespersons while still providing necessary access restrictions to ensure that each salesperson only sees the orders they are associated with.