protected function isValidFieldname(FieldStorageConfig $field_storage, FieldableEntityInterface $entity) { $comment_field_name_ok = FALSE; if ($field_storage->getTargetEntityTypeId() !== 'comment') { return TRUE; } $field_name = $field_storage->get('field_name'); // Check if the 'comment' field name exists on the 'commented' entity type. // @todo: Still not waterproof. You could have a field on a non-relevant entity_type. foreach (_workflow_info_fields() as $key => $info) { if ($info->getName() == $field_name && $info->getTargetEntityTypeId() !== 'comment') { $comment_field_name_ok = TRUE; } } return $comment_field_name_ok; }
/** * {@inheritdoc} */ protected function blockAccess(AccountInterface $account) { /* @var $entity EntityInterface */ if (!($entity = workflow_url_get_entity())) { return AccessResult::forbidden(); } // Only show block on entity view page (when default operation = ''). if ($operation = workflow_url_get_operation()) { return AccessResult::forbidden(); } // Only show block if entity has workflow, and user has permission. foreach (_workflow_info_fields($entity) as $definition) { $type_id = $definition->getSetting('workflow_type'); if ($account->hasPermission("access {$type_id} workflow_transition form")) { return AccessResult::allowed(); } } return AccessResult::forbidden(); }
/** * Returns the number of entities with this state. * * @return int * Counted number. * * @todo: add $options to select on entity type, etc. */ public function count() { $count = 0; $sid = $this->id(); foreach ($fields = _workflow_info_fields() as $field_info) { $field_name = $field_info->getName(); $query = \Drupal::entityQuery($field_info->getTargetEntityTypeId()); // @see #2285983 for using SQLite on D7. $count += $query->condition($field_name, $sid, '=')->count()->execute(); } return $count; }
/** * Determines if the column 'Field name' must be shown. * * @param EntityInterface $entity * * @return bool */ protected function showColumnFieldname(EntityInterface $entity) { if (is_null($this->show_column_fieldname)) { // @todo: also remove when field_name is set in route?? if (count(_workflow_info_fields($entity)) > 1) { $this->show_column_fieldname = TRUE; } } return $this->show_column_fieldname; }
/** * Returns the number of entities with this state. * * @return int * Counted number. * * @todo: add $options to select on entity type, etc. */ public function count() { $sid = $this->sid; // Get the numbers for Workflow Node. $result = db_select('workflow_node', 'wn')->fields('wn')->condition('sid', $sid, '=')->execute(); $count = count($result->fetchAll()); // @see #2285983 for using SQLite. // Get the numbers for Workflow Field. $fields = _workflow_info_fields(); foreach ($fields as $field_name => $field_map) { if ($field_map['type'] == 'workflow') { $query = new EntityFieldQuery(); $query->fieldCondition($field_name, 'value', $sid, '=')->count(); // We only need the count. $result = $query->execute(); $count += $result; } } return $count; }
/** * {@inheritdoc} */ public static function executeTransitionsOfEntity(EntityInterface $entity) { // Avoid this hook on workflow objects. if (in_array($entity->getEntityTypeId(), ['workflow_type', 'workflow_state', 'workflow_config_transition', 'workflow_transition', 'workflow_scheduled_transition'])) { return; } foreach (_workflow_info_fields($entity) as $field_info) { $field_name = $field_info->getName(); /* @var $transition WorkflowTransitionInterface */ $transition = $entity->{$field_name}->__get('workflow_transition'); if ($transition) { if ($entity->getEntityTypeId() !== 'comment') { // We come from Content edit page, from widget. // Set the just-saved entity explicitly. Not necessary for update, // but upon insert, the old version didn't have an ID, yet. $transition->setTargetEntity($entity); } $transition->execute(); } else { // We come from WorkflowTransitionForm, which explicitly save the entity. // The transition is executed by the form. } } }
/** * {@inheritdoc} */ public function isDeletable() { $is_deletable = FALSE; // May not be deleted if assigned to a Field. foreach ($fields = _workflow_info_fields() as $field_info) { if ($field_info->getSetting('workflow_type') == $this->id()) { return FALSE; } } // D8-port: This is deleted, since it is only for D7's workflow_node. // // May not be deleted if a State is assigned to a state. // foreach ($this->getStates(TRUE) as $state) { // if ($state->count()) { // return $is_deletable; // } // } $is_deletable = TRUE; return $is_deletable; }
/** * Returns if the Workflow may be deleted. * * @return bool $is_deletable * TRUE if a Workflow may safely be deleted. */ public function isDeletable() { $is_deletable = FALSE; // May not be deleted if a TypeMap exists. if ($this->getTypeMap()) { return $is_deletable; } // May not be deleted if assigned to a Field. foreach (_workflow_info_fields() as $field) { if ($field['settings']['wid'] == $this->wid) { return $is_deletable; } } // May not be deleted if a State is assigned to a state. foreach ($this->getStates(TRUE) as $state) { if ($state->count()) { return $is_deletable; } } $is_deletable = TRUE; return $is_deletable; }
/** * Implements hook_field_settings_form() -> ConfigFieldItemInterface::settingsForm(). */ public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) { $element = array(); // Create list of all Workflow types. Include an initial empty value. // Validate each workflow, and generate a message if not complete. $workflows = workflow_get_workflow_names(FALSE); // @todo D8: add this to WorkflowFieldConstraintValidator. // Set message, if no 'validated' workflows exist. if (count($workflows) == 1) { drupal_set_message(t('You must create at least one workflow before content can be assigned to a workflow.'), 'warning'); } // Validate via annotation WorkflowFieldConstraint. Show a message for each error. $violation_list = $this->validate(); foreach ($violation_list->getIterator() as $violation) { switch ($violation->getPropertyPath()) { case 'fieldnameOnComment': // A 'comment' field name MUST be equal to content field name. // @todo: Still not waterproof. You could have a field on a non-relevant entity_type. drupal_set_message($violation->getMessage(), 'error'); $workflows = array(); break; default: break; } } // Set the required workflow_type on 'comment' fields. // N.B. the following must BELOW the (count($workflows) == 1) snippet. $field_storage = $this->getFieldDefinition()->getFieldStorageDefinition(); if (!$this->getSetting('workflow_type') && $field_storage->getTargetEntityTypeId() == 'comment') { $field_name = $field_storage->get('field_name'); $workflows = array(); foreach (_workflow_info_fields($entity = NULL, $entity_type = '', $entity_bundle = '', $field_name) as $key => $info) { if ($info->getName() == $field_name && $info->getTargetEntityTypeId() !== 'comment') { $wid = $info->getSetting('workflow_type'); $workflow = Workflow::load($wid); $workflows[$wid] = $workflow->label(); } } } // Let the user choose between the available workflow types. $wid = $this->getSetting('workflow_type'); $url = \Drupal\Core\Url::fromRoute('entity.workflow_type.collection'); $element['workflow_type'] = array('#type' => 'select', '#title' => t('Workflow type'), '#options' => $workflows, '#default_value' => $wid, '#required' => TRUE, '#disabled' => $has_data, '#description' => t('Choose the Workflow type. Maintain workflows <a href=":url">here</a>.', array(':url' => $url->toString()))); // Get a string representation to show all options. /* * Overwrite ListItemBase::storageSettingsForm(). */ $allowed_values = WorkflowState::loadMultiple([], $wid); $allowed_values_function = $this->getSetting('allowed_values_function'); $element['allowed_values'] = array('#type' => 'textarea', '#title' => t('Allowed values for the selected Workflow type'), '#default_value' => $wid ? $this->allowedValuesString($allowed_values) : [], '#rows' => count($allowed_values), '#access' => $wid ? TRUE : FALSE, '#disabled' => TRUE, '#element_validate' => array(array(get_class($this), 'validateAllowedValues')), '#field_has_data' => $has_data, '#field_name' => $this->getFieldDefinition()->getName(), '#entity_type' => $this->getEntity()->getEntityTypeId(), '#allowed_values' => $allowed_values); $element['allowed_values']['#description'] = $this->allowedValuesDescription(); return $element; }
/** * Menu access control callback. Checks access to Workflow tab. * * This used to be D7-function workflow_tab_access($user, $entity). * * The History tab should not be used with multiple workflows per entity. * Use the dedicated view for this use case. * @todo D8: remove this in favour of View 'Workflow history per entity'. * @todo D8-port: make this workf for non-Node entity types. * * @param \Drupal\workflow\Controller\AccountInterface $account * Run access checks for this account. * * @return \Drupal\Core\Access\AccessResult */ public function historyAccess(AccountInterface $account) { static $access = array(); $uid = $account ? $account->id() : -1; // TODO D8-port: make Workflow History tab happen for every entity_type. // @see workflow.routing.yml, workflow.links.task.yml, WorkflowTransitionListController. // ATM it only works for Nodes and Terms. // This is a hack. The Route should always pass an object. // On view tab, $entity is object, // On workflow tab, $entity is id(). // Get the entity for this form. $entity = workflow_url_get_entity(); /* @var $entity EntityInterface */ // Figure out the $entity's bundle and id. $entity_type = $entity->getEntityTypeId(); $entity_bundle = $entity->bundle(); $entity_id = $entity ? $entity->id() : ''; $field_name = workflow_url_get_field_name(); if (isset($access[$uid][$entity_type][$entity_id][$field_name ? $field_name : 'no_field'])) { return $access[$uid][$entity_type][$entity_id][$field_name ? $field_name : 'no_field']; } $access_result = AccessResult::forbidden(); // When having multiple workflows per bundle, use Views display // 'Workflow history per entity' instead! $fields = _workflow_info_fields($entity, $entity_type, $entity_bundle, $field_name); if (!$fields) { return AccessResult::forbidden(); } else { // @todo: Keep below code aligned between WorkflowState, ~Transition, ~TransitionListController $uid = $account ? $account->id() : -1; $entity_id = $entity ? $entity->id() : ''; // Determine if user is owner of the entity. $is_owner = WorkflowManager::isOwner($account, $entity); /** * Determine if user has Access. Fill the cache. */ // @todo: what to do with multiple workflow_fields per bundle? Use Views instead! Or introduce a setting. // @TODO D8-port: workflow_tab_access: use proper 'WORKFLOW_TYPE' permissions foreach ($fields as $definition) { $type_id = $definition->getSetting('workflow_type'); if ($account->hasPermission("access any {$type_id} workflow_transion overview")) { $access_result = AccessResult::allowed(); } elseif ($is_owner && $account->hasPermission("access own {$type_id} workflow_transion overview")) { $access_result = AccessResult::allowed(); } elseif ($account->hasPermission('administer nodes')) { $access_result = AccessResult::allowed(); } $access[$uid][$entity_type][$entity_id][$field_name ? $field_name : 'no_field'] = $access_result; } } return $access_result; }