maestro-3.0.1-rc2/src/Plugin/EngineTasks/MaestroIfTask.php

src/Plugin/EngineTasks/MaestroIfTask.php
<?php

namespace Drupal\maestro\Plugin\EngineTasks;

use Drupal\Core\Plugin\PluginBase;
use Drupal\maestro\MaestroEngineTaskInterface;
use Drupal\maestro\Engine\MaestroEngine;
use Drupal\maestro\MaestroTaskTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\maestro\Form\MaestroExecuteInteractive;

/**
 * Maestro If Task Plugin.
 *
 * The plugin annotations below should include:
 * id: The task type ID for this task.  For Maestro tasks, this is Maestro[TaskType].
 *     So for example, the start task shipped by Maestro is MaestroStart.
 *     The Maestro End task has an id of MaestroEnd
 *     Those task IDs are what's used in the engine when a task is injected into the queue.
 *
 * @Plugin(
 *   id = "MaestroIf",
 *   task_description = @Translation("The Maestro Engine's If task."),
 * )
 */
class MaestroIfTask extends PluginBase implements MaestroEngineTaskInterface {

  use MaestroTaskTrait;

  /**
   * Constructor.
   */
  public function __construct($configuration = NULL) {
    if (is_array($configuration)) {
      $this->processID = $configuration[0];
      $this->queueID = $configuration[1];
    }
  }

  /**
   * {@inheritDoc}
   */
  public function isInteractive() {
    return FALSE;
  }

  /**
   * {@inheritDoc}
   */
  public function shortDescription() {
    return $this->t('If Task');
  }

  /**
   * {@inheritDoc}
   */
  public function description() {
    return $this->t('Performs logic on task completion or variables.');
  }

  /**
   * {@inheritDoc}
   *
   * @see \Drupal\Component\Plugin\PluginBase::getPluginId()
   */
  public function getPluginId() {
    return 'MaestroIf';
  }

  /**
   * {@inheritDoc}
   */
  public function getTaskColours() {
    return '#daa520';
  }

  /**
   * Part of the ExecutableInterface
   * Execution of the Batch Function task will use the handler for this task as the executable function.
   * {@inheritdoc}.
   */
  public function execute() {
    $templateMachineName = MaestroEngine::getTemplateIdFromProcessId($this->processID);
    $taskMachineName = MaestroEngine::getTaskIdFromQueueId($this->queueID);
    $task = MaestroEngine::getTemplateTaskByID($templateMachineName, $taskMachineName);
    $statusFlag = NULL;
    $ifData = $task['data']['if'];
    $variable = $ifData['variable'];
    $variableValue = $ifData['variable_value'];
    $method = $ifData['method'];
    // This is one of our constants defined in the engine.
    $status = $ifData['status'];
    // = , !=, < , >
    $operator = $ifData['operator'];

    switch ($method) {
      case 'byvariable':
        $processVariableValue = MaestroEngine::getProcessVariable($variable, $this->processID);
        // we're being optimistic here in that we're going to have a status match.
        $statusFlag = TRUE;
        // We need to determine if the variable chosen contains the value we are testing against based on the condition.
        switch ($operator) {
          case '=':
            // Not equal!
            if (strcmp($variableValue, $processVariableValue) != 0) {
              $statusFlag = FALSE;
            }
            break;

          case '!=':
            // equal!
            if (strcmp($variableValue, $processVariableValue) == 0) {
              $statusFlag = FALSE;
            }
            break;

          case '<':
            if (
              (floatval($processVariableValue) > floatval($variableValue)) ||
              (floatval($processVariableValue) == floatval($variableValue))
            )
               {
              $statusFlag = FALSE;
            }
            break;

          case '>':
            if ( 
              (floatval($processVariableValue) < floatval($variableValue)) || 
              (floatval($processVariableValue) == floatval($variableValue))
            ) 
              {
              $statusFlag = FALSE;
            }
            break;
        }
        break;

      case 'bylasttaskstatus':
        // Need to find out who points to this task.  If there is more than one pointer to this task,
        // we have no real way to know what to do other than if any other task that DOESN'T have the
        // status, we return false.
        $pointers = MaestroEngine::getTaskPointersFromTemplate($templateMachineName, $taskMachineName);
        // Pointers now holds the task machine names (taskIDs).  we fetch these from the queue now.
        $query = \Drupal::entityQuery('maestro_queue');
        $query->accessCheck(FALSE);
        $andMainConditions = $query->andConditionGroup()
          ->condition('process_id', $this->processID)
          // We need to also ignore any statuses that are not 1's
          // otherwise the engine looks at tasks that have been regenerated or outstanding.
          ->condition('status', '0', '<>')
          ->condition('archived', '1');

        $orConditionGroup = $query->orConditionGroup();
        foreach ($pointers as $taskID) {
          $orConditionGroup->condition('task_id', $taskID);
        }

        $andMainConditions->condition($orConditionGroup);
        $query->condition($andMainConditions);
        $entity_ids = $query->execute();
        foreach ($entity_ids as $entityID) {
          $queueRecord = \Drupal::entityTypeManager()->getStorage('maestro_queue')->load($entityID);
          if (strcmp($status, $queueRecord->status->getString()) != 0) {
            $statusFlag = FALSE;
          }
        }
        // At this point, if the statusFlag is not false, it must be OK as the default is NULL.
        if ($statusFlag === NULL) {
          $statusFlag = TRUE;
        }
        break;
    }
    // At this point, we have a statusFlag variable that denotes whether the pointed-from tasks in the queue have
    // a status that is equal to the status that was provided in the template.  If it's false, then we complete this
    // IF task with the execution status as success with a completion status of use the false branch.
    if ($statusFlag !== NULL) {
      if ($statusFlag == TRUE) {
        // Normal condition here. we've not aborted or done anything different.
        $this->executionStatus = TASK_STATUS_SUCCESS;
        // This will follow the true branch.
        $this->completionStatus = MAESTRO_TASK_COMPLETION_NORMAL;
      }
      else {
        // again, nothing unusual.  just set the task status.
        $this->executionStatus = TASK_STATUS_FALSE_BRANCH;
        // ahh.. last status doesn't equal what we tested for.  Use the false branch for nextstep.
        $this->completionStatus = MAESTRO_TASK_COMPLETION_USE_FALSE_BRANCH;
      }
      // Nothing really stopping us from always completing this task in the engine.
      return TRUE;
    }

    \Drupal::logger('maestro')->error('If task does not have a statusFlag set and is unable to complete');
    // Problem here - we have a situation where the IF statement is stuck because the statusFlag was never set.
    return FALSE;
    // This will hold the engine at the IF task forever.
  }

  /**
   * {@inheritDoc}
   */
  public function getExecutableForm($modal, MaestroExecuteInteractive $parent) {

  }

  /**
   * {@inheritDoc}
   */
  public function handleExecuteSubmit(array &$form, FormStateInterface $form_state) {

  }

