workflow.api.php in Workflow 8
Same filename and directory in other branches
Hooks provided by the workflow module.
File
workflow.api.phpView source
<?php
/**
* @file
* Hooks provided by the workflow module.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\user\UserInterface;
use Drupal\workflow\Entity\WorkflowConfigTransition;
use Drupal\workflow\Entity\WorkflowState;
use Drupal\workflow\Entity\WorkflowTransitionInterface;
/**
* Implements hook_workflow_operations().
*
* Adds extra operations to ListBuilders:
* - Workflow, WorkflowState, WorkflowTransition;
*
* @param string $op
* 'top_actions': Allow modules to insert their own front page action links.
* 'operations': Allow modules to insert their own workflow operations.
* 'workflow': Allow modules to insert workflow operations.
* 'state': Allow modules to insert state operations.
* @param \Drupal\Core\Entity\EntityInterface|null $entity
* The current workflow/state/transition object.
*
* @return array
* The new actions, to be added to the entity list.
*/
function hook_workflow_operations($op, EntityInterface $entity = NULL) {
$operations = [];
switch ($op) {
case 'top_actions':
// As of D8, below hook_workflow_operations is removed, in favour of core hooks.
// @see workflow.links.action.yml for an example top action.
return $operations;
case 'operations':
break;
case 'workflow':
// This example adds an operation to the 'operations column' of the Workflow List.
/** @var \Drupal\workflow\Entity\Workflow $workflow */
$workflow = $entity;
$alt = t('Control content access for @wf', [
'@wf' => $workflow
->label(),
]);
$attributes = [
'alt' => $alt,
'title' => $alt,
];
$operations['workflow_access_form'] = [
'title' => t('Access'),
'weight' => 50,
'url' => Url::fromRoute('entity.workflow_type.access_form', [
'workflow_type' => $workflow
->id(),
]),
'query' => \Drupal::destination()
->getAsArray(),
];
return $operations;
case 'state':
/** @var \Drupal\workflow\Entity\WorkflowState $state */
$state = $entity;
break;
case 'workflow_transition':
// As of D8, below hook_workflow_operations is removed, in favour of core hooks.
// @see EntityListBuilder::getOperations, workflow_operations, workflow.api.php.
// Your module may add operations to the Entity list.
/** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
$transition = $entity;
break;
default:
break;
}
return $operations;
}
/**
* Implements hook_workflow().
*
* NOTE: This hook may reside in the implementing module
* or in a module.workflow.inc file.
*
* @param string $op
* The current workflow operation.
* E.g., 'transition pre', 'transition post'.
* @param \Drupal\workflow\Entity\WorkflowTransitionInterface $transition
* The transition, that contains all of the above.
* @param \Drupal\user\UserInterface $user
*
* @return bool|void
* The return value, depending on $op.
*/
function hook_workflow($op, WorkflowTransitionInterface $transition, UserInterface $user) {
switch ($op) {
case 'transition permitted':
// As of version 8.x-1.x, this operation is never called to check if transition is permitted.
// This was called in the following situations:
// case 1. when building a workflow widget with list of available transitions;
// case 2. when executing a transition, just before the 'transition pre';
// case 3. when showing a 'revert state' link in a Views display.
// Your module's implementation may return FALSE here and disallow
// the execution, or avoid the presentation of the new State.
// This may be user-dependent.
// As of version 8.x-1.x:
// case 1: use hook_workflow_permitted_state_transitions_alter(),
// case 2: use the 'transition pre' operation,
// case 3: use the 'transition pre' operation.
return TRUE;
case 'transition revert':
// Hook is called when showing the Transition Revert form.
// Implement this hook if you need to control this.
// If you return FALSE here, you will veto the transition.
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $op, '');
return TRUE;
case 'transition pre':
// The workflow module does nothing during this operation.
// Implement this hook if you need to change/do something BEFORE anything
// is saved to the database.
// If you return FALSE here, you will veto the transition.
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $op, '');
return TRUE;
case 'transition post':
// In D7, this is called by Workflow Node during update of the state, directly
// after updating the Workflow. Workflow Field does not call this,
// since you can call a hook_entity_* event after saving the entity.
// @see https://api.drupal.org/api/drupal/includes%21module.inc/group/hooks/7
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $op, '');
return TRUE;
case 'transition delete':
case 'state delete':
case 'workflow delete':
// These hooks are removed in D8, in favour of the core hooks:
// - workflow_entity_predelete(EntityInterface $entity)
// - workflow_entity_delete(EntityInterface $entity)
// See examples at the bottom of this file.
return TRUE;
}
return TRUE;
}
/**
* Implements hook_workflow_history_alter().
*
* In D8, hook_workflow_history_alter() is removed, in favour
* of ListBuilder::getDefaultOperations
* and hook_workflow_operations('workflow_transition').
*
* Allow other modules to add Operations to the most recent history change.
* E.g., Workflow Revert implements an 'undo' operation.
*
* @param array $variables
* The current workflow history information as an array.
* 'old_sid' - The state ID of the previous state.
* 'old_state_name' - The state name of the previous state.
* 'sid' - The state ID of the current state.
* 'state_name' - The state name of the current state.
* 'history' - The row from the workflow_transition_history table.
* 'transition' - a WorkflowTransition object, containing all of the above.
*/
function hook_workflow_history_alter(array &$variables) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, '', '');
// The Workflow module does nothing with this hook.
// For an example implementation, see the Workflow Revert add-on.
}
/**
* Implements hook_workflow_comment_alter().
*
* Allow other modules to change the user comment when saving a state change.
*
* @param string $comment
* The comment of the current state transition.
* @param array $context
* 'transition' - The current transition itself.
*/
function hook_workflow_comment_alter(&$comment, array &$context) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, '', '');
/** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
$transition = $context['transition'];
//$comment = $transition->getOwner()->getUsername() . ' says: ' . $comment;
}
/**
* Implements hook_workflow_permitted_state_transitions_alter().
*
* This hook allows you to add custom filtering of allowed target states, add
* new custom states, change labels, etc.
* It is invoked in WorkflowState::getOptions().
*
* @param array $transitions
* An array of allowed transitions from the current state (as provided in
* $context). They are already filtered by the settings in Admin UI.
* @param array $context
* An array of relevant objects. Currently:
* @code
* $context = array(
* 'user' => $user,
* 'workflow' => $workflow,
* 'state' => $current_state,
* 'force' => $force,
* );
* @endcode
*/
function hook_workflow_permitted_state_transitions_alter(array &$transitions, array $context) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, '', '');
// User may have the custom role AUTHOR.
$user = $context['user'];
// The following could be fetched from each transition.
$workflow = $context['workflow'];
$current_state = $context['state'];
// The following could be fetched from the $user and $transition objects.
$force = $context['force'];
// Implement here own permission logic.
foreach ($transitions as $key => $transition) {
/** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition*/
if (!$transition
->isAllowed($user, $force)) {
// unset($transitions[$key]);
}
}
// This example creates a new custom target state.
$values = [
// Fixed values for new transition.
'wid' => $context['workflow']
->id(),
'from_sid' => $context['state']
->id(),
// Custom values for new transition.
// The ID must be an integer, due to db-table constraints.
'to_sid' => '998',
'label' => 'go to my new fantasy state',
];
$new_transition = WorkflowConfigTransition::create($values);
// $transitions[] = $new_transition;
}
/**********************************************************************
* Hooks defined by core Form API: hooks to to alter the Workflow Form/Widget.
*/
/**
* Alter forms for field widgets provided by other modules.
*
* @param $element
* The field widget form element as constructed by hook_field_widget_form().
* @param $form_state
* An associative array containing the current state of the form.
* @param $context
* An associative array containing the following key-value pairs, matching the
* arguments received by hook_field_widget_form():
*
* - form: The form structure to which widgets are being attached. This may be
* a full form structure, or a sub-element of a larger form.
* - field: The field structure.
* - instance: The field instance structure.
* - langcode: The language associated with $items.
* - items: Array of default values for this field.
* - delta: The order of this item in the array of subelements (0, 1, 2, etc).
*
* @see hook_field_widget_form()
* @see hook_field_widget_WIDGET_TYPE_form_alter()
*/
function hook_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
// A hook for changing any widget. Better use below (more specific) hooks.
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $context['widget']->getPluginId(), '');
}
function hook_field_widget_workflow_default_form_alter(&$element, FormStateInterface $form_state, $context) {
// A hook specific for the 'workflow_default' widget.
// D7: This hook is introduced in Drupal 7.8.
// D8: This name is specified in the annotation of WorkflowDefaultWidget.
workflow_debug(__FILE__, __FUNCTION__, __LINE__, '', '');
// A widget on an entity form.
if ('workflow_default' != $context['widget']
->getPluginId()) {
return;
}
// This object contains all you need. You may find it in one of two locations.
/** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
if (!isset($element['#default_value'])) {
return;
}
if (!($transition = $element['#default_value'])) {
return;
}
// An example of customizing/overriding the workflow widget.
// Beware, until now, you must do this twice: on the widget and on the form.
if ($transition
->getOwnerId() == 1) {
\Drupal::messenger()
->addWarning('(Test/Devel message) I got you, user 1,
you will never schedule again, and you WILL document each state change!');
// Let's prohibit scheduling for user 1.
$element['workflow_scheduling']['#access'] = FALSE;
// Let's prohibit scheduling for user 1.
if ($element['comment']['#access'] == TRUE) {
$element['comment']['#required'] = TRUE;
}
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Use this hook to alter the form.
* It is only suited if you only use View Page or Workflow Tab.
* If you change the state on the Entity Edit page (form), you need the hook
* hook_form_alter(). See below for more info.
*/
function hook_form_workflow_transition_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $form_id, '');
// The WorkflowTransitionForm (E.g., Workflow History tab, Block).
// It has its own handling.
// @todo Populate the WorkflowTransitionForm with a Widget, so we have 1 way-of-working.
// Let's take a (changeable) reference to the element.
$workflow_element =& $form;
// This object contains all you need. You may find it in one of two locations.
/** @var \Drupal\workflow\Entity\WorkflowTransitionInterface $transition */
$transition = $form['workflow_transition']['#value'];
// An example of customizing/overriding the workflow widget.
// Beware, until now, you must do this twice: on the widget and on the form.
if ($transition
->getOwnerId() == 1) {
\Drupal::messenger()
->addWarning('(Test/Devel message) I got you, user 1,
you will never schedule again, and you WILL document each state change!');
// Let's prohibit scheduling for user 1.
$workflow_element['workflow_scheduling']['#access'] = FALSE;
// Let's prohibit scheduling for user 1.
if ($workflow_element['comment']['#access'] == TRUE) {
$workflow_element['comment']['#required'] = TRUE;
}
}
// Get the Entity.
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = NULL;
//$entity = $form['workflow_entity']['#value'];
$entity_type = 'node';
// $form['workflow_entity_type']['#value'];
$entity_bundle = '';
// $entity->bundle();
$sid = '';
if ($entity) {
$entity_type = $entity
->getEntityTypeId();
$entity_bundle = $entity
->bundle();
// Get the current State ID.
$sid = workflow_node_current_state($entity, $field_name = NULL);
// Get the State object, if needed.
$state = WorkflowState::load($sid);
}
// Change the form, depending on the state ID. @todo Update D8 machine name.
// In the upcoming version 7.x-2.4, States should have a machine_name, too.
if ($entity_type == 'node' && $entity_bundle == 'MY_NODE_TYPE') {
switch ($sid) {
case '2':
// Change form element, form validate and form submit for state '2'.
break;
case '3':
// Change form element, form validate and form submit for state '3'.
break;
}
}
}
/**
* Implements hook_form_alter().
*
* @usage Use this hook to alter the form on an Entity Form, Comment Form (Edit page).
*
* @see hook_form_workflow_transition_form_alter() for example code.
*/
function hook_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (substr($form_id, 0, 8) == 'workflow') {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, $form_id, '');
}
}
/**
* Implements hook_copy_form_values_to_transition_field_alter().
*
* @see #2899025 'Attached field type 'file' not working on WorkflowTransition'.
*/
function hook_copy_form_values_to_transition_field_alter(EntityInterface $entity, $context) {
/** @var \Drupal\Core\Field\Entity\BaseFieldOverride $field */
$field = $context['field'];
$field_name = $context['field_name'];
$user_input = $context['user_input'];
// Workaround for issue 2899025, but works only with entity_browser module.
// @see https://www.drupal.org/project/workflow/issues/2899025
// Issue 'Attached field type 'file' not working on WorkflowTransition'
if ($field
->getType() == 'file' && !empty($user_input['current'])) {
workflow_debug(__FILE__, __FUNCTION__, __LINE__, '', '');
// Avoid inserting two references to the same file.
// Workaround for issue #2926094 'Avoid calling the WorkflowTransitionElement twice on a form'.
$entity->{$field_name} = [];
foreach ($user_input['current'] as $target_id => $values) {
$data = [
"target_id" => $target_id,
"description" => $values["meta"]["description"],
];
$entity->{$field_name}[] = $data;
}
}
}
/**
* Hooks defined by core Entity: hook_entity_CRUD.
*
* Instead of using hook_entity_OPERATION, better use hook_ENTITY_TYPE_OPERATION.
*
* @see hook_entity_create(), hook_entity_update(), etc.
* @see hook_ENTITY_TYPE_create(), hook_ENTITY_TYPE_update(), etc.
*/
function hook_entity_predelete(EntityInterface $entity) {
if (substr($entity
->getEntityTypeId(), 0, 8) == 'workflow') {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'pre-delete', $entity->getEntityTypeId());
}
switch ($entity
->getEntityTypeId()) {
case 'workflow_config_transition':
case 'workflow_state':
case 'workflow_type':
// Better use hook_ENTITY_TYPE_OPERATION.
// E.g., hook_workflow_type_predelete.
break;
}
}
function hook_entity_delete(EntityInterface $entity) {
if (substr($entity
->getEntityTypeId(), 0, 8) == 'workflow') {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'delete', $entity->getEntityTypeId());
}
}
function hook_workflow_type_delete(EntityInterface $entity) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'delete', $entity->getEntityTypeId());
}
function hook_workflow_config_transition_delete(EntityInterface $entity) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'delete', $entity->getEntityTypeId());
}
function hook_workflow_state_delete(EntityInterface $entity) {
// workflow_debug(__FILE__, __FUNCTION__, __LINE__, 'delete', $entity->getEntityTypeId());
}
Functions
Name | Description |
---|---|
hook_copy_form_values_to_transition_field_alter | Implements hook_copy_form_values_to_transition_field_alter(). |
hook_entity_delete | |
hook_entity_predelete | Hooks defined by core Entity: hook_entity_CRUD. |
hook_field_widget_form_alter | Alter forms for field widgets provided by other modules. |
hook_field_widget_workflow_default_form_alter | |
hook_form_alter | Implements hook_form_alter(). |
hook_form_workflow_transition_form_alter | Implements hook_form_BASE_FORM_ID_alter(). |
hook_workflow | Implements hook_workflow(). |
hook_workflow_comment_alter | Implements hook_workflow_comment_alter(). |
hook_workflow_config_transition_delete | |
hook_workflow_history_alter | Implements hook_workflow_history_alter(). |
hook_workflow_operations | Implements hook_workflow_operations(). |
hook_workflow_permitted_state_transitions_alter | Implements hook_workflow_permitted_state_transitions_alter(). |
hook_workflow_state_delete | |
hook_workflow_type_delete |