workflow_access.features.inc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. /**
  3. * @file
  4. * Workflow_access records are a **faux-exportable** component.
  5. */
  6. /**
  7. * Helper to find the roles needs by an export.
  8. *
  9. * @return array
  10. * A workflow_name-indexed hash of non-default roles in workflow_access for
  11. * that workflow.
  12. */
  13. function _workflow_access_get_affected_roles() {
  14. $sql = <<<SQL
  15. SELECT DISTINCT
  16. w.name AS wname,
  17. r.name AS rname
  18. FROM {workflow_access} wa
  19. INNER JOIN {workflow_states} ws ON wa.sid = ws.sid
  20. INNER JOIN {workflows} w ON ws.wid = w.wid
  21. INNER JOIN {role} r ON wa.rid = r.rid
  22. SQL;
  23. $roles = array();
  24. foreach (db_query($sql) as $row) {
  25. $roles[$row->wname][$row->rname] = $row->rname;
  26. }
  27. return $roles;
  28. }
  29. /**
  30. * Implements hook_features_export_options().
  31. *
  32. * Provide a list of all workflows as selectable Feature components.
  33. *
  34. * Generates the options to choose from.
  35. * Using $wid as key. Result is used by hook_features_export().
  36. */
  37. function workflow_access_features_export_options() {
  38. $workflows = array();
  39. foreach (workflow_load_multiple() as $workflow) {
  40. $name = $workflow->getName();
  41. $workflows[$name] = t('workflow access configuration for: @label', array('@label' => $name));
  42. }
  43. return $workflows;
  44. }
  45. /**
  46. * Implements hook_features_export().
  47. */
  48. function workflow_access_features_export($data, &$export, $module_name = '') {
  49. $pipe = array();
  50. $export['dependencies']['workflow_access'] = 'workflow_access';
  51. $export['dependencies']['workflow'] = 'workflow';
  52. $roles = _workflow_access_get_affected_roles();
  53. foreach ($data as $workflow_name) {
  54. if ($workflow = workflow_load_by_name($workflow_name)) {
  55. $export['features']['workflow_access'][$workflow_name] = $workflow_name;
  56. $export['features']['workflow'][$workflow_name] = $workflow_name;
  57. // Access configuration for a workflow needs that workflow to exist.
  58. $pipe['workflow'][$workflow_name] = $workflow_name;
  59. // And it needs the roles to which rights are granted.
  60. if (isset($roles[$workflow_name])) {
  61. foreach ($roles[$workflow_name] as $role_name) {
  62. $pipe['user_role'][$role_name] = $role_name;
  63. }
  64. }
  65. }
  66. }
  67. return $pipe;
  68. }
  69. /**
  70. * Implements hook_features_export_render().
  71. *
  72. * Instruct Features which php code to generate, including the code-ified
  73. * workflow access records we want to export from db into code.
  74. */
  75. function workflow_access_features_export_render($module_name, $data, $export = NULL) {
  76. $code = array();
  77. $code[] = ' $workflows = array();';
  78. // For each selected workflow, fetch all related workflow access records
  79. // we want to put into code.
  80. foreach ($data as $workflow_name) {
  81. $workflow = workflow_load_by_name($workflow_name);
  82. if ($workflow) {
  83. $states = $workflow->getStates($all = TRUE);
  84. if ($states) {
  85. $code[] = "\n \$workflows['$workflow_name'] = array();";
  86. foreach ($states as $state) {
  87. $access_records = workflow_access_get_features_workflow_access_by_sid($state->sid);
  88. if (!empty($access_records)) {
  89. $state_name = $state->getName();
  90. $code[] = " \$workflows['$workflow_name']['$state_name'] = array();";
  91. foreach ($access_records as $record) {
  92. $rname = $record->rname;
  93. unset($record->rname);
  94. $code[] = " \$workflows['$workflow_name']['$state_name']['$rname'] = " . features_var_export($record, ' ') . ';';
  95. }
  96. }
  97. }
  98. }
  99. }
  100. }
  101. $code[] = "\n return \$workflows;";
  102. $code = implode("\n", $code);
  103. return array('workflow_access_features_default_settings' => $code);
  104. }
  105. /**
  106. * Implements hook_features_rebuild().
  107. *
  108. * Instruct Features to insert our records (that were exported into code)
  109. * into the workflow_access table.
  110. */
  111. function workflow_access_features_rebuild($module) {
  112. // @see d.o. https://www.drupal.org/node/2472501
  113. // $workflow_access_records = module_invoke($module, 'workflow_access_features_default_settings');
  114. if (!$workflow_access_records = features_get_default('workflow_access', $module)) {
  115. return;
  116. }
  117. // Retrieve the workflow IDs.
  118. $wids = array();
  119. foreach ($workflow_access_records as $workflow_name => $state) {
  120. $workflow = workflow_load_by_name($workflow_name);
  121. $wids[$workflow_name] = $workflow->wid;
  122. }
  123. foreach ($wids as $workflow_name => $wid) {
  124. $workflow = workflow_load_by_name($workflow_name);
  125. if (!empty($workflow) && $states = $workflow->getStates($all = TRUE)) {
  126. foreach ($states as $state) {
  127. // Remove all workflow access records for states belonging to this
  128. // workflow. We don't want lingering entries - we only want the ones we're
  129. // about to insert.
  130. workflow_access_delete_workflow_access_by_sid($state->sid);
  131. }
  132. }
  133. }
  134. // Insert our workflow access records. They look like
  135. // workflow_name[state_name][role_name] => array(grant_name => 0|1, ...)
  136. foreach ($workflow_access_records as $workflow_name => $states) {
  137. foreach ($states as $state_name => $records) {
  138. if ($state = workflow_state_load_by_name($state_name, $wids[$workflow_name])) {
  139. foreach ($records as $rname => $record) {
  140. $record['sid'] = ($state) ? $state->sid : $state->sid;
  141. if ($rname == WORKFLOW_FEATURES_AUTHOR_NAME) {
  142. $record['rid'] = WORKFLOW_ROLE_AUTHOR_RID;
  143. }
  144. else {
  145. $role = user_role_load_by_name($rname);
  146. $record['rid'] = $role->rid;
  147. }
  148. workflow_access_insert_workflow_access_by_sid($record);
  149. }
  150. }
  151. }
  152. }
  153. }
  154. /**
  155. * Implements hook_features_revert().
  156. */
  157. function workflow_access_features_revert($module) {
  158. workflow_access_features_rebuild($module);
  159. }
  160. /**
  161. * Get workflow_access object like below by state id.
  162. *
  163. * Array(
  164. * 'rname' => 'authenticated user',
  165. * 'grant_view' => 1,
  166. * 'grant_update' => 0,
  167. * 'grant_delete' => 0,
  168. * );
  169. *
  170. * State ID and Workflow ID are not returned because they are implicit for a
  171. * given sid.
  172. */
  173. function workflow_access_get_features_workflow_access_by_sid($sid) {
  174. // Get all workflow access rules for a sid, where wa.rid is either a valid
  175. // role or -1, which stands for the author.
  176. $sql = <<<SQL
  177. SELECT
  178. r.name as rname,
  179. wa.grant_view, wa.grant_update, wa.grant_delete
  180. FROM {workflow_access} wa
  181. LEFT JOIN {role} r ON wa.rid = r.rid
  182. WHERE
  183. wa.sid = :sid AND (wa.rid = r.rid OR wa.rid = :rid)
  184. SQL;
  185. $results = db_query($sql, array(':sid' => $sid, ':rid' => WORKFLOW_ROLE_AUTHOR_RID));
  186. $records = $results->fetchAll();
  187. foreach ($records as $record) {
  188. if (empty($record->rname)) {
  189. $record->rname = WORKFLOW_FEATURES_AUTHOR_NAME;
  190. }
  191. }
  192. return $records;
  193. }