  /**
   * {@inheritDoc}
   */
  public function getTaskEditForm(array $task, $templateMachineName) {
    $ifParms = isset($task['data']['if']) ? $task['data']['if'] : [];

    $form = [
      '#markup' => $this->t('Edit the logic for this IF task'),
    ];

    $form['method'] = [
      '#type' => 'radios',
      '#title' => $this->t('Execute the IF:'),
      '#options' => [
        'byvariable' => $this->t('By Variable'),
        'bylasttaskstatus' => $this->t('By Last Task Status'),
      ],
      '#default_value' => isset($ifParms['method']) ? $ifParms['method'] : '',
      '#required' => TRUE,
      '#attributes' => [
          // 'onclick' => 'document.getElementById("byvar").setAttribute("open", "open");'
        'onclick' => 'maestro_if_task_toggle(this);',
      ],
      '#attached' => [
        'library' => ['maestro/maestro-engine-task-edit'],
      ],
    ];

    /*
     * By Variable options
     */

    $variables = MaestroEngine::getTemplateVariables($templateMachineName);
    $options = [];
    foreach ($variables as $variableName => $arr) {
      $options[$variableName] = $variableName;
    }

    $form['byvariable'] = [
      '#id' => 'byvar',
      '#tree' => TRUE,
      '#type' => 'details',
      '#title' => $this->t('By Variable Options'),
      '#open' => FALSE,
    ];

    $form['byvariable']['variable'] = [
      '#type' => 'select',
      '#title' => $this->t('Argument variable'),
      '#required' => FALSE,
      '#default_value' => isset($ifParms['variable']) ? $ifParms['variable'] : '',
      '#options' => $options,

    ];

    $form['byvariable']['operator'] = [
      '#type' => 'select',
      '#title' => $this->t('Operator'),
      '#required' => FALSE,
      '#default_value' => isset($ifParms['operator']) ? $ifParms['operator'] : '',
      '#options' => [
        '=' => '=',
        '>' => '>',
        '<' => '<',
        '!=' => '!=',
      ],
    ];

    $form['byvariable']['variable_value'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Variable value'),
      '#description' => $this->t('The IF will check against this value during execution'),
      '#default_value' => isset($ifParms['variable_value']) ? $ifParms['variable_value'] : '',
      '#required' => FALSE,
    ];

    /*
     * The by status section
     */
    $form['bystatus'] = [
      '#id' => 'bystatus',
      '#tree' => TRUE,
      '#type' => 'details',
      '#title' => $this->t('By Last Task Status'),
      '#open' => FALSE,
      '#markup' => $this->t('This method is only useful if ONLY ONE task points to this IF. 
          If more than one task points to this IF task, a FALSE will be returned if ANY of those 
          tasks do not have a status of the status chosen in the status selector.'),
    ];

    $form['bystatus']['status'] = [
      '#type' => 'select',
      '#title' => $this->t('Status'),
      '#required' => FALSE,
      '#default_value' => isset($ifParms['status']) ? $ifParms['status'] : '',
      '#options' => [
        TASK_STATUS_SUCCESS => $this->t('Last Task Status is Success'),
        TASK_STATUS_CANCEL => $this->t('Last Task Status is Cancel'),
        TASK_STATUS_HOLD => $this->t('Last Task Status is Hold'),
        TASK_STATUS_ABORTED => $this->t('Last Task Status is Aborted'),
      ],
    ];

    if (isset($ifParms['method']) && $ifParms['method'] == 'byvariable') {
      $form['byvariable']['#open'] = TRUE;
      $form['bystatus']['#open'] = FALSE;
    }
    else {
      $form['byvariable']['#open'] = FALSE;
      $form['bystatus']['#open'] = TRUE;
    }

    return $form;
  }

  /**
   * {@inheritDoc}
   */
  public function validateTaskEditForm(array &$form, FormStateInterface $form_state) {
    $method = $form_state->getValue('method');
    switch ($method) {
      case 'byvariable':
        $byvars = $form_state->getValue('byvariable');
        if (empty($byvars['variable'])) {
          $form_state->setErrorByName('byvariable][variable', $this->t('When doing an IF by variable, you must provide a variable to IF on.'));
        }
        if (empty($byvars['operator'])) {
          $form_state->setErrorByName('byvariable][operator', $this->t('When doing an IF by variable, you must provide a operator.'));
        }
        if (!isset($byvars['variable_value'])) {
          $form_state->setErrorByName('byvariable][variable_value', $this->t('When doing an IF by variable, you must provide a variable value.'));
        }
        $form['byvariable']['#open'] = TRUE;
        $form['bystatus']['#open'] = FALSE;
        break;

      case 'bystatus':
        // This condition may not even occur, but if for some reason the form is corrupt, we need to ensure we have a value.
        $byvars = $form_state->getValue('bystatus');
        if (empty($byvars['status'])) {
          $form_state->setErrorByName('bystatus][status', $this->t('When doing an IF by statys, you must provide a status value.'));
        }
        $form['byvariable']['#open'] = FALSE;
        $form['bystatus']['#open'] = TRUE;
        break;
    }
  }

  /**
   * {@inheritDoc}
   */
  public function prepareTaskForSave(array &$form, FormStateInterface $form_state, array &$task) {
    // variable, operator, variable_value, status.
    $method = $form_state->getValue('method');
    $byvariable = $form_state->getValue('byvariable');
    $bystatus = $form_state->getValue('bystatus');
    $task['data']['if'] = [
      'method' => $method,
      'variable' => $byvariable['variable'],
      'operator' => $byvariable['operator'],
      'variable_value' => $byvariable['variable_value'],
      'status' => $bystatus['status'],
    ];
  }

  /**
   * {@inheritDoc}
   */
  public function performValidityCheck(array &$validation_failure_tasks, array &$validation_information_tasks, array $task) {
    // We have a number of fields that we know MUST be filled in.
    // the issue is that we have a nextstep and nextfalsestep branches that we really don't know if they should be connected or not
    // so for the time being, we'll leave the nextstep and nextfalsestep branches alone and only show warnings.
    $data = $task['data']['if'];
    // We will give a warning for the 'to' and 'falseto' branches missing
    $to = $task['nextstep'] ?? NULL;
    if (!$to || !isset($to)) {
      $validation_information_tasks[] = [
        'taskID' => $task['id'],
        'taskLabel' => $task['label'],
        'reason' => t('The IF task does not have a TRUE branch connection.'),
      ];
    }
    $false = $task['nextfalsestep'] ?? NULL;
    if (!$false || !isset($false)) {
      $validation_information_tasks[] = [
        'taskID' => $task['id'],
        'taskLabel' => $task['label'],
        'reason' => t('The IF task does not have a FALSE branch connection.'),
      ];
    }

    // Check the method.  if it's blank, the whole thing will simply fail out.
    if (!is_array($data) || (array_key_exists('method', $data) && $data['method'] == '')  || !array_key_exists('method', $data)) {
      $validation_failure_tasks[] = [
        'taskID' => $task['id'],
        'taskLabel' => $task['label'],
        'reason' => t('The IF task has not been set up properly.  The method of "By Variable" or "By Status" is missing and thus the engine will be unable to execute this task.'),
      ];
    }
    else {
      // Method IS filled in.  Let's validate the rest now
      // operator is important for both.
      if ((array_key_exists('operator', $data) && $data['operator'] == '')  || !array_key_exists('operator', $data)) {
        $validation_failure_tasks[] = [
          'taskID' => $task['id'],
          'taskLabel' => $task['label'],
          'reason' => t('The IF task has not been set up properly. The operator has not been set. The engine will be unable to execute this task.'),
        ];
      }

      switch ($data['method']) {
        case 'byvariable':
          // Check that the variable has been set.
          if ((array_key_exists('variable', $data) && $data['variable'] == '')  || !array_key_exists('variable', $data)) {
            $validation_failure_tasks[] = [
              'taskID' => $task['id'],
              'taskLabel' => $task['label'],
              'reason' => t('The IF task has not been set up properly. The variable has not been set. The engine will be unable to execute this task.'),
            ];
          }
          // It is conceivable that the variable value could be tested against a blank.  So just make sure the value key exists.
          if (!array_key_exists('variable_value', $data)) {
            $validation_failure_tasks[] = [
              'taskID' => $task['id'],
              'taskLabel' => $task['label'],
              'reason' => t('The IF task has not been set up properly. The variable value has not been set. The engine will be unable to execute this task.'),
            ];
          }
          break;

        case 'bystatus':
          if ((array_key_exists('status', $data) && $data['status'] == '')  || !array_key_exists('status', $data)) {
            $validation_failure_tasks[] = [
              'taskID' => $task['id'],
              'taskLabel' => $task['label'],
              'reason' => t('The IF task has not been set up properly. The status has not been set. The engine will be unable to execute this task.'),
            ];
          }
          break;
      }
    }
  }

  /**
   * {@inheritDoc}
   */
  public function getTemplateBuilderCapabilities() {
    return ['edit', 'drawlineto', 'drawfalselineto', 'removelines', 'remove'];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc