You are here

workflow.module in Workflow 8

Support workflows made up of arbitrary states.

File

workflow.module
View source
<?php

/**
 * @file
 * Support workflows made up of arbitrary states.
 */
define('WORKFLOW_CREATION_STATE', 1);
define('WORKFLOW_CREATION_DEFAULT_WEIGHT', -50);
define('WORKFLOW_DELETION', 0);

// Couldn't find a more elegant way to preserve translation.
define('WORKFLOW_CREATION_STATE_NAME', 'creation');

/**
 * Role ID for anonymous users.
 */

// #2657072 brackets are added later to indicate a special role,
// and distinguish from frequently used 'author' role.
define('WORKFLOW_ROLE_AUTHOR_NAME', 'Author');
define('WORKFLOW_ROLE_AUTHOR_RID', 'workflow_author');
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\user\Entity\User;
use Drupal\workflow\Entity\Workflow;
use Drupal\workflow\Entity\WorkflowManager;
use Drupal\workflow\Entity\WorkflowScheduledTransition;
use Drupal\workflow\Entity\WorkflowState;
use Drupal\workflow\Entity\WorkflowTransition;
use Drupal\workflow\Entity\WorkflowTransitionInterface;
\Drupal::moduleHandler()
  ->loadInclude('workflow', 'inc', 'workflow.devel');
\Drupal::moduleHandler()
  ->loadInclude('workflow', 'inc', 'workflow.entity');
\Drupal::moduleHandler()
  ->loadInclude('workflow', 'inc', 'workflow.field');
\Drupal::moduleHandler()
  ->loadInclude('workflow', 'inc', 'workflow.form');
\Drupal::moduleHandler()
  ->loadInclude('workflow', 'inc', 'workflow.rules');

/**********************************************************************
 * Info hooks.
 */

/**
 * @inheritdoc
 */
function workflow_help($route_name) {
  $output = '';
  switch ($route_name) {
    case 'help.page.workflow':
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Workflow module adds a field to Entities to
        store field values as Workflow states. You can control "state transitions"
        and add action to specific transitions.') . '</p>';
      return $output;
    case 'entity.workflow_transition.field_ui_fields':
      return t('This page allows you to add fields to the Workflow form.
        Normally this is an advanced action, which is not needed in
        regular use cases.');
    case 'entity.workflow_type.collection':
      return t('This page allows you to maintain Workflows. Once a workflow is
        created, you can maintain your entity type and add a Field of type
        \'Workflow\'.');
    case 'entity.workflow_state.collection':
      return t("To create a new state, enter its name in the last row of the\n        'State' column. Check the 'Active' box to make it effective. You may\n        also drag it to the appropriate position.") . '<br />' . t("A state must be marked as active, to be available in the\n        workflow's transitions.") . '<br />' . t("If you wish to inactivate a state that has content (i.e. count is\n        not zero), then you need to select a state to which to reassign that\n        content.");
    case 'entity.workflow_transition.collection':
      $url = Url::fromRoute('user.admin_permissions', [], [
        'fragment' => 'module-workflow',
      ]);
      return t('You are currently viewing the possible transitions to and from
        workflow states. The state is shown in the left column; the state to be
        moved to is to the right. For each transition, check the box next to
        the role(s) that may initiate the transition. For example, if only the
        "production editor" role may move content from Review state to the
        Published state, check the box next to "production editor". The author
        role is built in and refers to the user who authored the content.') . '<br /><i>' . t("If not all roles are in the list, please review which roles may\n        'participate in workflows' on <a href=':url'>the Permissions page</a>.\n        On that page, uncheck the 'Authenticated user' role temporarily to\n        view the permissions of each separate role.</i>", [
        ':url' => $url
          ->toString(),
      ]);
    case 'entity.workflow_transition_label.collection':
      return t('You can add labels to transitions if you don\'t like the
        standard state labels. They will modify the Workflow form options, so
        specific workflow transitions can have their own labels, relative to
        the beginning and ending states. Rather than showing the user a
        workflow box containing options like "review required" as a state in
        the workflow, it could say "move to the editing department for grammar
        review".');
  }
  return $output;
}

/**
 * Implements hook_hook_info().
 *
 * Allow adopters to place their hook implementations in either
 * their main module or in a module.workflow.inc file.
 */
function workflow_hook_info() {
  $hooks['workflow'] = [
    'group' => 'workflow',
  ];
  return $hooks;
}

/**********************************************************************
 * CRUD hooks.
 */

/**
 * Implements hook_user_cancel().
 *
 * Update tables for deleted account, move account to user 0 (anon.)
 * ALERT: This may cause previously non-Anonymous posts to suddenly
 * be accessible to Anonymous.
 *
 * @param $edit
 * @param \Drupal\Core\Session\AccountInterface $account
 *   An account object.
 * @param string $method
 *
 * @see hook_user_cancel()
 */
function workflow_user_cancel($edit, AccountInterface $account, $method) {
  WorkflowManager::cancelUser($edit, $account, $method);
}

/**
 * Implements hook_user_delete().
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *   An account object.
 *
 * @todo Hook hook_user_delete does not exist. hook_ENTITY_TYPE_delete?
 */
function workflow_user_delete($account) {
  WorkflowManager::deleteUser($account);
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 *
 * Is called when adding a new Workflow type.
 * The technical name for the Workflow entity is 'workflow_type'.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An Entity.
 */
function workflow_workflow_type_insert(EntityInterface $entity) {
  WorkflowManager::participateUserRoles($entity);
}

/**
 * Implements hook_entity_insert().
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An Entity.
 */
function workflow_entity_insert(EntityInterface $entity) {

  // Execute updates in hook_presave() to revert executions,
  // Execute inserts in hook_insert, to have the Entity ID determined.
  _workflow_execute_transitions($entity);
}

/**
 * Implements hook_entity_presave().
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An EntityInterface object.
 */
function workflow_entity_presave(EntityInterface $entity) {
  if (!$entity
    ->isNew()) {

    // Avoid a double call by hook_entity_presave and hook_entity_insert.
    _workflow_execute_transitions($entity);
  }
}

/**
 * Execute transitions. if prohibited, restore original field value.
 *  - insert: use hook_insert(), to have the Entity ID determined when saving transitions.
 *  - update: use hook_presave() to revert executions,
 *  - so, do not use hook_update().
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An Entity.
 */
function _workflow_execute_transitions(EntityInterface $entity) {

  // Avoid this hook on workflow objects.
  if (WorkflowManager::isWorkflowEntityType($entity
    ->getEntityTypeId())) {
    return;
  }

  // Execute/save the transitions from the widgets in the entity form.
  WorkflowManager::executeTransitionsOfEntity($entity);
}

/**
 * Implements hook_entity_delete().
 *
 * Delete the corresponding workflow table records.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An Entity.
 */
function workflow_entity_delete(EntityInterface $entity) {

  // @todo Test with multiple workflows.
  if (get_class($entity) == 'Drupal\\field\\Entity\\FieldConfig' || get_class($entity) == 'Drupal\\field\\Entity\\FieldStorageConfig') {

    // A Workflow Field is removed from an entity.
    $field_config = $entity;

    /** @var \Drupal\Core\Entity\ContentEntityBase $field_config */
    $entity_type = $field_config
      ->get('entity_type');
    $field_name = $field_config
      ->get('field_name');

    /** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
    foreach (WorkflowScheduledTransition::loadMultipleByProperties($entity_type, [], [], $field_name) as $transition) {
      $transition
        ->delete();
    }
    foreach (WorkflowTransition::loadMultipleByProperties($entity_type, [], [], $field_name) as $transition) {
      $transition
        ->delete();
    }
  }
  elseif (!WorkflowManager::isWorkflowEntityType($entity
    ->getEntityTypeId())) {

    // A 'normal' entity is deleted.
    foreach ($fields = _workflow_info_fields($entity) as $field_id => $field_storage) {
      $entity_id = $entity
        ->id();
      $entity_type = $field_storage
        ->getTargetEntityTypeId();
      $field_name = $field_storage
        ->getName();

      /** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
      foreach (WorkflowScheduledTransition::loadMultipleByProperties($entity_type, [
        $entity_id,
      ], [], $field_name) as $transition) {
        $transition
          ->delete();
      }
      foreach (WorkflowTransition::loadMultipleByProperties($entity_type, [
        $entity_id,
      ], [], $field_name) as $transition) {
        $transition
          ->delete();
      }
    }
  }
}

/**
 * Implements hook_cron().
 *
 * Given a time frame, execute all scheduled transitions.
 */
function workflow_cron() {
  WorkflowManager::executeScheduledTransitionsBetween(0, \Drupal::time()
    ->getRequestTime());
}

/**
 * Implements hook_theme().
 */
function workflow_theme() {
  return [
    'workflow_transition' => [
      'render element' => 'elements',
      'file' => 'workflow.theme.inc',
    ],
  ];
}

/**
 * Business related functions, the API.
 */

/**
 * @param \Drupal\workflow\Entity\WorkflowTransitionInterface $transition
 *   A WorkflowTransition.
 * @param bool $force
 *   Indicator if the transition must be forces.
 *
 * @return string
 *   A string.
 */
function workflow_execute_transition(WorkflowTransitionInterface $transition, $force = FALSE) {

  // Execute transition and update the attached entity.
  return $transition
    ->executeAndUpdateEntity($force);
}

/**
 * Functions to get an options list (to show in a Widget).
 * To be used in non-OO modules, like workflow_rules, workflow_views.
 *
 * The naming convention is workflow_get_<entity_type>_names.
 * (A bit different from 'user_role_names'.)
 * Can be used for hook_allowed_values from list.module:
 * - user_role
 * - workflow
 * - workflow_state
 * - sid.
 */

/**
 * Retrieves the names of roles matching specified conditions.
 *
 * Deprecated D8: workflow_get_roles --> workflow_get_user_role_names.
 *
 * Usage:
 *   D7: $roles = workflow_get_user_role_names('participate in workflow');
 *   D8: $type_id = $workflow->id();
 *   D8: $roles = workflow_get_user_role_names("create $type_id workflow_transition");
 *
 * @param string $permission
 *   (optional) A string containing a permission. If set, only roles
 *    containing that permission are returned. Defaults to NULL, which
 *    returns all roles.
 *    Normal usage for filtering roles that are enabled in a workflow_type
 *    would be: $permission = 'create $type_id transition'.
 *
 * @return array
 *   Array of role names keyed by role ID, including the 'author' role.
 */
function workflow_get_user_role_names($permission) {
  static $roles = NULL;
  if ($roles && isset($roles[$permission])) {
    return $roles[$permission];
  }

  // Copied from AccountForm::form().
  $roles[$permission] = array_map([
    '\\Drupal\\Component\\Utility\\Html',
    'escape',
  ], [
    WORKFLOW_ROLE_AUTHOR_RID => '(' . t(WORKFLOW_ROLE_AUTHOR_NAME) . ')',
  ] + user_role_names(FALSE, $permission));
  return $roles[$permission];
}

/**
 * Get an options list for workflow states.
 *
 * @param mixed $wid
 *   The Workflow ID.
 * @param bool $grouped
 *   Indicates if the value must be grouped per workflow.
 *   This influences the rendering of the select_list options.
 *
 * @return array
 *   An array of $sid => state->label(), grouped per Workflow.
 */
function workflow_get_workflow_state_names($wid = '', $grouped = FALSE) {
  $options = [];

  // @todo Implement $add parameter.
  //
  // @todo Follow Options pattern.
  // @see callback_allowed_values_function()
  // @see options_allowed_values()
  // Get the (user-dependent) options.
  // Since this function is only used in UI, it is save to use the global $user.
  $user = workflow_current_user();

  /** @var \Drupal\workflow\Entity\Workflow[] $workflows */
  $workflows = Workflow::loadMultiple($wid ? [
    $wid,
  ] : NULL);

  // Do not group if only 1 Workflow is configured or selected.
  $grouped = count($workflows) == 1 ? FALSE : $grouped;
  foreach ($workflows as $wid => $workflow) {

    /** @var \Drupal\workflow\Entity\WorkflowState $state */
    $state = WorkflowState::create([
      'wid' => $wid,
    ]);
    $workflow_options = $state
      ->getOptions(NULL, '', $user, FALSE);
    if (!$grouped) {
      $options += $workflow_options;
    }
    else {

      // Make a group for each Workflow.
      $options[$workflow
        ->label()] = $workflow_options;
    }
  }
  return $options;
}

/**
 * Get an options list for workflows. Include an initial empty value
 * if requested. Validate each workflow, and generate a message if not complete.
 *
 * @param bool $required
 *   Indicates if the resulting list contains a options value.
 *
 * @return array
 *   An array of $wid => workflow->label().
 */
function workflow_get_workflow_names($required = TRUE) {
  $options = [];
  if (!$required) {
    $options[''] = t('- Select a value -');
  }
  foreach (Workflow::loadMultiple() as $wid => $workflow) {

    /** @var \Drupal\workflow\Entity\Workflow $workflow */
    if ($workflow
      ->isValid()) {
      $options[$wid] = $workflow
        ->label();
    }
  }
  return $options;
}

/**
 * Gets an Options list of field names.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An entity.
 * @param string $entity_type
 *   An entity_type.
 * @param string $entity_bundle
 *   An entity.
 * @param string $field_name
 *   A field name.
 *
 * @return array
 *   An list of field names.
 */
function workflow_get_workflow_field_names(EntityInterface $entity = NULL, $entity_type = '', $entity_bundle = '', $field_name = '') {
  $result = [];
  foreach (_workflow_info_fields($entity, $entity_type, $entity_bundle, $field_name) as $definition) {
    $field_name2 = $definition
      ->getName();
    $result[$field_name2] = $field_name2;
  }
  return $result;
}

/**
 * Helper function, to get the label of a given State Id.
 * deprecated: workflow_get_sid_label() --> workflow_get_sid_name()
 *
 * @param string $sid
 *   A State ID.
 *
 * @return string
 *   An translated label.
 */
function workflow_get_sid_name($sid) {
  if (empty($sid)) {
    $label = 'No state';
  }
  elseif ($state = WorkflowState::load($sid)) {
    $label = $state
      ->label();
  }
  else {
    $label = 'Unknown state';
  }
  return t($label);
}

/**
 * Determines the Workflow field_name of an entity.
 * If an entity has multiple workflows, only returns the first one.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity at hand.
 * @param string $field_name
 *   The field name. If given, will be passed as return value.
 *
 * @return string
 *   The found Field name.
 */
function workflow_get_field_name(EntityInterface $entity, $field_name = '') {
  if (!$entity) {

    // $entity may be empty on Entity Add page.
    return '';
  }
  if ($field_name) {
    return $field_name;
  }
  $fields = workflow_get_workflow_field_names($entity);
  $field_name = reset($fields);
  return $field_name;
}

/**
 * Functions to get the state of an entity.
 */

/**
 * Wrapper function to get a UserInterface object.
 *
 * @param \Drupal\Core\Session\AccountInterface|null $account
 *   An Account.
 *
 * @return \Drupal\user\UserInterface
 *   A User to check permissions, since we can't add Roles to AccountInterface.
 */
function workflow_current_user(AccountInterface $account = NULL) {
  if (!$account) {
    $account = \Drupal::currentUser();
  }
  return User::load($account
    ->id());
}

/**
 * Gets the current state ID of a given entity.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An entity.
 * @param string $field_name
 *   A Field name.
 *
 * @return string
 *   The current State ID.
 */
function workflow_node_current_state(EntityInterface $entity, $field_name = '') {
  return WorkflowManager::getCurrentStateId($entity, $field_name);
}

/**
 * Gets the previous state ID of a given entity.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An entity.
 * @param string $field_name
 *   A field_name.
 *
 * @return string
 *   The previous State ID.
 */
function workflow_node_previous_state(EntityInterface $entity, $field_name = '') {
  return WorkflowManager::getPreviousStateId($entity, $field_name);
}

/**
 * Get a specific workflow, given an entity type.
 * Only one workflow is possible per node type.
 * Caveat: gives undefined results with multiple workflows per entity.
 * @todo Support multiple workflows per entity.
 *
 * @param string $entity_bundle
 *   An entity bundle.
 * @param string $entity_type
 *   An entity type. This is passed when also the Field API must be checked.
 *
 * @return \Drupal\workflow\Entity\Workflow
 *   A Workflow object, or NULL if no workflow is retrieved.
 */
function workflow_get_workflows_by_type($entity_bundle, $entity_type) {
  static $map = [];
  if (isset($map[$entity_type][$entity_bundle])) {
    return $map[$entity_type][$entity_bundle];
  }
  $wid = FALSE;
  if (isset($entity_type)) {
    foreach (_workflow_info_fields(NULL, $entity_type, $entity_bundle) as $field_info) {
      $wid = $field_info
        ->getSetting('workflow_type');
    }
  }

  // Set the cache with a workflow object.
  $map[$entity_type][$entity_bundle] = NULL;
  if ($wid) {
    $map[$entity_type][$entity_bundle] = Workflow::load($wid);
  }
  return $map[$entity_type][$entity_bundle];
}

/**
 * Finds the Workflow fields on a given Entity type.
 *
 * @return mixed
 *
 * @see EntityFieldManager::getFieldMapByFieldType
 */
function workflow_get_workflow_fields_by_entity_type() {
  return \Drupal::service('entity_field.manager')
    ->getFieldMapByFieldType('workflow');
}

/**
 * Gets the workflow field names, if not known already.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   Object to work with. May be empty, e.g., on menu build.
 * @param string $entity_type
 *   Entity type of object. Optional, but required if $entity provided.
 * @param string $entity_bundle
 *   Bundle of entity. Optional.
 * @param string $field_name
 *   Field name. Optional.
 *
 * @return Drupal\field\Entity\FieldStorageConfig[]
 *   An array of FieldStorageConfig objects.
 */
function _workflow_info_fields($entity = NULL, $entity_type = '', $entity_bundle = '', $field_name = '') {
  $field_info = [];

  // Figure out the $entity's bundle and id.
  if ($entity) {
    $entity_type = $entity
      ->getEntityTypeId();
    $entity_bundle = $entity
      ->bundle();
  }
  else {

    // Entity type and bundle should be specified.
  }
  $field_list = \Drupal::service('entity_field.manager')
    ->getFieldMapByFieldType('workflow');
  foreach ($field_list as $e_type => $data) {
    if (!$entity_type || $entity_type == $e_type) {
      foreach ($data as $f_name => $value) {
        if (!$entity_bundle || isset($value['bundles'][$entity_bundle])) {
          if (!$field_name || $field_name == $f_name) {

            // Do not use the field_name as ID, but the
            // unique <entity_type>.<field_name> since you cannot share the
            // same field on multiple entity_types (unlike D7).
            $field_config = FieldStorageConfig::loadByName($e_type, $f_name);
            if ($field_config) {
              $field_info[$field_config
                ->id()] = $field_config;
            }
            else {

              // The field is a base/extra field.
              // not a configurable Field via Field UI.
              // Re-fetch the field definitions, with extra data.
              $field_definitions = \Drupal::service('entity_field.manager')
                ->getFieldDefinitions($e_type, $entity_bundle);

              // @todo Loop over bundles?

              /** @var \Drupal\Core\Field\BaseFieldDefinition $field_config */
              $field_config = $field_definitions[$f_name];
              if ($field_config) {
                $field_info[$field_config
                  ->getUniqueStorageIdentifier()] = $field_config;
              }
              else {

                // @todo Loop over bundles?
              }
            }
          }
        }
      }
    }
  }
  return $field_info;
}

/**
 * Helper function to get the entity from a route.
 *
 * This is a hack. It should be solved by using $route_match.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   An optional entity.
 * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
 *   A route.
 *
 * @return \Drupal\Core\Entity\EntityInterface
 *   Entity from the route.
 */
function workflow_url_get_entity(EntityInterface $entity = NULL, RouteMatchInterface $route_match = NULL) {
  if ($entity) {
    return $entity;
  }
  if (!$route_match) {
    $route_match = \Drupal::routeMatch();
  }
  $entities = [];
  foreach ($route_match
    ->getParameters() as $param) {
    if ($param instanceof EntityInterface) {
      $entities[] = $param;
    }
  }
  $value = reset($entities);
  if ($value && is_object($value)) {
    return $value;
  }
  if ($value && !is_object($value)) {

    // On workflow tab, we'd get an id.
    // This is an indicator that the route is mal-configured.
    workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'route declaration is not optimal.');

    /* Return $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($value); */
    return NULL;
  }
  return $value;
}

/**
 * Helper function to get the field name from a route.
 *
 * For now only used for ../{entity_id}/workflow history tab.
 *
 * @return string|null
 *   Return $field_name
 */
function workflow_url_get_field_name() {
  return workflow_url_get_parameter('field_name');
}

/**
 * Helper function to get the entity from a route.
 *
 * @return mixed|string
 *   Return $operation
 */
function workflow_url_get_operation() {
  $url = Url::fromRoute('<current>');

  // The last part of the path is the operation: edit, workflow, devel.
  $url_parts = explode('/', $url
    ->toString());
  $operation = array_pop($url_parts);

  // Except for view pages.
  if (is_numeric($operation) || $operation == 'view') {
    $operation = '';
  }
  return $operation;
}

/**
 * Helper function to get arbitrary parameter from a route.
 *
 * @param string $parameter
 *   The requested parameter.
 *
 * @return string
 *   field_name
 */
function workflow_url_get_parameter($parameter) {
  return \Drupal::routeMatch()
    ->getParameter($parameter);

  // Return \Drupal::request()->get($parameter);
}

/**
 * Helper function to determine Workflow from Workflow UI URL.
 *
 * @return \Drupal\workflow\Entity\Workflow
 *   Workflow Object.
 */
function workflow_url_get_workflow() {

  /** @var \Drupal\workflow\Entity\Workflow[] $workflows */
  static $workflows = [];
  $wid = workflow_url_get_parameter('workflow_type');
  if (is_object($wid)) {

    // $wid is a Workflow object.
    return $wid;
  }
  if (!isset($workflows[$wid])) {

    // $wid is a string.
    $workflows[$wid] = $wid ? Workflow::load($wid) : NULL;
  }
  return $workflows[$wid];
}

/**
 * Helper function to determine the title of the page.
 *
 * Used in file workflow.routing.yml.
 *
 * @return \Drupal\Core\StringTranslation\TranslatableMarkup
 *   the page title.
 */
function workflow_url_get_title() {
  $label = '';

  // Get the Workflow from the page.

  /** @var \Drupal\workflow\Entity\Workflow $workflow */

  /** @noinspection PhpAssignmentInConditionInspection */
  if ($workflow = workflow_url_get_workflow()) {
    $label = $workflow
      ->label();
  }
  $title = t('Edit @entity %label', [
    '@entity' => 'Workflow',
    '%label' => $label,
  ]);
  return $title;
}

/**
 * Helper function to determine Workflow from Workflow UI URL.
 *
 * @param string $url
 *   URL.
 *
 * @return mixed
 *   the Workflow type.
 */
function workflow_url_get_form_type($url = '') {

  // For some reason, $_SERVER is not allowed as default.
  $url = $url == '' ? $_SERVER['REQUEST_URI'] : $url;
  $base_url = '/config/workflow/workflow/';
  $string = substr($url, strpos($url, $base_url) + strlen($base_url));
  $type = explode('/', $string)[1];
  return $type;
}

Functions

Namesort descending Description
workflow_cron Implements hook_cron().
workflow_current_user Wrapper function to get a UserInterface object.
workflow_entity_delete Implements hook_entity_delete().
workflow_entity_insert Implements hook_entity_insert().
workflow_entity_presave Implements hook_entity_presave().
workflow_execute_transition
workflow_get_field_name Determines the Workflow field_name of an entity. If an entity has multiple workflows, only returns the first one.
workflow_get_sid_name Helper function, to get the label of a given State Id. deprecated: workflow_get_sid_label() --> workflow_get_sid_name()
workflow_get_user_role_names Retrieves the names of roles matching specified conditions.
workflow_get_workflows_by_type Get a specific workflow, given an entity type. Only one workflow is possible per node type. Caveat: gives undefined results with multiple workflows per entity. @todo Support multiple workflows per entity.
workflow_get_workflow_fields_by_entity_type Finds the Workflow fields on a given Entity type.
workflow_get_workflow_field_names Gets an Options list of field names.
workflow_get_workflow_names Get an options list for workflows. Include an initial empty value if requested. Validate each workflow, and generate a message if not complete.
workflow_get_workflow_state_names Get an options list for workflow states.
workflow_help @inheritdoc
workflow_hook_info Implements hook_hook_info().
workflow_node_current_state Gets the current state ID of a given entity.
workflow_node_previous_state Gets the previous state ID of a given entity.
workflow_theme Implements hook_theme().
workflow_url_get_entity Helper function to get the entity from a route.
workflow_url_get_field_name Helper function to get the field name from a route.
workflow_url_get_form_type Helper function to determine Workflow from Workflow UI URL.
workflow_url_get_operation Helper function to get the entity from a route.
workflow_url_get_parameter Helper function to get arbitrary parameter from a route.
workflow_url_get_title Helper function to determine the title of the page.
workflow_url_get_workflow Helper function to determine Workflow from Workflow UI URL.
workflow_user_cancel Implements hook_user_cancel().
workflow_user_delete Implements hook_user_delete().
workflow_workflow_type_insert Implements hook_ENTITY_TYPE_insert().
_workflow_execute_transitions Execute transitions. if prohibited, restore original field value.
_workflow_info_fields Gets the workflow field names, if not known already.

Constants