class MaestroWebformTask in Maestro 3.x
Same name and namespace in other branches
- 8.2 modules/maestro_webform/src/Plugin/EngineTasks/MaestroWebformTask.php \Drupal\maestro_webform\Plugin\EngineTasks\MaestroWebformTask
Maestro Webform Task Plugin.
Plugin annotation
@Plugin(
id = "MaestroWebform",
task_description = @Translation("The Maestro Engine's Interactive Webform task."),
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\maestro_webform\Plugin\EngineTasks\MaestroWebformTask implements MaestroEngineTaskInterface uses MaestroTaskTrait
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of MaestroWebformTask
File
- modules/
maestro_webform/ src/ Plugin/ EngineTasks/ MaestroWebformTask.php, line 29
Namespace
Drupal\maestro_webform\Plugin\EngineTasksView source
class MaestroWebformTask extends PluginBase implements MaestroEngineTaskInterface {
// Please see the \Drupal\maestro\MaestroTaskTrait for details on what's included.
use MaestroTaskTrait;
/**
* Constructor.
*
* @param array $configuration
* The incoming configuration information from the engine execution.
* [0] - is the process ID
* [1] - is the queue ID
* The processID and queueID properties are defined in the MaestroTaskTrait.
*/
public function __construct(array $configuration = NULL) {
if (is_array($configuration)) {
$this->processID = $configuration[0];
$this->queueID = $configuration[1];
}
}
/**
* {@inheritDoc}
*/
public function isInteractive() {
/*
* Webform Task type is interactive allowing the end user to interact with the Maestro Task Console..
*/
return TRUE;
}
/**
* {@inheritDoc}
*/
public function shortDescription() {
return $this
->t('Webfom Task');
}
/**
* {@inheritDoc}
*/
public function description() {
return $this
->t('Maestro Interactive Webform Task.');
}
/**
* {@inheritDoc}
*
* @see \Drupal\Component\Plugin\PluginBase::getPluginId()
*/
public function getPluginId() {
// The ID of the plugin. Should match the @id shown in the annotation.
return 'MaestroWebform';
}
/**
* {@inheritDoc}
*/
public function getTaskColours() {
// Using the Blue task box as we've historically used blue for interactive.
return '#0000ff';
}
/**
* Part of the ExecutableInterface
* Execution of the Example task returns TRUE and does nothing else.
* {@inheritdoc}.
*/
public function execute() {
/*
* Setting our run_once flag so that the engine doesn't have to keep trying to process this task.
*/
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($this->queueID);
$queueRecord
->set('run_once', 1);
$queueRecord
->save();
return TRUE;
}
/**
* {@inheritDoc}
*/
public function getExecutableForm($modal, MaestroExecuteInteractive $parent) {
/*
* This will be our base form for displaying the webform submission to the end user through the task console.
*/
$form['#title'] = $this
->t('Submission Review');
// Load the task's configuration so that we can determine which webform and unique identifier this
// particular task will be using.
$templateTask = MaestroEngine::getTemplateTaskByQueueID($this->queueID);
$taskUniqueSubmissionId = $templateTask['data']['unique_id'];
$webformMachineName = $templateTask['data']['webform_machine_name'];
$queueEntry = MaestroEngine::getQueueEntryById($this->queueID);
if ($queueEntry) {
$started_date = intval($queueEntry->started_date
->getString());
$created_date = intval($queueEntry->created
->getString());
// We will set the started date to the FIRST time someone clicks on the execute of the task.
// when we create a task, we set the started_date to the time the entity is created.
if ($started_date - $created_date < 5) {
// There could be some slack between the started date and the created date just due to latency in task and entity creation.
// giving it 5s should be enough time.
$queueEntry
->set('started_date', time());
$queueEntry
->save();
}
}
// Determine if the Webform Task has a node it is attached to set in the task's definition.
// Signals nothing selected.
$webformNode = FALSE;
if (isset($templateTask['data']['use_nodes_attached']) && $templateTask['data']['use_nodes_attached'] == 1) {
// Task has been flagged as requiring the webform node to be utilized.
if (isset($templateTask['data']['webform_nodes_attached_variable']) && $templateTask['data']['webform_nodes_attached_variable'] != 'none') {
// Task is using the process variable to get the node ID. Intval it to ensure it's an integer.
$node_id = intval(MaestroEngine::getProcessVariable($templateTask['data']['webform_nodes_attached_variable'], $this->processID));
$webformNode = 'node/' . $node_id;
}
elseif (isset($templateTask['data']['webform_nodes_attached_to']) && $templateTask['data']['webform_nodes_attached_to'] != 'none') {
// Task is using the selectbox value for which node to show.
$webformNode = $templateTask['data']['webform_nodes_attached_to'];
}
// If we get here without the if/elseif firing, webformNode is FALSE.
}
// Determine if the webform's $taskUniqueSubmissionId exists in the "webforms" process variable.
// If it exists, show it to the user.
// If not, then bring it up to be created.
// Load a webform submission by loading this task's unique identifier.
$sid = MaestroEngine::getEntityIdentiferByUniqueID($this->processID, $taskUniqueSubmissionId);
$webform_submission = NULL;
if ($sid) {
$webform_submission = WebformSubmission::load($sid);
}
if ($webform_submission) {
// We have a submission. Let's now see if we should be showing the edit page.
if (isset($templateTask['data']['show_edit_form']) && $templateTask['data']['show_edit_form'] == 1) {
$url = Url::fromUserInput('/admin/structure/webform/manage/contact/submission/' . $sid . '/edit', [
'query' => [
'maestro' => 1,
'queueid' => $this->queueID,
],
]);
$response = new RedirectResponse($url
->toString());
return $response;
}
else {
$container = \Drupal::getContainer();
$webformSubmissionViewController = WebformSubmissionViewController::create($container);
$webform_build_view = $webformSubmissionViewController
->view($webform_submission, 'table', $langcode = NULL);
$form['submission_information'] = $webform_build_view['information'];
$form['submission_information']['#open'] = FALSE;
// We just want the submission.
$form['submission_data'] = $webform_build_view['submission'];
}
}
else {
// Not able to retrieve the webform submission.
if ($sid !== FALSE && $sid !== NULL) {
\Drupal::messenger()
->addError(t('The submission attached to this workflow was unable to be fetched.'));
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -15,
];
}
else {
if ($webformNode && $webformNode !== FALSE) {
$url = Url::fromUserInput('/' . $webformNode, [
'query' => [
'maestro' => 1,
'queueid' => $this->queueID,
],
]);
}
else {
$url = Url::fromUserInput('/webform/' . $webformMachineName, [
'query' => [
'maestro' => 1,
'queueid' => $this->queueID,
],
]);
}
$response = new RedirectResponse($url
->toString());
return $response;
}
}
$form['queueID'] = [
'#type' => 'hidden',
'#title' => $this
->t('The queue ID of this task'),
'#default_value' => $this->queueID,
'#description' => $this
->t('queueID'),
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this
->t('Accept'),
];
$form['actions']['reject'] = [
'#type' => 'submit',
'#value' => $this
->t('Reject'),
];
$form['#attached']['library'][] = 'maestro_webform/maestro-webform-css';
// Does the developer/admin wish to attach any custom form elements? Let them do so here:
\Drupal::moduleHandler()
->invokeAll('maestro_webform_submission_form', [
$this->queueID,
&$form,
&$this,
]);
return $form;
}
/**
* {@inheritDoc}
*/
public function handleExecuteSubmit(array &$form, FormStateInterface $form_state) {
$completeTask = TRUE;
$queueID = intval($form_state
->getValue('maestro_queue_id'));
$triggeringElement = $form_state
->getTriggeringElement();
$templateTask = MaestroEngine::getTemplateTaskByQueueID($queueID);
if (strstr($triggeringElement['#id'], 'edit-submit') !== FALSE && $queueID > 0) {
MaestroEngine::completeTask($queueID, \Drupal::currentUser()
->id());
}
else {
// Complete the task, but we'll also flag it as TASK_STATUS_CANCEL
// Let the devs manage the submission as well:
\Drupal::moduleHandler()
->invokeAll('maestro_webform_submission_set_cancel_completion_status', [
$queueID,
&$form,
&$form_state,
$triggeringElement,
&$completeTask,
]);
if ($completeTask) {
MaestroEngine::completeTask($queueID, \Drupal::currentUser()
->id());
MaestroEngine::setTaskStatus($queueID, TASK_STATUS_CANCEL);
}
}
// Redirect based on where the task told us to go.
if (isset($templateTask['data']['redirect_to']) && $templateTask['data']['redirect_to'] != '') {
$response = new TrustedRedirectResponse('/' . $templateTask['data']['redirect_to']);
$form_state
->setResponse($response);
}
else {
$response = new TrustedRedirectResponse('/taskconsole');
$form_state
->setResponse($response);
}
// Let the devs manage the submission as well:
\Drupal::moduleHandler()
->invokeAll('maestro_webform_submission_form_submit', [
$queueID,
&$form,
&$form_state,
$triggeringElement,
]);
}
/**
* {@inheritDoc}
*/
public function getTaskEditForm(array $task, $templateMachineName) {
// let's get all the webforms established in the system.
$webforms = Webform::loadMultiple();
// $webforms is an array where the keys are the machine names of the webform and values are the webform entity.
// the $webform[$key]->title is the human readable name.
$webform_options = [
'' => $this
->t('Please Choose'),
];
foreach ($webforms as $key => $webform) {
$webform_options[$key] = $webform
->get('title');
}
$form['webform_machine_name'] = [
'#type' => 'select',
'#options' => $webform_options,
'#title' => $this
->t('Webform'),
'#description' => $this
->t('The Webform you wish to use when no previous submissions tagged with the Unique Identifier (next field) exist in the workflow.
If a submission exists in the workflow, this field is used to show the webform\'s output.'),
'#default_value' => isset($task['data']['webform_machine_name']) ? $task['data']['webform_machine_name'] : '',
'#required' => TRUE,
'#ajax' => [
'callback' => [
$this,
'fetchNodesAttached',
],
'event' => 'change',
'wrapper' => 'attached-nodes',
'progress' => [
'type' => 'throbber',
'message' => t('Fetching Nodes Attached...'),
],
],
];
$form['unique_id'] = [
'#type' => 'textfield',
'#title' => $this
->t('Unique Identifier'),
'#description' => $this
->t('The name of the key used when tracking the webform content for the maestro process. By default the identifier is "submission".'),
'#default_value' => isset($task['data']['unique_id']) ? $task['data']['unique_id'] : '',
'#required' => TRUE,
];
$form['show_edit_form'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Show the edit form if submission already exists?'),
'#description' => $this
->t('If a webform submission already exists, checking this option will send you to the edit form for the submission rather than the summary.'),
'#default_value' => isset($task['data']['show_edit_form']) ? $task['data']['show_edit_form'] : '0',
];
$form['use_nodes_attached'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Webform attached to a node?'),
'#description' => $this
->t('Is your webform attached to a node?
When checked, signals Maestro that your entry/edit of a webform depends on the node it is attached to.'),
'#default_value' => isset($task['data']['use_nodes_attached']) ? $task['data']['use_nodes_attached'] : '0',
];
$form['nodes_attached'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Webform Attached to Node Settings'),
'#states' => [
'visible' => [
':input[name="use_nodes_attached"]' => [
'checked' => TRUE,
],
],
],
];
$variables = MaestroEngine::getTemplateVariables($templateMachineName);
$options = [];
$options['none'] = $this
->t('Do not use process variable');
foreach ($variables as $variableName => $arr) {
$options[$variableName] = $variableName;
}
$form['nodes_attached']['webform_nodes_attached_variable'] = [
'#type' => 'select',
'#options' => $options,
'#title' => $this
->t('Specify a variable to use that holds a Node ID.'),
'#description' => $this
->t('The variable selected must be populated by a single Node ID which the chosen webform is attached to.'),
'#default_value' => isset($task['data']['webform_nodes_attached_variable']) ? $task['data']['webform_nodes_attached_variable'] : '',
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="use_nodes_attached"]' => [
'checked' => TRUE,
],
],
],
];
// Based on the webform_machine_name, we do an auto-lookup to determine if any nodes are bound to this webform and
// allow the administrator to choose a node to use to show the webform to the end user for editing/creating.
// this alters the webform's URI when presenting add/edit pages.
$options = $this
->_getAttachedNodeOptions(isset($task['data']['webform_machine_name']) ? $task['data']['webform_machine_name'] : '');
$form['nodes_attached']['webform_nodes_attached_to'] = [
'#type' => 'select',
'#title' => $this
->t('Select a Node Attached To Specified Webform'),
'#description' => $this
->t('Enabled when you choose NOT to use a process variable. Listed are the nodes that use the specified webform.'),
'#states' => [
'enabled' => [
':input[name="webform_nodes_attached_variable"]' => [
'value' => 'none',
],
],
],
'#options' => $options,
'#default_value' => isset($task['data']['webform_nodes_attached_to']) ? $task['data']['webform_nodes_attached_to'] : 'none',
'#required' => FALSE,
'#prefix' => '<div id="attached-nodes">',
'#suffix' => '</div>',
];
$form['skip_webform_handlers'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Skip Any Maestro Webform Submission Handlers'),
'#description' => $this
->t('Maestro allows you to spawn a workflow via a Webform submission handler. Check to bypass any Maestro webform submission handlers attached to the webform chosen.'),
'#default_value' => isset($task['data']['skip_webform_handlers']) ? $task['data']['skip_webform_handlers'] : '0',
];
$form['redirect_to'] = [
'#type' => 'textfield',
'#title' => $this
->t('Return Path'),
'#description' => $this
->t('You can specify where your return path should go upon task completion.'),
'#default_value' => isset($task['data']['redirect_to']) ? $task['data']['redirect_to'] : 'taskconsole',
'#required' => TRUE,
];
return $form;
}
/**
* Ajax callback to validate the Webform selection. Generate a list of nodes it's attached to, if any.
*/
public function fetchNodesAttached(array &$form, FormStateInterface $form_state) {
$options = $this
->_getAttachedNodeOptions($form_state
->getValue('webform_machine_name'));
$elem = [
'#type' => 'select',
'#options' => $options,
'#title' => $this
->t('Nodes Attached To selected webform'),
'#description' => $this
->t('Enabled when you choose NOT to use a process variable. Listed are the nodes that use the specified webform.'),
'#description_display' => 'after',
'#states' => [
'enabled' => [
':input[name="webform_nodes_attached_variable"]' => [
'value' => 'none',
],
],
],
'#required' => FALSE,
'#prefix' => '<div id="attached-nodes">',
'#suffix' => '</div>',
];
$renderer = \Drupal::service('renderer');
$response = new AjaxResponse();
$response
->addCommand(new ReplaceCommand('#attached-nodes', $renderer
->render($elem)));
return $response;
}
/**
* {@inheritDoc}
*/
public function validateTaskEditForm(array &$form, FormStateInterface $form_state) {
/*
* Need to validate anything on your edit form? Do that here.
*/
}
/**
* {@inheritDoc}
*/
public function prepareTaskForSave(array &$form, FormStateInterface $form_state, array &$task) {
$task['data']['unique_id'] = $form_state
->getValue('unique_id');
$task['data']['webform_machine_name'] = $form_state
->getValue('webform_machine_name');
// Forcing this task to not be modal.
$task['data']['modal'] = 'notmodal';
$task['data']['skip_webform_handlers'] = $form_state
->getValue('skip_webform_handlers');
$task['data']['webform_nodes_attached_to'] = $form_state
->getValue('webform_nodes_attached_to');
$task['data']['use_nodes_attached'] = $form_state
->getValue('use_nodes_attached');
$task['data']['webform_nodes_attached_variable'] = $form_state
->getValue('webform_nodes_attached_variable');
$task['data']['redirect_to'] = $form_state
->getValue('redirect_to');
$task['data']['show_edit_form'] = $form_state
->getValue('show_edit_form');
}
/**
* {@inheritDoc}
*/
public function performValidityCheck(array &$validation_failure_tasks, array &$validation_information_tasks, array $task) {
// We do a validity check on the template in maestro_webform.module to ensure that the
// template has a webforms process variable when a webform task is present.
}
/**
* {@inheritDoc}
*/
public function getTemplateBuilderCapabilities() {
/*
* We're using the stock edit, draw lines, remove lines and removal task capabilities in the editor.
*/
return [
'edit',
'drawlineto',
'removelines',
'remove',
];
}
/**
* Internal used method to get attached node options.
*/
protected function _getAttachedNodeOptions($webform_machine_name) {
$options = [];
if ($webform_machine_name != '') {
$field_configs = \Drupal::entityTypeManager()
->getStorage('field_config')
->loadByProperties([
'entity_type' => 'node',
]);
$node_types = NodeType::loadMultiple();
$ntypes = [];
$fnames = [];
foreach ($field_configs as $field_config) {
if ($field_config
->get('field_type') === 'webform') {
$bundle = $field_config
->get('bundle');
$ntypes[$bundle] = $node_types[$bundle];
$field_name = $field_config
->get('field_name');
$fnames[$field_name] = $field_name;
}
}
if (count($fnames) > 0) {
$query = \Drupal::entityTypeManager()
->getStorage('node')
->getQuery();
$or = $query
->orConditionGroup();
foreach ($fnames as $field_name) {
$or
->condition($field_name . '.target_id', $webform_machine_name);
}
$query
->condition($or);
$result = $query
->execute();
// The result are now node IDs we can use to add to the options.
$entities = \Drupal::entityTypeManager()
->getStorage('node')
->loadMultiple($result);
foreach ($entities as $id => $node) {
$options['node/' . $id] = $node
->label();
}
}
}
if (count($options)) {
$options = array_merge([
'none' => $this
->t('Not Selected'),
], $options);
}
else {
$options['none'] = $this
->t('No nodes attach this webform');
}
return $options;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
MaestroTaskTrait:: |
protected | property | Default will be that the task completed normally. | |
MaestroTaskTrait:: |
protected | property | The default will be success for the execution status. | |
MaestroTaskTrait:: |
protected | property | The Maestro Process ID. | |
MaestroTaskTrait:: |
protected | property | The Maestro queue ID. | |
MaestroTaskTrait:: |
public | function | Retrieve the core Maestro form edit elements for Assignments and Notifications. | |
MaestroTaskTrait:: |
public | function | Retrieve the core Maestro form edit elements that all tasks MUST adhere to. | |
MaestroTaskTrait:: |
public | function | Returns the value of the completion status protected variable denoting any special completion status condition the task wishes to pass along. | |
MaestroTaskTrait:: |
public | function | Returns the value of the execution status protected variable denoting if the execution of this task is complete. | |
MaestroTaskTrait:: |
public | function | Available for all tasks -- this does the general task construction for us, ensuring we have sanity in the saved Config Entity for the task. Assignments and Notifications are the two main elements this method worries about. | |
MaestroWebformTask:: |
public | function |
Longer description. This generally follows the short Description but can be used to be more descriptive if you
wish to surface this description in a UI element. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Part of the ExecutableInterface
Execution of the Example task returns TRUE and does nothing else.
. Overrides ExecutableInterface:: |
|
MaestroWebformTask:: |
public | function | Ajax callback to validate the Webform selection. Generate a list of nodes it's attached to, if any. | |
MaestroWebformTask:: |
public | function |
Gets the Maestro executable form for a task console. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Overrides PluginBase:: |
|
MaestroWebformTask:: |
public | function |
Returns the task's defined colours. This is useful if you want to let the tasks decide on what colours to paint themselves in the UI. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Method to allow a task to add their own fields to the task edit form. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Returns an array of consistenly keyed array elements that define what this task can do in the template builder.
Elements are:
edit, drawlineto, drawfalselineto, removelines, remove. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Interactive tasks, or tasks that signal themselves as requiring human interaction will have the resulting form submissions
sent to their own handler for processing to determine if the task should be completed or not or to carry out any task
processing… Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Returns TRUE or FALSE to denote if this task has an interactive interface that needs to be shown in the Task Console
and for any other requirements of the task. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Lets the task perform validation on itself. If the task is missing any internal requirements, it can flag itself as having an issue.
Return array MUST be in the format of array(
'taskID' => the task machine name,
'taskLabel'… Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
The specific task's manipulation of the values to save for a template save. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
Get the task's short description. Useful for things like labels. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
public | function |
This method must be called by the template builder in order to validate the form entry values before saving. Overrides MaestroEngineTaskInterface:: |
|
MaestroWebformTask:: |
protected | function | Internal used method to get attached node options. | |
MaestroWebformTask:: |
public | function |
Constructor. Overrides PluginBase:: |
|
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |