workflow.features.inc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. /**
  3. * @file
  4. * Intergrates workflow with features.
  5. */
  6. define('WORKFLOW_FEATURES_AUTHOR_NAME', 'workflow_features_author_name');
  7. /**
  8. * Workflows are a **faux-exportable** component.
  9. */
  10. /**
  11. * Implements hook_features_export().
  12. */
  13. function workflow_features_export($data, &$export, $module_name = '') {
  14. // fontyourface_default_fonts integration is provided by Features.
  15. $export['dependencies']['features'] = 'features';
  16. $export['dependencies']['workflow'] = 'workflow';
  17. foreach (workflow_get_workflows() as $workflow) {
  18. if (in_array($workflow->name, $data)) {
  19. $export['features']['workflow'][$workflow->name] = $workflow->name;
  20. }
  21. }
  22. return $export;
  23. }
  24. /**
  25. * Implements hook_features_export_render().
  26. */
  27. function workflow_features_export_render($module, $data) {
  28. $translatables = $code = array();
  29. $code[] = ' $workflows = array();';
  30. $code[] = '';
  31. $workflows = workflow_get_workflows();
  32. foreach ($data as $name) {
  33. if ($workflow = workflow_get_workflows_full_object($name)) {
  34. unset($workflow->wid);
  35. $workflow_export = features_var_export($workflow, ' ');
  36. $workflow_identifier = features_var_export($workflow->name);
  37. $code[] = " // Exported workflow: $name";
  38. $code[] = " \$workflows[{$workflow_identifier}] = {$workflow_export};";
  39. $code[] = "";
  40. }
  41. }
  42. $code[] = ' return $workflows;';
  43. $code = implode("\n", $code);
  44. return array('workflow_default_workflows' => $code);
  45. }
  46. /**
  47. * Implements hook_features_export_options().
  48. */
  49. function workflow_features_export_options() {
  50. $workflows = array();
  51. foreach (workflow_get_workflows() as $workflow) {
  52. $workflows[$workflow->name] = $workflow->name;
  53. }
  54. return $workflows;
  55. }
  56. /**
  57. * Implements hook_features_revert().
  58. */
  59. function workflow_features_revert($module) {
  60. // Including the features inc to make sure this func is available during install of a Features module.
  61. module_load_include('inc', 'features', 'features.export');
  62. foreach (features_get_default('workflow', $module) as $key => $workflow) {
  63. workflow_update_workflows_full_object($workflow);
  64. }
  65. }
  66. /**
  67. * Implements hook_features_export_rebuild().
  68. */
  69. function workflow_features_export_rebuild($module) {
  70. workflow_features_revert($module);
  71. }
  72. /**
  73. * CRUD style functions below.
  74. */
  75. /**
  76. * For use by CRUD only, save everything from the CRUD formed object.
  77. *
  78. * @see workflow_get_workflows_full_object
  79. *
  80. * @param $workflow
  81. * A fully loaded workflow object to save the states of.
  82. *
  83. * @return
  84. * Returns whether the workflow was saved fully.
  85. */
  86. function workflow_update_workflows_full_object($workflow) {
  87. $workflow = (object) $workflow;
  88. // Given a workflow in the format returned from export.
  89. // First we grab the states, transitions and node_maps out.
  90. $states = isset($workflow->states) ? $workflow->states : array();
  91. $transitions = isset($workflow->transitions) ? $workflow->transitions : array();
  92. $node_types = isset($workflow->node_types) ? $workflow->node_types : array();
  93. unset($workflow->states, $workflow->transitions, $workflow->node_types);
  94. // Then make a workflow so we can track by wid.
  95. if ($orig_workflow = workflow_get_workflows_by_name($workflow->name)) {
  96. $workflow->wid = $orig_workflow->wid;
  97. }
  98. workflow_update_workflows($workflow, FALSE);
  99. // Cancel out if workflow failed to save.
  100. if (!isset($workflow->wid) || empty($workflow->wid)) {
  101. return FALSE;
  102. }
  103. // Workflow is now a fully vetted workflow object. We have NOT created a creation state with this.
  104. // Then make states, marking state name to state sid.
  105. $active_states = array();
  106. foreach ($states as $state) {
  107. $state = (object) $state;
  108. $state->wid = $workflow->wid;
  109. if ($orig_state = workflow_get_workflow_states_by_wid_state($state->wid, $state->state)) {
  110. $state->sid = $orig_state->sid;
  111. }
  112. workflow_update_workflow_states($state);
  113. $active_states[$state->state] = $state->sid;
  114. }
  115. // Delete any states *not* in our original construction.
  116. foreach (workflow_get_workflow_states_by_wid($workflow->wid) as $state) {
  117. if (!in_array($state->sid, $active_states)) {
  118. workflow_delete_workflow_states_by_sid($state->sid);
  119. }
  120. }
  121. // Then make transitions with the state mapping.
  122. foreach ($transitions as $transition) {
  123. $transition = (object) $transition;
  124. $transition->sid = $active_states[$transition->state];
  125. $transition->target_sid = $active_states[$transition->target_state];
  126. // Roles are exported by rolename, so need to translate to RID.
  127. $transition->roles = !empty($transition->roles) ? _workflow_roles_to_rids($transition->roles) : '';
  128. workflow_update_workflow_transitions($transition);
  129. }
  130. // Then add the node_type mapping.
  131. foreach ($node_types as $node_type) {
  132. $node_type = (object) array(
  133. 'type' => $node_type,
  134. 'wid' => $workflow->wid
  135. );
  136. // Insert, nodes only have one workflow. Insert will delete any prior workflow assoc.
  137. workflow_insert_workflow_type_map($node_type);
  138. }
  139. return TRUE;
  140. }
  141. /**
  142. * For use by CRUD only, gather everything into the CRUD formed object.
  143. *
  144. * @param $name
  145. * A string corresponding to a workflow object.
  146. *
  147. * @return
  148. * A fully loaded workflow object with type and statue mappings.
  149. */
  150. function workflow_get_workflows_full_object($name) {
  151. if ($workflow = workflow_get_workflows_by_name($name)) {
  152. // Now we need to add data to the object for each state, an array of sub-objects.
  153. $options = array('status' => 1); // We only want active states for this export.
  154. $active_states = array();
  155. foreach (workflow_get_workflow_states_by_wid($workflow->wid, $options) as $index => $state) {
  156. $active_states[$state->sid] = $state->state;
  157. // Remove what we don't need to export.
  158. unset($state->sid);
  159. unset($state->wid);
  160. $workflow->states[] = $state;
  161. }
  162. // Now we need to add data to the export for each transition, an array of sub-objects.
  163. // Same goes for transitions, see above re: states.
  164. foreach ($active_states as $sid => $state) {
  165. // We're going to look everythign up by the start state, not state involved, to avoid dupes.
  166. foreach (workflow_get_workflow_transitions_by_sid($sid, $options) as $transition) {
  167. // And to get the target state (by name) we need to look it up too.
  168. $target_state = workflow_get_workflow_states_by_sid($transition->target_sid);
  169. $transition->state = $state;
  170. $transition->target_state = $target_state->state;
  171. unset($transition->sid, $transition->target_sid);
  172. // Translate to role names so works cross install.
  173. $transition->roles = !empty($transition->roles) ? _workflow_rids_to_roles($transition->roles) : '';
  174. // Remove what we don't need to export.
  175. unset($transition->tid);
  176. $workflow->transitions[] = $transition;
  177. }
  178. }
  179. // Now we need to add data to the export for each type map, an array of sub-objects.
  180. // Same goes for node mappings, see above re: states.
  181. foreach (workflow_get_workflow_type_map_by_wid($workflow->wid) as $index => $type_map) {
  182. $workflow->node_types[] = $type_map->type;
  183. }
  184. }
  185. return $workflow;
  186. }
  187. /**
  188. * Internally cache the user roles as core doesn't.
  189. */
  190. function _workflow_user_roles($reset = FALSE) {
  191. $roles = &drupal_static(__FUNCTION__);
  192. if ($reset || !isset($roles)) {
  193. $roles = user_roles();
  194. }
  195. return $roles;
  196. }
  197. /**
  198. * Translates a role string to RIDs for importing.
  199. *
  200. * @param $role_string
  201. * A string of roles or fake 'author' role.
  202. *
  203. * @return
  204. * A string of RIDs seperated by commas.
  205. */
  206. function _workflow_roles_to_rids($role_string) {
  207. $roles = _workflow_user_roles();
  208. $rid_array = array();
  209. foreach (explode(',', $role_string) as $role_name) {
  210. if ($role_name === WORKFLOW_FEATURES_AUTHOR_NAME) {
  211. $rid_array[] = 'author';
  212. }
  213. elseif ($role_name && in_array($role_name, $roles)) {
  214. $rid_array[] = array_search($role_name, $roles);
  215. }
  216. }
  217. return implode(',', $rid_array);
  218. }
  219. /**
  220. * Translates a string of rids to role names for exporting.
  221. *
  222. * @param $rid_string
  223. * A string of rids or fake 'author' role.
  224. *
  225. * @return
  226. * A string of role names seperated by commas.
  227. */
  228. function _workflow_rids_to_roles($rid_string) {
  229. $roles = _workflow_user_roles();
  230. $rid_array = explode(',', $rid_string);
  231. // There may be a role named 'author', so make 'author' distinct.
  232. $return = in_array('author', $rid_array) ? WORKFLOW_FEATURES_AUTHOR_NAME . ',' : '';
  233. // Translate RIDs to rolenames.
  234. $return .= implode(',', array_intersect_key($roles, array_flip($rid_array)));
  235. return trim($return, ',');
  236. }