workflow.features.inc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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 = reset(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. $active_transitions = array();
  123. foreach ($transitions as $transition) {
  124. $transition = (object) $transition;
  125. $transition->sid = $active_states[$transition->state];
  126. $transition->target_sid = $active_states[$transition->target_state];
  127. // Roles are exported by rolename, so need to translate to RID.
  128. $transition->roles = !empty($transition->roles) ? _workflow_roles_to_rids($transition->roles) : '';
  129. workflow_update_workflow_transitions($transition);
  130. $active_transitions[] = $transition->tid;
  131. }
  132. // Delete any transitions in our workflow that are *not* in our original construction.
  133. foreach (workflow_get_workflow_transitions_by_wid($workflow->wid) as $transition) {
  134. if (!in_array($transition->tid, $active_transitions)) {
  135. workflow_delete_workflow_transitions_by_tid($transition->tid);
  136. }
  137. }
  138. // Then add the node_type mapping.
  139. foreach ($node_types as $node_type) {
  140. $node_type = (object) array(
  141. 'type' => $node_type,
  142. 'wid' => $workflow->wid
  143. );
  144. // Insert, nodes only have one workflow. Insert will delete any prior workflow assoc.
  145. workflow_insert_workflow_type_map($node_type);
  146. }
  147. return TRUE;
  148. }
  149. /**
  150. * For use by CRUD only, gather everything into the CRUD formed object.
  151. *
  152. * @param $name
  153. * A string corresponding to a workflow object.
  154. *
  155. * @return
  156. * A fully loaded workflow object with type and statue mappings.
  157. */
  158. function workflow_get_workflows_full_object($name) {
  159. if ($workflow = workflow_get_workflows_by_name($name)) {
  160. // Now we need to add data to the object for each state, an array of sub-objects.
  161. $options = array('status' => 1); // We only want active states for this export.
  162. $active_states = array();
  163. foreach (workflow_get_workflow_states_by_wid($workflow->wid, $options) as $index => $state) {
  164. $active_states[$state->sid] = $state->state;
  165. // Remove what we don't need to export.
  166. unset($state->sid);
  167. unset($state->wid);
  168. $workflow->states[] = $state;
  169. }
  170. // Now we need to add data to the export for each transition, an array of sub-objects.
  171. // Same goes for transitions, see above re: states.
  172. foreach ($active_states as $sid => $state) {
  173. // We're going to look everythign up by the start state, not state involved, to avoid dupes.
  174. foreach (workflow_get_workflow_transitions_by_sid($sid, $options) as $transition) {
  175. // And to get the target state (by name) we need to look it up too.
  176. $target_state = workflow_get_workflow_states_by_sid($transition->target_sid);
  177. $transition->state = $state;
  178. $transition->target_state = $target_state->state;
  179. unset($transition->sid, $transition->target_sid);
  180. // Translate to role names so works cross install.
  181. $transition->roles = !empty($transition->roles) ? _workflow_rids_to_roles($transition->roles) : '';
  182. // Remove what we don't need to export.
  183. unset($transition->tid);
  184. $workflow->transitions[] = $transition;
  185. }
  186. }
  187. // Now we need to add data to the export for each type map, an array of sub-objects.
  188. // Same goes for node mappings, see above re: states.
  189. foreach (workflow_get_workflow_type_map_by_wid($workflow->wid) as $index => $type_map) {
  190. $workflow->node_types[] = $type_map->type;
  191. }
  192. }
  193. return $workflow;
  194. }
  195. /**
  196. * Internally cache the user roles as core doesn't.
  197. */
  198. function _workflow_user_roles($reset = FALSE) {
  199. $roles = &drupal_static(__FUNCTION__);
  200. if ($reset || !isset($roles)) {
  201. $roles = user_roles();
  202. }
  203. return $roles;
  204. }
  205. /**
  206. * Translates a role string to RIDs for importing.
  207. *
  208. * @param $role_string
  209. * A string of roles or fake 'author' role.
  210. *
  211. * @return
  212. * A string of RIDs seperated by commas.
  213. */
  214. function _workflow_roles_to_rids($role_string) {
  215. $roles = _workflow_user_roles();
  216. $rid_array = array();
  217. foreach (explode(',', $role_string) as $role_name) {
  218. if ($role_name === WORKFLOW_FEATURES_AUTHOR_NAME) {
  219. $rid_array[] = 'author';
  220. }
  221. elseif ($role_name && in_array($role_name, $roles)) {
  222. $rid_array[] = array_search($role_name, $roles);
  223. }
  224. }
  225. return implode(',', $rid_array);
  226. }
  227. /**
  228. * Translates a string of rids to role names for exporting.
  229. *
  230. * @param $rid_string
  231. * A string of rids or fake 'author' role.
  232. *
  233. * @return
  234. * A string of role names seperated by commas.
  235. */
  236. function _workflow_rids_to_roles($rid_string) {
  237. $roles = _workflow_user_roles();
  238. $rid_array = explode(',', $rid_string);
  239. // There may be a role named 'author', so make 'author' distinct.
  240. $return = in_array('author', $rid_array) ? WORKFLOW_FEATURES_AUTHOR_NAME . ',' : '';
  241. // Translate RIDs to rolenames.
  242. $return .= implode(',', array_intersect_key($roles, array_flip($rid_array)));
  243. return trim($return, ',');
  244. }