View source
<?php
namespace Drupal\maestro\Engine;
use Drupal\maestro\Engine\Exception\MaestroGeneralException;
use Drupal\maestro\Engine\Exception\MaestroSaveEntityException;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\user\Entity\User;
use Drupal\Core\Url;
class MaestroEngine {
protected $debug;
protected $developmentMode = FALSE;
protected $version = 2;
public function __construct() {
$this->debug = FALSE;
$this->developmentMode = FALSE;
}
public function enableDebug() {
$this->debug = TRUE;
}
public function disableDebug() {
$this->debug = FALSE;
}
public function getDebug() {
return $this->debug;
}
public function enableDevelopmentMode() {
$this->developmentMode = TRUE;
}
public function disableDevelopmentMode() {
$this->developmentMode = FALSE;
}
public function getDevelopmentMode() {
return $this->developmentMode;
}
public static function getTemplates() {
$entity_store = \Drupal::entityTypeManager()
->getStorage('maestro_template');
return $entity_store
->loadMultiple();
}
public static function getTemplate($machine_name) {
$entity_store = \Drupal::entityTypeManager()
->getStorage('maestro_template');
$maestro_template = $entity_store
->load($machine_name);
return $maestro_template;
}
public static function getTemplateTaskByID($templateMachineName, $taskID) {
if ($templateMachineName) {
$template = self::getTemplate($templateMachineName);
if ($template) {
return $template->tasks[$taskID];
}
}
return FALSE;
}
public static function getTemplateTaskByQueueID($queueID) {
return MaestroEngine::getTemplateTaskByID(MaestroEngine::getTemplateIdFromProcessId(MaestroEngine::getProcessIdFromQueueId($queueID)), MaestroEngine::getTaskIdFromQueueId($queueID));
}
public static function getTemplateVariables($templateMachineName) {
$template = self::getTemplate($templateMachineName);
return $template->variables;
}
public static function getTemplateIdFromProcessId($processID) {
$processRecord = FALSE;
if ($processID) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
}
if ($processRecord) {
return $processRecord->template_id
->getString();
}
return FALSE;
}
public static function saveTemplateTask($templateMachineName, $taskMachineName, array $task) {
$returnValue = FALSE;
$template = MaestroEngine::getTemplate($templateMachineName);
$taskID = $task['id'];
$template->tasks[$taskID] = $task;
try {
$returnValue = $template
->save();
} catch (EntityStorageException $e) {
$returnValue = FALSE;
}
return $returnValue;
}
public static function removeTemplateTask($templateMachineName, $taskToRemove) {
$returnValue = FALSE;
$template = MaestroEngine::getTemplate($templateMachineName);
$templateTask = MaestroEngine::getTemplateTaskByID($templateMachineName, $taskToRemove);
$pointers = MaestroEngine::getTaskPointersFromTemplate($templateMachineName, $taskToRemove);
$tasks = $template->tasks;
unset($tasks[$taskToRemove]);
foreach ($pointers as $pointer) {
$nextsteps = explode(',', $tasks[$pointer]['nextstep']);
$key = array_search($taskToRemove, $nextsteps);
unset($nextsteps[$key]);
$tasks[$pointer]['nextstep'] = implode(',', $nextsteps);
}
$template->tasks = $tasks;
try {
$returnValue = $template
->save();
} catch (EntityStorageException $e) {
$returnValue = FALSE;
}
return $returnValue;
}
public static function getTaskPointersFromTemplate($templateMachineName, $taskMachineName) {
$template = MaestroEngine::getTemplate($templateMachineName);
$pointers = [];
foreach ($template->tasks as $task) {
$nextSteps = explode(',', $task['nextstep']);
$nextFalseSteps = explode(',', $task['nextfalsestep']);
if (array_search($taskMachineName, $nextSteps) !== FALSE || array_search($taskMachineName, $nextFalseSteps) !== FALSE) {
$pointers[] = $task['id'];
}
}
return $pointers;
}
public static function getTaskIdFromQueueId($queueID) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
if ($queueRecord) {
return $queueRecord->task_id
->getString();
}
return FALSE;
}
public static function getProcessIdFromQueueId($queueID) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
if ($queueRecord) {
return $queueRecord->process_id
->getString();
}
return FALSE;
}
public static function getProcessVariable($variableName, $processID) {
$query = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->getQuery();
$query
->condition('process_id', $processID)
->condition('variable_name', $variableName);
$entity_ids = $query
->execute();
$val = FALSE;
if (count($entity_ids) > 0) {
$entityID = current($entity_ids);
\Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->resetCache([
$entityID,
]);
$processVariableRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->load($entityID);
$val = $processVariableRecord->variable_value
->getString();
}
return $val;
}
public static function setProcessVariable($variableName, $variableValue, $processID) {
$query = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->getQuery();
$query
->condition('process_id', $processID)
->condition('variable_name', $variableName);
$varID = $query
->execute();
if (count($varID) > 0) {
$varRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->load(current($varID));
$varRecord
->set('variable_value', $variableValue);
$varRecord
->save();
$query = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->getQuery();
$query
->condition('process_variable', $varID)
->condition('by_variable', '1')
->condition('task_completed', '0');
$entries = $query
->execute();
$engine = new MaestroEngine();
$storeAssignmentInfo = [];
foreach ($entries as $assignmentID) {
$assignRecord = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->load($assignmentID);
$queueID = $assignRecord->queue_id
->getString();
$processID = MaestroEngine::getProcessIdFromQueueId($queueID);
$taskID = MaestroEngine::getTaskIdFromQueueId($queueID);
$templateMachineName = MaestroEngine::getTemplateIdFromProcessId($processID);
$storeAssignmentInfo[$queueID] = [
'templateMachineName' => $templateMachineName,
'taskID' => $taskID,
];
$assignRecord
->delete();
}
foreach ($storeAssignmentInfo as $queueID => $assingmentInfo) {
$engine
->productionAssignments($assingmentInfo['templateMachineName'], $assingmentInfo['taskID'], $queueID);
}
\Drupal::moduleHandler()
->invokeAll('maestro_post_variable_save', [
$variableName,
$variableValue,
$processID,
]);
}
}
public static function getProcessVariableID($variableName, $processID) {
$query = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->getQuery();
$query
->condition('process_id', $processID)
->condition('variable_name', $variableName);
$entity_ids = $query
->execute();
$val = FALSE;
if (count($entity_ids) > 0) {
$entityID = current($entity_ids);
$varRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->resetCache([
$entityID,
]);
$varRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->load($entityID);
$val = $varRecord->id
->getString();
}
return $val;
}
public static function setProductionTaskLabel($queueID, $taskLabel) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$queueRecord
->set('task_label', $taskLabel);
$queueRecord
->save();
}
public static function completeTask($queueID, $userID = 0) {
$task_completion_time = time();
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$queueRecord
->set('status', TASK_STATUS_SUCCESS);
$queueRecord
->set('uid', $userID);
$queueRecord
->set('completed', $task_completion_time);
$queueRecord
->save();
$query = \Drupal::entityQuery('maestro_production_assignments');
$query
->condition('queue_id', $queueID);
$assignmentIDs = $query
->execute();
foreach ($assignmentIDs as $assignmentID) {
$assignmentRecord = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->load($assignmentID);
$assignmentRecord
->set('task_completed', 1);
$assignmentRecord
->save();
}
$task = MaestroEngine::getTemplateTaskByQueueID($queueID);
if (isset($task['participate_in_workflow_status_stage']) && $task['participate_in_workflow_status_stage'] == 1) {
$process_id = MaestroEngine::getProcessIdFromQueueId($queueID);
$query = \Drupal::entityQuery('maestro_process_status')
->condition('process_id', $process_id)
->condition('stage_number', $task['workflow_status_stage_number']);
$statusEntityIDs = $query
->execute();
foreach ($statusEntityIDs as $entity_id) {
$statusRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process_status')
->load($entity_id);
if ($statusRecord) {
$statusRecord
->set('completed', $task_completion_time);
$statusRecord
->save();
}
}
}
}
public static function setTaskStatus($queueID, $status = TASK_STATUS_SUCCESS) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$queueRecord
->set('status', $status);
$queueRecord
->save();
}
public static function archiveTask($queueID) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$queueRecord
->set('archived', 1);
$queueRecord
->save();
}
public static function unArchiveTask($queueID) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$queueRecord
->set('archived', 0);
$queueRecord
->save();
}
public static function endProcess($processID) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
$processRecord
->set('complete', PROCESS_STATUS_COMPLETED);
$processRecord
->set('completed', time());
$processRecord
->save();
}
public static function abortProcess($processID) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
$processRecord
->set('complete', PROCESS_STATUS_ABORTED);
$processRecord
->set('completed', time());
$processRecord
->save();
}
public static function setProcessLabel($processID, $processLabel) {
if ($processLabel) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
$processRecord
->set('process_name', $processLabel);
$processRecord
->save();
}
}
public static function getAssignedTaskQueueIds($userID) {
\Drupal::entityTypeManager()
->getViewBuilder('maestro_production_assignments')
->resetCache();
$account = User::load($userID);
$userRoles = $account
->getRoles(TRUE);
$query = \Drupal::entityQuery('maestro_production_assignments');
$andConditionByUserID = $query
->andConditionGroup()
->condition('assign_id', $account
->getAccountName())
->condition('assign_type', 'user');
$orConditionAssignID = $query
->orConditionGroup()
->condition($andConditionByUserID);
$roleAND = NULL;
foreach ($userRoles as $userRole) {
$roleAND = $query
->andConditionGroup()
->condition('assign_id', $userRole)
->condition('assign_type', 'role');
$orConditionAssignID
->condition($roleAND);
}
$query
->condition($orConditionAssignID);
$query
->condition('task_completed', '0');
$assignmentIDs = $query
->execute();
$queueIDs = [];
foreach ($assignmentIDs as $entity_id) {
$assignmentRecord = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->load($entity_id);
$queueRecord = self::getQueueEntryById($assignmentRecord->queue_id
->getString());
if ($queueRecord) {
$processRecord = self::getProcessEntryById($queueRecord->process_id
->getString());
if ($queueRecord->status
->getString() == '0' && $queueRecord->archived
->getString() == '0' && $processRecord->complete
->getString() == '0') {
$queueIDs[] = $assignmentRecord->queue_id
->getString();
}
}
}
\Drupal::moduleHandler()
->invokeAll('maestro_post_fetch_assigned_queue_tasks', [
$userID,
&$queueIDs,
]);
return $queueIDs;
}
public static function getQueueEntryById($queueID) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->resetCache([
$queueID,
]);
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
return $queueRecord;
}
public static function getProcessEntryById($processID) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->resetCache([
$processID,
]);
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
return $processRecord;
}
public static function getPluginTask($taskClassName, $processID = 0, $queueID = 0) {
$manager = \Drupal::service('plugin.manager.maestro_tasks');
$plugins = $manager
->getDefinitions();
$task = NULL;
if (array_key_exists($taskClassName, $plugins)) {
$task = $manager
->createInstance($plugins[$taskClassName]['id'], [
$processID,
$queueID,
]);
}
return $task;
}
public static function canUserExecuteTask($queueID, $userID) {
$queueIDs = self::getAssignedTaskQueueIds($userID);
$returnValue = FALSE;
if (array_search($queueID, $queueIDs) !== FALSE) {
$returnValue = TRUE;
}
return $returnValue;
}
public static function getAssignedNamesOfQueueItem($queueID, $associativeArray = FALSE) {
$output = [];
$query = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->getQuery();
$query
->condition('queue_id', $queueID);
$entity_ids = $query
->execute();
if (count($entity_ids) > 0) {
foreach ($entity_ids as $assignmentID) {
$assignRecord = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->load($assignmentID);
$assignRecord->by_variable
->getString() == 0 ? $type = t('Fixed') : ($type = t('Variable'));
if ($associativeArray) {
$output[$assignRecord->assign_id
->getString()] = [
'assign_id' => $assignRecord->assign_id
->getString(),
'by_variable' => $type,
'assign_type' => $assignRecord->assign_type
->getString(),
'id' => $assignRecord->id
->getString(),
];
}
else {
$output[$assignRecord->assign_id
->getString()] = $assignRecord->assign_id
->getString() . ':' . $type;
}
}
}
return $output;
}
public static function getTaskStatusLabel($status) {
$return_status = '';
switch ($status) {
case TASK_STATUS_ACTIVE:
$return_status = t('Active');
break;
case TASK_STATUS_ABORTED:
$return_status = t('Aborted');
break;
case TASK_STATUS_CANCEL:
$return_status = t('Cancelled');
break;
case TASK_STATUS_HOLD:
$return_status = t('On Hold');
break;
case TASK_STATUS_SUCCESS:
$return_status = t('Successfully Completed');
break;
default:
$return_status = t('Unknown');
break;
}
return $return_status;
}
public static function getTaskStatusArray() {
$arr = [];
$arr[TASK_STATUS_ACTIVE] = t('Active');
$arr[TASK_STATUS_SUCCESS] = t('Successfully Completed');
$arr[TASK_STATUS_CANCEL] = t('Cancelled');
$arr[TASK_STATUS_HOLD] = t('On Hold');
$arr[TASK_STATUS_ABORTED] = t('Aborted');
return $arr;
}
public static function getTaskArchiveArray() {
$arr = [];
$arr[TASK_ARCHIVE_ACTIVE] = t('Active');
$arr[TASK_ARCHIVE_NORMAL] = t('Archived');
$arr[TASK_ARCHIVE_REGEN] = t('Regenerated');
return $arr;
}
public static function performTemplateValidityCheck($templateMachineName) {
$template = MaestroEngine::getTemplate($templateMachineName);
$pointers = [];
$endTaskExists = FALSE;
$validation_failure_tasks = [];
$validation_information_tasks = [];
foreach ($template->tasks as $task) {
$pointers = MaestroEngine::getTaskPointersFromTemplate($templateMachineName, $task['id']);
if ($task['tasktype'] !== 'MaestroOr' && $task['tasktype'] !== 'MaestroAnd') {
if (count($pointers) > 1) {
$validation_information_tasks[] = [
'taskID' => $task['id'],
'taskLabel' => $task['label'],
'reason' => t('This task, with two pointers to it, will cause a regeneration to happen. Please see documentation for more information.'),
];
}
}
if ($task['tasktype'] !== 'MaestroStart') {
if (count($pointers) == 0) {
$validation_failure_tasks[] = [
'taskID' => $task['id'],
'taskLabel' => $task['label'],
'reason' => t('Task has no other tasks pointing to it. Only the Start Task is allowed to have no tasks pointing to it.'),
];
}
}
if ($task['tasktype'] === 'MaestroEnd') {
$endTaskExists = TRUE;
}
$executable_task = NULL;
$executable_task = MaestroEngine::getPluginTask($task['tasktype']);
if ($executable_task != NULL) {
$executable_task
->performValidityCheck($validation_failure_tasks, $validation_information_tasks, $task);
}
}
if (!$endTaskExists) {
$validation_failure_tasks[] = [
'taskID' => t('No Task ID'),
'taskLabel' => t('No Task Label'),
'reason' => t('This template is missing an END Task. Without an END Task, the process will never be flagged as complete.'),
];
}
\Drupal::moduleHandler()
->invokeAll('maestro_template_validation_check', [
$templateMachineName,
&$validation_failure_tasks,
&$validation_information_tasks,
]);
if (count($validation_failure_tasks) == 0) {
$template->validated = TRUE;
}
else {
$template->validated = FALSE;
}
$template
->save();
return [
'failures' => $validation_failure_tasks,
'information' => $validation_information_tasks,
];
}
public static function setTemplateToUnvalidated($templateMachineName) {
$template = MaestroEngine::getTemplate($templateMachineName);
if ($template !== NULL) {
$template->validated = FALSE;
$template
->save();
}
}
public static function createEntityIdentifier($processID, $entityType, $entityBundle, $taskUniqueID, $entityID) {
if (isset($processID) && isset($entityType) && isset($entityBundle) && isset($taskUniqueID) && isset($entityID)) {
$values = [
'process_id' => $processID,
'unique_id' => $taskUniqueID,
'entity_type' => $entityType,
'entity_id' => $entityID,
'bundle' => $entityBundle,
];
$new_entry = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->create($values);
$new_entry
->save();
return $new_entry
->id();
}
return NULL;
}
public static function updateEntityIdentifierByEntityTableID($entityIdentifierID, $entityID = NULL, $entityType = NULL, $entityBundle = NULL, $taskUniqueID = NULL) {
if (isset($entityIdentifierID)) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityIdentifierID);
if ($record) {
if (isset($taskUniqueID)) {
$record
->set('unique_id', $taskUniqueID);
}
if (isset($entityType)) {
$record
->set('entity_type', $entityType);
}
if (isset($entityID)) {
$record
->set('entity_id', $entityID);
}
if (isset($entityBundle)) {
$record
->set('bundle', $entityBundle);
}
$record
->save();
}
}
}
public static function getEntityIdentiferByUniqueID($processID, $taskUniqueID) {
$value = NULL;
$query = \Drupal::entityQuery('maestro_entity_identifiers')
->condition('process_id', $processID)
->condition('unique_id', $taskUniqueID);
$entityID = current($query
->execute());
if ($entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityID);
if ($record) {
$value = $record->entity_id
->getString();
}
}
return $value;
}
public static function getEntityIdentiferFieldsByUniqueID($processID, $taskUniqueID) {
$retArray = [];
$query = \Drupal::entityQuery('maestro_entity_identifiers')
->condition('process_id', $processID)
->condition('unique_id', $taskUniqueID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityID);
if ($record) {
$retArray[$record->unique_id
->getString()] = [
'unique_id' => $record->unique_id
->getString(),
'entity_type' => $record->entity_type
->getString(),
'bundle' => $record->bundle
->getString(),
'entity_id' => $record->entity_id
->getString(),
];
}
}
return $retArray;
}
public static function getEntityIdentiferByIdentifierRowID($rowID) {
$value = NULL;
$query = \Drupal::entityQuery('maestro_entity_identifiers')
->condition('id', $rowID);
$entityID = current($query
->execute());
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityID);
if ($record) {
$value = $record->entity_id
->getString();
}
return $value;
}
public static function getAllEntityIdentifiersForProcess($processID) {
$retArray = [];
$query = \Drupal::entityQuery('maestro_entity_identifiers')
->condition('process_id', $processID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityID);
if ($record) {
$retArray[$record->unique_id
->getString()] = [
'unique_id' => $record->unique_id
->getString(),
'entity_type' => $record->entity_type
->getString(),
'bundle' => $record->bundle
->getString(),
'entity_id' => $record->entity_id
->getString(),
];
}
}
return $retArray;
}
public static function getAllStatusEntriesForProcess($processID) {
$retArray = [];
$query = \Drupal::entityQuery('maestro_process_status')
->condition('process_id', $processID)
->sort('stage_number', 'ASC');
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_process_status')
->load($entityID);
if ($record) {
$retArray[$record->stage_number
->getString()] = [
'message' => $record->stage_message
->getString(),
'completed' => $record->completed
->getString(),
'stage_number' => $record->stage_number
->getString(),
];
}
}
return $retArray;
}
public static function deleteProcess($processID) {
$query = \Drupal::entityQuery('maestro_queue')
->condition('process_id', $processID);
$ids = $query
->execute();
foreach ($ids as $queueID) {
$query = \Drupal::entityQuery('maestro_production_assignments')
->condition('queue_id', $queueID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->load($entityID);
if ($record) {
$record
->delete();
}
}
$queueRecord = MaestroEngine::getQueueEntryById($queueID);
$queueRecord
->delete();
}
$query = \Drupal::entityQuery('maestro_entity_identifiers')
->condition('process_id', $processID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_entity_identifiers')
->load($entityID);
if ($record) {
$record
->delete();
}
}
$query = \Drupal::entityQuery('maestro_process_variables')
->condition('process_id', $processID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->load($entityID);
if ($record) {
$record
->delete();
}
}
$query = \Drupal::entityQuery('maestro_process_status')
->condition('process_id', $processID);
$entityIDs = $query
->execute();
foreach ($entityIDs as $entityID) {
$record = \Drupal::entityTypeManager()
->getStorage('maestro_process_status')
->load($entityID);
if ($record) {
$record
->delete();
}
}
$processRecord = MaestroEngine::getProcessEntryById($processID);
$processRecord
->delete();
}
public function newProcess($templateName, $startTask = 'start') {
$process_id = FALSE;
$template = $this
->getTemplate($templateName);
if (!isset($template->validated) || $template->validated == FALSE) {
if ($this->debug) {
\Drupal::messenger()
->addError(t('This template has not been validated. You must validate before launching.'));
}
return FALSE;
}
if ($template !== NULL) {
$values = [
'process_name' => $template->label,
'template_id' => $template->id,
'complete' => 0,
'initiator_uid' => \Drupal::currentUser()
->id(),
];
$new_process = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->create($values);
$new_process
->save();
if ($new_process
->id()) {
$process_id = $new_process
->id();
$variables = $template->variables;
foreach ($variables as $variable) {
$values = [
'process_id' => $process_id,
'variable_name' => $variable['variable_id'],
'variable_value' => $variable['variable_value'],
];
switch ($variable['variable_id']) {
case 'initiator':
$values['variable_value'] = \Drupal::currentUser()
->getAccountName();
break;
case 'workflow_timeline_stage_count':
$values['variable_value'] = $template->default_workflow_timeline_stage_count;
break;
case 'workflow_current_stage':
$values['variable_value'] = 0;
break;
case 'workflow_current_stage_message':
$values['variable_value'] = '';
break;
}
$new_var = \Drupal::entityTypeManager()
->getStorage('maestro_process_variables')
->create($values);
$new_var
->save();
if (!$new_var
->id()) {
throw new MaestroSaveEntityException('maestro_process_variable', $variable['variable_id'] . ' failed saving during new process creation.');
}
}
$status_message_array = [];
foreach ($template->tasks as $task) {
if (isset($task['participate_in_workflow_status_stage']) && $task['participate_in_workflow_status_stage'] == 1) {
if (isset($task['workflow_status_stage_number'])) {
$status_message_array[$task['workflow_status_stage_number']] = $task['workflow_status_stage_message'];
}
}
}
if (count($status_message_array)) {
foreach ($status_message_array as $stage_number => $stage_message) {
$values = [
'process_id' => $process_id,
'stage_number' => $stage_number,
'stage_message' => $stage_message,
];
$new_stage = \Drupal::entityTypeManager()
->getStorage('maestro_process_status')
->create($values);
$new_stage
->save();
if (!$new_stage
->id()) {
throw new MaestroSaveEntityException('maestro_process_status', 'Stage ' . $variable['stage_number'] . ' status message failed saving during new process creation.');
}
}
}
$start_task = $template->tasks[$startTask];
if (is_array($start_task)) {
$values = [
'process_id' => $process_id,
'task_class_name' => $start_task['tasktype'],
'task_id' => $start_task['id'],
'task_label' => $start_task['label'],
'engine_version' => 2,
'is_interactive' => $start_task['assignto'] == 'engine' ? 0 : 1,
'show_in_detail' => isset($start_task['showindetail']) ? $start_task['showindetail'] : 0,
'handler' => isset($start_task['handler']) ? $start_task['handler'] : '',
'task_data' => isset($start_task['data']) ? $start_task['data'] : '',
'status' => 0,
'run_once' => isset($start_task['runonce']) ? $start_task['runonce'] : 0,
'uid' => \Drupal::currentUser()
->id(),
'archived' => 0,
'started_date' => time(),
];
$queue = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->create($values);
$queue
->save();
if ($queue
->id()) {
$this
->productionAssignments($templateName, $startTask, $queue
->id());
}
else {
throw new MaestroSaveEntityException('maestro_queue', $start_task['tasktype'] . ' failed saving new task during new process creation.');
}
}
else {
throw new MaestroGeneralException('Start task for template ' . $template->id . ' may be corrupt.');
}
}
}
return $process_id;
}
public function cleanQueue() {
$config = \Drupal::config('maestro.settings');
if ($this->debug) {
kint_require();
\Kint::$maxLevels = 0;
}
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '0')
->condition('status', '0')
->condition('is_interactive', '0')
->condition('run_once', '0')
->condition('process_id.entity.complete', '0');
$entity_ids = $query
->execute();
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '0')
->condition('is_interactive', '1')
->condition('status', '0', '<>')
->condition('run_once', '1')
->condition('process_id.entity.complete', '0');
$entity_ids += $query
->execute();
ksort($entity_ids);
foreach ($entity_ids as $queueID) {
if ($this->developmentMode) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->resetCache([
$queueID,
]);
}
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$processID = $queueRecord->process_id
->getString();
if ($this->developmentMode) {
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->resetCache([
$processID,
]);
}
$processRecord = \Drupal::entityTypeManager()
->getStorage('maestro_process')
->load($processID);
$taskClassName = $queueRecord->task_class_name
->getString();
$taskID = $queueRecord->task_id
->getString();
$templateMachineName = $processRecord->template_id
->getString();
if ($processRecord->complete
->getString() == '0') {
$task = $this
->getPluginTask($taskClassName, $processID, $queueID);
if ($task && !$task
->isInteractive()) {
$result = $task
->execute();
if ($result === TRUE) {
$queueRecord
->set('status', $task
->getExecutionStatus());
$queueRecord
->set('completed', time());
$queueRecord
->save();
$this
->nextStep($templateMachineName, $taskID, $processID, $task
->getCompletionStatus());
$this
->archiveTask($queueID);
}
}
else {
if ($task && $task
->isInteractive()) {
$this
->nextStep($templateMachineName, $taskID, $processID, $task
->getCompletionStatus());
$this
->archiveTask($queueID);
}
else {
throw new MaestroGeneralException('Task definition doesn\'t exist. TaskID:' . $taskID . ' in ProcessID:' . $processID . ' is not flagged as interactive or non-interactive.');
}
}
}
}
if ($config
->get('maestro_send_notifications')) {
$currentTime = time();
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '0')
->condition('is_interactive', '1')
->condition('status', '0')
->condition('run_once', '1')
->condition('next_reminder_time', $currentTime, '<')
->condition('next_reminder_time', '0', '<>')
->condition('reminder_interval', '0', '>');
$entity_ids = $query
->execute();
foreach ($entity_ids as $queueID) {
if ($this->developmentMode) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->resetCache([
$queueID,
]);
}
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$taskMachineName = $queueRecord->task_id
->getString();
$templateMachineName = MaestroEngine::getTemplateIdFromProcessId($queueRecord->process_id
->getString());
$reminderInterval = intval($queueRecord->reminder_interval
->getString()) * 86400;
$this
->doProductionAssignmentNotifications($templateMachineName, $taskMachineName, $queueID, 'reminder');
$queueRecord
->set('next_reminder_time', $currentTime + $reminderInterval);
$queueRecord
->set('num_reminders_sent', intval($queueRecord->num_reminders_sent
->getString()) + 1);
$queueRecord
->save();
}
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '0')
->condition('is_interactive', '1')
->condition('status', '0')
->condition('run_once', '1')
->condition('escalation_interval', 0, '>');
$entity_ids = $query
->execute();
foreach ($entity_ids as $queueID) {
if ($this->developmentMode) {
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->resetCache([
$queueID,
]);
}
$queueRecord = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->load($queueID);
$taskMachineName = $queueRecord->task_id
->getString();
$templateMachineName = MaestroEngine::getTemplateIdFromProcessId($queueRecord->process_id
->getString());
$createdTime = $queueRecord->created
->getString();
$numberOfEscalationsSent = intval($queueRecord->num_escalations_sent
->getString());
$escalationInterval = (1 + $numberOfEscalationsSent) * (intval($queueRecord->escalation_interval
->getString()) * 86400);
if ($currentTime > $createdTime + $escalationInterval) {
$this
->doProductionAssignmentNotifications($templateMachineName, $taskMachineName, $queueID, 'escalation');
$queueRecord
->set('last_escalation_time', $currentTime);
$queueRecord
->set('num_escalations_sent', intval($queueRecord->num_escalations_sent
->getString()) + 1);
$queueRecord
->save();
}
}
}
}
protected function nextStep($template, $templateTaskID, $processID, $completionStatus) {
$templateTask = $this
->getTemplateTaskByID($template, $templateTaskID);
$regenerationFlag = FALSE;
$nextSteps = $templateTask['nextstep'];
if ($completionStatus == MAESTRO_TASK_COMPLETION_USE_FALSE_BRANCH) {
$nextSteps = $templateTask['nextfalsestep'];
}
if ($nextSteps != '') {
$taskArray = explode(',', $nextSteps);
foreach ($taskArray as $taskID) {
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', TASK_ARCHIVE_REGEN, '<>')
->condition('status', TASK_STATUS_ACTIVE, '<>')
->condition('process_id', $processID)
->condition('task_id', $taskID)
->condition('task_class_name', 'MaestroOr', '<>')
->condition('task_class_name', 'MaestroAnd', '<>');
$entity_ids = $query
->execute();
if (count($entity_ids) == 0) {
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '0')
->condition('status', TASK_STATUS_ACTIVE)
->condition('process_id', $processID)
->condition('task_id', $taskID);
$entity_ids = $query
->execute();
if (count($entity_ids) == 0) {
$queueID = $this
->createProductionTask($taskID, $template, $processID);
}
}
else {
$noRegenStatusArray = [];
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '1')
->condition('status', '0')
->condition('process_id', $processID)
->condition('task_class_name', 'MaestroAnd');
$andIDs = $query
->execute();
if (is_array($andIDs)) {
$noRegenStatusArray += $andIDs;
}
foreach ($andIDs as $entityID) {
$queueRecord = MaestroEngine::getQueueEntryById($entityID);
$pointers = MaestroEngine::getTaskPointersFromTemplate(MaestroEngine::getTemplateIdFromProcessId($processID), $queueRecord->task_id
->getValue());
$query = \Drupal::entityQuery('maestro_queue');
$andMainConditions = $query
->andConditionGroup()
->condition('process_id', $processID);
$orConditionGroup = $query
->orConditionGroup();
foreach ($pointers as $taskID) {
$orConditionGroup
->condition('task_id', $taskID);
}
$andMainConditions
->condition($orConditionGroup);
$query
->condition($andMainConditions);
$pointerIDs = $query
->execute();
if (is_array($pointerIDs)) {
$noRegenStatusArray += $pointerIDs;
}
}
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('status', '0', '<>')
->condition('process_id', $processID);
$regenIDs = $query
->execute();
foreach ($regenIDs as $entityID) {
if (array_search($entityID, $noRegenStatusArray) === FALSE) {
$queueRecord = MaestroEngine::getQueueEntryById($entityID);
$queueRecord
->set('archived', TASK_ARCHIVE_REGEN);
$queueRecord
->save();
}
}
$queueID = $this
->createProductionTask($taskID, $template, $processID);
}
}
}
else {
}
}
protected function productionAssignments($templateMachineName, $taskID, $queueID) {
$task = $this
->getTemplateTaskByID($templateMachineName, $taskID);
$executableTask = MaestroEngine::getPluginTask($task['tasktype']);
$assigned = '';
if (array_key_exists('assigned', $task)) {
$assigned = $task['assigned'];
}
if (($assigned == '' || $assigned == 'engine') && !$executableTask
->isInteractive()) {
return;
}
if ($assigned == '' && $executableTask
->isInteractive()) {
return;
}
$assignments = explode(',', $assigned);
foreach ($assignments as $assignment) {
$thisAssignment = explode(':', $assignment);
if ($thisAssignment[1] == 'fixed') {
$values = [
'queue_id' => $queueID,
'assign_type' => $thisAssignment[0],
'by_variable' => 0,
'assign_id' => $thisAssignment[2],
'process_variable' => 0,
'assign_back_id' => 0,
'task_completed' => 0,
];
$prodAssignments = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->create($values);
$prodAssignments
->save();
}
elseif ($thisAssignment[1] == 'variable') {
$var = MaestroEngine::getProcessVariable($thisAssignment[2], MaestroEngine::getProcessIdFromQueueId($queueID));
$varID = MaestroEngine::getProcessVariableID($thisAssignment[2], MaestroEngine::getProcessIdFromQueueId($queueID));
$assignmentsByVar = explode(',', $var);
foreach ($assignmentsByVar as $assignTo) {
if ($assignTo != '') {
$values = [
'queue_id' => $queueID,
'assign_type' => $thisAssignment[0],
'by_variable' => 1,
'assign_id' => $assignTo,
'process_variable' => $varID,
'assign_back_id' => 0,
'task_completed' => 0,
];
$prodAssignments = \Drupal::entityTypeManager()
->getStorage('maestro_production_assignments')
->create($values);
$prodAssignments
->save();
}
}
}
}
\Drupal::moduleHandler()
->invokeAll('maestro_post_production_assignments', [
$templateMachineName,
$taskID,
$queueID,
]);
}
protected function createProductionTask($taskMachineName, $templateMachineName, $processID) {
$config = \Drupal::config('maestro.settings');
$queueID = FALSE;
$nextTask = $this
->getTemplateTaskByID($templateMachineName, $taskMachineName);
$executableTask = MaestroEngine::getPluginTask($nextTask['tasktype']);
$currentTime = time();
$nextReminderTime = 0;
$reminderInterval = 0;
$escalationInterval = 0;
if (array_key_exists('notifications', $nextTask)) {
$reminderInterval = $nextTask['notifications']['reminder_after'];
if (intval($reminderInterval) > 0) {
$nextReminderTime = $currentTime + intval($reminderInterval) * 86400;
}
$escalationInterval = $nextTask['notifications']['escalation_after'];
}
$values = [
'process_id' => $processID,
'task_class_name' => $nextTask['tasktype'],
'task_id' => $nextTask['id'],
'task_label' => $nextTask['label'],
'engine_version' => 2,
'is_interactive' => $executableTask
->isInteractive() ? 1 : 0,
'show_in_detail' => isset($nextTask['showindetail']) ? $nextTask['showindetail'] : 0,
'handler' => isset($nextTask['handler']) ? $nextTask['handler'] : '',
'task_data' => isset($nextTask['data']) ? $nextTask['data'] : '',
'status' => 0,
'run_once' => $executableTask
->isInteractive() ? 1 : 0,
'uid' => 0,
'archived' => 0,
'started_date' => $currentTime,
'num_reminders_sent' => 0,
'num_escalations_sent' => 0,
'next_reminder_time' => $nextReminderTime,
'reminder_interval' => $reminderInterval,
'escalation_interval' => $escalationInterval,
];
$queue = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->create($values);
$queue
->save();
if ($queue
->id()) {
$this
->productionAssignments($templateMachineName, $taskMachineName, $queue
->id());
$queueID = $queue
->id();
if ($config
->get('maestro_send_notifications')) {
$this
->doProductionAssignmentNotifications($templateMachineName, $taskMachineName, $queue
->id(), 'assignment');
}
if (isset($nextTask['participate_in_workflow_status_stage']) && $nextTask['participate_in_workflow_status_stage'] == 1) {
if (isset($nextTask['workflow_status_stage_number'])) {
$this
->setProcessVariable('workflow_current_stage', $nextTask['workflow_status_stage_number'], $processID);
}
if (isset($nextTask['workflow_status_stage_message'])) {
$this
->setProcessVariable('workflow_current_stage_message', $nextTask['workflow_status_stage_message'], $processID);
}
}
}
else {
}
return $queueID;
}
protected function doProductionAssignmentNotifications($templateMachineName, $taskMachineName, $queueID, $notificationType = 'assignment') {
$config = \Drupal::config('maestro.settings');
$templateTask = $this
->getTemplateTaskByID($templateMachineName, $taskMachineName);
$notificationList = [];
if (array_key_exists('notifications', $templateTask) && array_key_exists('notification_assignments', $templateTask['notifications'])) {
$notifications = explode(',', $templateTask['notifications']['notification_assignments']);
foreach ($notifications as $notification) {
$doNotification = TRUE;
$thisNotification = explode(':', $notification);
if ($thisNotification[3] == $notificationType) {
$entity = '';
if ($thisNotification[1] == 'fixed') {
$entity = $thisNotification[2];
}
elseif ($thisNotification[1] == 'variable') {
$processID = MaestroEngine::getProcessIdFromQueueId($queueID);
$variableValue = MaestroEngine::getProcessVariable($thisNotification[2], $processID);
$entity = $variableValue;
}
else {
$doNotification = FALSE;
}
if ($thisNotification[0] == 'user' && $doNotification) {
$users = explode(',', $entity);
foreach ($users as $accountName) {
if ($accountName != '') {
$account = user_load_by_name($accountName);
if ($account) {
$notificationList[$account
->get('mail')
->getString()] = $account
->get('mail')
->getString();
}
else {
throw new MaestroGeneralException('Unknown account name identified when attempting a notification.');
}
}
}
}
elseif ($thisNotification[0] == 'role' && $doNotification) {
$roles = explode(',', $entity);
foreach ($roles as $roleName) {
if ($roleName != '') {
$ids = \Drupal::entityQuery('user')
->condition('status', 1)
->condition('roles', $roleName)
->execute();
$users = User::loadMultiple($ids);
foreach ($users as $account) {
$notificationList[$account
->get('mail')
->getString()] = $account
->get('mail')
->getString();
}
}
}
}
else {
\Drupal::moduleHandler()
->invokeAll('maestro_production_' . $notificationType . '_notification', [
$queueID,
$thisNotification,
&$notificationList,
]);
}
}
}
if (count($notificationList) > 0) {
$notificationMessage = '';
if (array_key_exists('notification_' . $notificationType, $templateTask['notifications']) && $templateTask['notifications']['notification_' . $notificationType] != '') {
$notificationMessage = $templateTask['notifications']['notification_' . $notificationType];
$tokenService = \Drupal::token();
$notificationMessage = $tokenService
->replace($notificationMessage, [
'maestro' => [
'task' => $templateTask,
'queueID' => $queueID,
],
]);
if ($notificationType == 'assignment') {
$subject = array_key_exists('notification_assignment_subject', $templateTask['notifications']) ? $tokenService
->replace($templateTask['notifications']['notification_assignment_subject'], [
'maestro' => [
'task' => $templateTask,
'queueID' => $queueID,
],
]) : 'You have a new task assignment';
}
elseif ($notificationType == 'reminder') {
$subject = array_key_exists('notification_reminder_subject', $templateTask['notifications']) ? $tokenService
->replace($templateTask['notifications']['notification_reminder_subject'], [
'maestro' => [
'task' => $templateTask,
'queueID' => $queueID,
],
]) : 'You have a new task assignment';
}
elseif ($notificationType == 'escalation') {
$subject = array_key_exists('notification_escalation_subject', $templateTask['notifications']) ? $tokenService
->replace($templateTask['notifications']['notification_escalation_subject'], [
'maestro' => [
'task' => $templateTask,
'queueID' => $queueID,
],
]) : 'You have a new task assignment';
}
}
else {
$redirectionLocation = rtrim($config
->get('maestro_task_console_location'), '/');
if ($redirectionLocation == '') {
$redirectionLocation = '/taskconsole';
}
$queueRecord = MaestroEngine::getQueueEntryById($queueID);
if ($notificationType == 'assignment') {
$notificationMessage = t('A new task titled:') . ' ' . $queueRecord->task_label
->getString() . ' ' . t('has been assigned to you.');
$notificationMessage .= t('Click here to go to see your tasks:') . ' ' . '<a href="' . Url::fromUserInput($redirectionLocation . '/' . $queueID, [
'absolute' => TRUE,
])
->toString() . '">Task Console</a>';
}
elseif ($notificationType == 'reminder') {
$notificationMessage = t('A reminder you have open tasks. Please review the task:') . ' ' . $queueRecord->task_label
->getString();
$notificationMessage .= t('Click here to go to your tasks:') . ' <a href="' . Url::fromUserInput($redirectionLocation . '/' . $queueID, [
'absolute' => TRUE,
])
->toString() . '">Task Console</a>';
}
elseif ($notificationType == 'escalation') {
$notificationMessage = t('An escalation for an overdue task has been generated for the task:') . ' ' . $queueRecord->task_label
->getString();
$notificationMessage .= t('Assigned To:') . ' ';
$notificationMessage .= t('Queue ID:') . ' ' . $queueID;
$notificationMessage .= t('Process IDr:') . ' ' . $queueRecord->process_id
->getString();
}
}
$mailManager = \Drupal::service('plugin.manager.mail');
$langcode = \Drupal::languageManager()
->getCurrentLanguage()
->getId();
$params = [];
$params['queueID'] = $queueID;
$tokenService = \Drupal::token();
$params['subject'] = isset($subject) ? $subject : t('You have a new task assignment');
$params['message'] = $notificationMessage;
foreach ($notificationList as $email) {
$result = $mailManager
->mail('maestro', $notificationType . '_notification', $email, $langcode, $params, NULL, TRUE);
}
}
}
}
}