Here is what I came up with so far... I am not sure if this is bulletproof. The $op seems to change depending where you are (or maybe who you are) - for example the Content overview the $op is 'view all revisions' for an administrator. In a View listing nodes with operation links, the op is 'update', 'view', 'delete'. I'm unsure when the $op is one thing versus another, but I have:
/**
* Implements hook_node_access().
*/
function mymodule_node_access(NodeInterface $node, $op, $account) {
$type = $node->bundle();
$route = \Drupal::routeMatch()->getRouteName();
if ($type != 'offer_detail_page') {
return AccessResult::neutral();
}
$op_check = [
'update',
'delete',
];
$route_check = [
'entity.node.edit_form',
'entity.node.delete_form',
];
if (!in_array($route, $route_check) && !in_array($op, $op_check)) {
return AccessResult::neutral();
}
// Jump out if user is admin
$admin_roles = [
'administrator',
'content_publisher',
'supplier_author'
];
$user_roles = $account->getRoles();
foreach ($user_roles as $rid) {
if (in_array($rid, $admin_roles)) {
return AccessResult::neutral();
}
}
// Get full account
$account = User::load($account->id());
$user_suppliers = array_column($account->get('field_suppliers')->getValue(), 'target_id');
$node_suppliers = array_column($node->get('field_supplier')->getValue(), 'target_id');
$user_has_suppliers_with_node = array_intersect($user_suppliers, $node_suppliers);
return AccessResult::allowedIf(!empty($user_has_suppliers_with_node))->cachePerUser()->addCacheableDependency($node);
}
This appears to grant edit/delete access to related users at a glance. Is this enough? Am I missing something?
Edit: you also need to enable permission per Content Moderation transition state they should have access to. If they have no transition state access, they will never get the edit button, even if you grant it in code.