123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <?php
- /**
- * @file
- * Provides Features integration for Workflow using the CRUD API.
- *
- * As you will notice this file will only handle the <export> of Worflows,
- * including states and transitions. The <import> is handeled magically,
- * and all modifications are done in function Workflow::save().
- */
- define('WORKFLOW_FEATURES_AUTHOR_NAME', 'workflow_features_author_name');
- // Even if workflow Node is not enabled, Features may use Node API's type_maps.
- require_once dirname(__FILE__) . '/workflow.node.type_map.inc';
- /**
- * Default controller handling features integration.
- */
- class WorkflowFeaturesController extends EntityDefaultFeaturesController {
- /**
- * Generates the result for hook_features_export().
- */
- public function export($data, &$export, $module_name = '') {
- $pipe = parent::export($data, $export, $module_name);
- foreach ($data as $workflow_name) {
- if ($workflow = workflow_load_by_name($workflow_name)) {
- // Add dependency on workflow_node.
- if (count($workflow->getTypeMap())) {
- $export['dependencies']['workflownode'] = 'workflownode';
- }
- // Add dependency on workflow_field.
- $export['features']['Workflow'][$workflow_name] = $workflow_name;
- }
- }
- return $pipe;
- }
- /**
- * Generates the result for hook_features_export_render().
- *
- * This is a copy of the parent, adding 'system_roles'.
- * The workflow is imported in the target system with Workflow::save().
- */
- public function export_render($module, $data, $export = NULL) {
- $translatables = $code = array();
- $code[] = ' $workflows = array();';
- $code[] = '';
- foreach ($data as $identifier) {
- // Clone workflow to make sure changes are not propagated to original.
- if ($workflow = entity_load_single($this->type, $identifier)) {
- $this->export_render_workflow($workflow, $identifier, $code);
- }
- }
- $code[] = ' return $workflows;';
- $code = implode("\n", $code);
- $hook = isset($this->info['export']['default hook']) ? $this->info['export']['default hook'] : 'default_' . $this->type;
- return array($hook => $code);
- }
- /**
- * Renders the provided workflow into export code.
- *
- * @param Workflow $workflow
- * The workflow to export.
- * @param string $identifier
- * The unique machine name for the workflow in the export.
- * @param array $code
- * A reference to the export code array that will receive the output.
- */
- protected function export_render_workflow(Workflow $workflow, $identifier, array &$code) {
- // Make sure data is not copied to the database.
- $workflow = clone $workflow;
- $this->sanitize_workflow_for_export($workflow);
- // Make sure to escape the characters \ and '.
- // The following method has the advantage, that you can export with
- // features,
- // and later import without enabling Features in the target system.
- $workflow_export = addcslashes(entity_export($this->type, $workflow, ' '), '\\\'');
- $workflow_identifier = features_var_export($identifier);
- $code[] = " // Exported workflow: {$workflow_identifier}";
- $code[] = " \$workflows[{$workflow_identifier}] = entity_import('{$this->type}', '" . $workflow_export . "');";
- $code[] = ''; // Blank line
- }
- /**
- * Prepares the provided workflow for export.
- *
- * Removes serial IDs and replaces them with machine names.
- *
- * @param Workflow $workflow
- * The workflow to sanitize. The contents of this object are modified directly.
- */
- protected function sanitize_workflow_for_export(Workflow $workflow) {
- // Eliminate serial IDs in exports to prevent "Overridden" status.
- // We use machine names instead.
- unset($workflow->wid);
- // Add roles to translate role IDs on target system.
- $permission = NULL;
- $workflow->system_roles = workflow_get_roles($permission);
- $sid_to_name_map = $this->pack_states($workflow);
- $this->pack_transitions($workflow, $sid_to_name_map);
- }
- /**
- * "Packs" the states in the provided workflow into an export-friendly format.
- *
- * @param Workflow $workflow
- * The workflow to pack. The contents of this object are modified directly.
- *
- * @return array
- * A map of the old state IDs to their new machine names.
- */
- protected function pack_states(Workflow $workflow) {
- $named_states = array();
- $sid_to_name_map = array();
- foreach ($workflow->states as $state) {
- /* @var WorkflowState $state */
- $name = $state->getName();
- $sid_to_name_map[$state->sid] = $name;
- // Eliminate serial IDs in exports to prevent "Overridden" status.
- // We use machine names instead.
- unset($state->sid);
- unset($state->wid);
- $named_states[$name] = $state;
- }
- ksort($named_states);
- // Identify states by machine name.
- $workflow->states = $named_states;
- return $sid_to_name_map;
- }
- /**
- * "Packs" the transitions in the provided workflow into an export-friendly format.
- *
- * @param Workflow $workflow
- * The workflow to pack. The contents of this object are modified directly.
- *
- * @param array $sid_to_name_map
- * The map of numeric state IDs to their machine names, for remapping sid
- * references.
- */
- protected function pack_transitions(Workflow $workflow, array $sid_to_name_map) {
- $named_transitions = array();
- foreach ($workflow->transitions as $transition) {
- /* @var WorkflowTransition $transition */
- $start_name = $sid_to_name_map[$transition->sid];
- $end_name = $sid_to_name_map[$transition->target_sid];
- $new_name = WorkflowConfigTransition::machineName($start_name, $end_name);
- $transition->name = $new_name;
- $transition->start_state = $start_name;
- $transition->end_state = $end_name;
- // Eliminate serial IDs in exports to prevent "Overridden" status.
- // We use machine names instead.
- unset($transition->wid);
- unset($transition->tid);
- unset($transition->sid);
- unset($transition->target_sid);
- $named_transitions[$new_name] = $transition;
- }
- ksort($named_transitions);
- // Identify transitions by new machine name.
- $workflow->transitions = $named_transitions;
- }
- /**
- * Revert this workflow, either creating the workflow new (if one with the
- * same machine name is not present), or updating the existing workflow.
- *
- * @param string $module
- * The name of the feature module whose components should be reverted.
- */
- function revert($module = NULL) {
- // Loads defaults from feature code.
- $defaults = workflow_get_defaults($module);
- foreach ($defaults as $machine_name => $entity) {
- workflow_revert($defaults, $machine_name);
- }
- }
- }
- /**
- * Implements hook_features_COMPONENT_alter().
- *
- * Adds the corresponding Workflow to the WorkflowField.
- */
- function workflow_features_pipe_field_base_alter(&$pipe, $data, $export) {
- if (!empty($data)) {
- foreach ($data as $field_name) {
- // $info = field_info_field($field_name);
- $field = _workflow_info_field($field_name);
- if ($field['type'] == 'workflow') {
- // $field['settings']['wid'] can be numeric or named.
- $workflow = workflow_load_single($field['settings']['wid']);
- // Fields might reference missing workflows.
- if (!empty($workflow)) {
- $pipe['Workflow'][] = $workflow->name;
- }
- }
- }
- }
- }
- /**
- * Implements hook_features_api_alter().
- *
- * Ensures Workflow always fires last during rebuild, to ensure that roles
- * referenced by workflows to be loaded-in when features contain roles.
- */
- function workflow_features_api_alter(array &$components) {
- // FIXME: Why is Workflow the only features provider with an uppercase component name?
- $component_name = 'Workflow';
- if (isset($components[$component_name])) {
- $setting = $components[$component_name];
- unset($components[$component_name]);
- $components[$component_name] = $setting;
- }
- }
|