Problem/Motivation
When viewing any submission view (/admin/structure/webform/manage/{webform}/submission/{webform_submission}/...) the Salesforce Local Task tab should appear for a Webform that is having it's submissions mapped to a Salesforce Object.
A previous issue fixed an error caused by the code -
https://www.drupal.org/project/salesforce/issues/2960813 β
I'm not sure if something has changed in the latest version of Webforms that is now breaking the code in the Salesforce Mapping UI module or whether it has always been like this?
The problem is because when the parameters are retrieved for the Webform Submission route current() is called and only one of them is returned:
// There must be a better way to get the entity from a route match.
$param = current(\Drupal::routeMatch()->getParameters()->all());
In the case of the Webform Submission View route this returns the view mode string 'html', 'table' etc, or the webform id for the 'Edit', 'Resend', etc as a string. All of which cause the MappedObjectController::access
method to return AccessResult::forbidden().
I assume that this was done to reduce the number of potential false positive access grants when displaying the link on a route that has multiple parameters, one of which may be a mapped entity?
For us however where we are only mapping webform submissions to Salesforce objects it breaks the adding of the additional link tasks. You can still access the Salesforce Mapped Object page through the operations in the webform listing but that is less user friendly when reviewing submissions.
Steps to reproduce
Map a Salesforce Object to a Webform's Webform Submission.
View the results page for that Webform - the Salesforce link will appear in Operations.
View a Submission page itself and the Salesforce task will not appear alongside the 'View', 'Edit', 'Resend' tabs.
Proposed resolution
The basic solution we found for this was to take all the route parameters and check them all not just whatever current() returns.
// There must be a better way to get the entity from a route match.
$params = \Drupal::routeMatch()->getParameters()->all();
if (!is_array($params)) {
$params = [$params];
}
foreach ($params as $param) {
if (!is_object($param)) {
continue;
}
$implements = class_implements($param);
if (empty($implements['Drupal\Core\Entity\EntityInterface'])) {
continue;
}
// Only allow access for entities with mappings.
if ( $this->entityTypeManager()
->getStorage('salesforce_mapping')
->loadByEntity($param)
) {
return AccessResult::allowed();
}
}
return AccessResult::forbidden();