wing.module 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. /**
  3. * @file
  4. * Workflow - New Generation
  5. *
  6. * - States are entities
  7. * - Worfklows are the bundle entities of states
  8. * - Transitions are fields on states, storing a (rid, sid) pair per item
  9. * - Any entity type can be subject to a workflow: association is represented by
  10. * an entityreference field whose widget uses a specific view to list the
  11. * relevant states
  12. * - Workflow access is handled by field access using the permission associated
  13. * with a state, one "view" or "edit" permission per state entity
  14. *
  15. * URL structure admin/structure/wing/...
  16. * /: dashboard
  17. * /settings: module settings
  18. * /add: workflow creation form
  19. * /workflow[/list]: list of workflows
  20. * /workflow/add: state creation form
  21. * /workflow/<wname>[/info]: info on workflow with list of states
  22. * /workflow/<wname>/edit|clone|delete|export: workflow operations form
  23. * /workflow/<wname>/fields: field UI for workflow as state bundle
  24. * /workflow/<wname>/fields: view modes for workflow as state bundle
  25. * /state[/list]: list of states
  26. * /state/<sname>[/info]: info on state, with list of previous/next states
  27. * and list of entities in state
  28. * /state/<sname>/edit|clone|delete|export
  29. * state operations form. Main point of interest is the transitions subform
  30. */
  31. /**
  32. * Implements hook_entity_info().
  33. *
  34. * Workflow is the bundle entity for state, but this concept is obsolete in D8,
  35. * so we ignore it.
  36. */
  37. function wing_entity_info() {
  38. $defaults = array(
  39. 'entity keys' => array(
  40. 'label' => 'title',
  41. 'module' => 'module',
  42. 'name' => 'machine_name',
  43. 'status' => 'status',
  44. ),
  45. 'exportable' => TRUE,
  46. 'fieldable' => FALSE,
  47. 'label callback' => 'entity_class_label',
  48. 'module' => 'wing',
  49. 'uri callback' => 'entity_class_uri',
  50. 'view modes' => array(
  51. 'full' => array(
  52. 'label' => t('Full'),
  53. 'custom settings' => FALSE,
  54. ),
  55. 'summary' => array(
  56. 'label' => t('Summary'),
  57. 'custom settings' => FALSE,
  58. ),
  59. 'simple' => array(
  60. 'label' => t('Simple'),
  61. 'custom settings' => FALSE,
  62. ),
  63. ),
  64. );
  65. $ret = array();
  66. $type = 'wing_workflow';
  67. $class = 'WingWorkflow';
  68. $ret[$type] = array_merge_recursive(array(
  69. 'access callback' => "{$type}_access",
  70. 'base table' => $type,
  71. 'controller class' => "{$class}Controller",
  72. 'entity class' => $class,
  73. 'entity keys' => array(
  74. 'id' => 'wid',
  75. ),
  76. 'export' => array(
  77. 'default hook' => "default_{$type}s",
  78. ),
  79. 'features controller class' => "{$class}FeaturesController",
  80. 'label' => t('Wing: Workflow'),
  81. 'load hook' => "{$type}_load", // Enable hook_wing_workflow_load().
  82. 'views controller class' => "{$class}ViewsController",
  83. ), $defaults);
  84. $type = 'wing_state';
  85. $class = 'WingState';
  86. $ret[$type] = array_merge_recursive(array(
  87. 'access callback' => '{$type}_access',
  88. 'base table' => $type,
  89. 'bundle keys' => array('bundle' => 'workflow'),
  90. 'bundles' => array(),
  91. 'controller class' => "{$class}Controller",
  92. 'entity class' => $class,
  93. 'entity keys' => array(
  94. 'id' => 'sid',
  95. 'bundle' => 'workflow',
  96. ),
  97. 'export' => array(
  98. 'default_hook' => "default_{$type}s",
  99. ),
  100. 'features controller class' => "{$class}FeaturesController",
  101. 'label' => t('Wing: State'),
  102. 'load hook' => "{$type}_load", // Enable hook_wing_state_load().
  103. 'views controller class' => "{$class}ViewsController",
  104. ), $defaults);
  105. // Add bundle info but bypass entity_load() as we cannot use it here.
  106. $workflows = db_select('wing_workflow', 'ww')
  107. ->fields('ww')
  108. ->execute()
  109. ->fetchAllAssoc('machine_name');
  110. foreach ($workflows as $workflow_name => $workflow) {
  111. $ret[$type]['bundles'][$workflow_name] = array(
  112. 'label' => $workflow->title,
  113. // 'admin' => array(
  114. // 'path' => 'admin/content/wing/workflow/%entity_object',
  115. // 'real path' => 'admin/content/wing/workflow/' . $workflow_name,
  116. // 'bundle argument' => 4,
  117. // 'access arguments' => array('administer wing'),
  118. // ),
  119. );
  120. }
  121. return $ret;
  122. }
  123. /**
  124. * Implements hook_entity_info_alter().
  125. *
  126. * Sort initial Wing entity info keys for easier debugging.
  127. */
  128. function wing_entity_info_alter(&$info) {
  129. ksort($info['wing_state']);
  130. ksort($info['wing_workflow']);
  131. }
  132. /**
  133. * Implements hook_field_info().
  134. *
  135. * Define "wing_transition" as a UI-less field.
  136. */
  137. function wing_field_info() {
  138. $ret = array(
  139. 'wing_transition' => array(
  140. 'label' => t('Wing: Transition'),
  141. 'description' => t('Store access from one workflow state to another.'),
  142. 'settings' => array(),
  143. 'instance_settings' => array(),
  144. 'default_widget' => 'text_textfield',
  145. 'default_formatter' => 'text_default',
  146. // 'default_widget' => 'wing_transition_widget',
  147. // 'default_formatter' => 'wing_transition_default',
  148. // 'no_ui' => FALSE,
  149. ),
  150. );
  151. dsm($ret, __FUNCTION__);
  152. return $ret;
  153. }
  154. /**
  155. * Implements hook_field_widget_info().
  156. */
  157. function wing_field_widget_info() {
  158. $ret = array(
  159. 'text_textfield' => array(
  160. 'label' => t('Text field'),
  161. 'field types' => array('text'),
  162. 'settings' => array('size' => 60),
  163. 'behaviors' => array(
  164. 'multiple values' => FIELD_BEHAVIOR_DEFAULT,
  165. 'default value' => FIELD_BEHAVIOR_DEFAULT,
  166. ),
  167. ),
  168. );
  169. return $ret;
  170. }
  171. /**
  172. * Implements hook_field_widget_info_alter().
  173. */
  174. function wing_field_widget_info_alter(&$info) {
  175. if (module_exists('text')) {
  176. $info['text_textfield']['field types'][] = 'wing_transition';
  177. }
  178. }
  179. /**
  180. * Implements hook_menu().
  181. */
  182. function wing_menu() {
  183. $items = array();
  184. $items['admin/content/wing'] = array(
  185. 'title' => 'Wing',
  186. 'access arguments' => array('administer wing'),
  187. 'page callback' => 'wing_overview',
  188. 'file' => 'wing.pages.inc',
  189. );
  190. $items['admin/content/wing/info'] = array(
  191. 'title' => 'Info',
  192. 'type' => MENU_DEFAULT_LOCAL_TASK,
  193. );
  194. $items['admin/content/wing/settings'] = array(
  195. 'title' => 'Settings',
  196. 'type' => MENU_LOCAL_TASK,
  197. 'page callback' => 'drupal_get_form',
  198. 'page arguments' => array('wing_settings_form'),
  199. 'file' => 'wing.admin.inc',
  200. 'access arguments' => array('administer wing'),
  201. 'weight' => 9,
  202. );
  203. return $items;
  204. }
  205. /**
  206. * Implements hook_permission().
  207. */
  208. function wing_permission() {
  209. $ret = array(
  210. 'administer wing' => array(
  211. 'title' => t('Administer Wing'),
  212. 'description' => t('Perform administration tasks for Wing.'),
  213. ),
  214. );
  215. return $ret;
  216. }
  217. /**
  218. * Entity access callback for wing_state.
  219. *
  220. * @param string $op
  221. * 'create', 'update', 'delete' or 'view'
  222. * @param WingState $entity
  223. * @param stdClass $account
  224. * @param string $entity_type
  225. *
  226. * @return boolean
  227. */
  228. function wing_state_access($op, $entity, $account, $entity_type) {
  229. // dsm(get_defined_vars(), __FUNCTION__);
  230. return TRUE;
  231. }
  232. /**
  233. * Implements hook_view_api().
  234. */
  235. function wing_views_api() {
  236. $path = drupal_get_path('module', 'wing');
  237. $ret = array(
  238. 'api' => 3,
  239. 'path' => "$path/views",
  240. 'template path' => "$path/themes",
  241. );
  242. return $ret;
  243. }
  244. /**
  245. * Entity access callback for wing_workflow.
  246. *
  247. * @param string $op
  248. * 'create', 'update', 'delete' or 'view'
  249. * @param WingWorkflow $entity
  250. * @param stdClass $account
  251. * @param string $entity_type
  252. *
  253. * @return boolean
  254. */
  255. function wing_workflow_access($op, $entity, $account, $entity_type) {
  256. $s_entity = isset($entity) ? "$entity" : 'NULL';
  257. $s_account = isset($account) ? $account->uid : "'<anonymous>'";
  258. // dsm(__FUNCTION__ . "('$op', $s_entity, $s_account, '$entity_type')");
  259. return TRUE;
  260. }
  261. function wing_workflow_exists($machine_name) {
  262. $ret = entity_load_multiple_by_name('wing_workflow', array($machine_name));
  263. dsm($ret, __FUNCTION__);
  264. return $ret;
  265. }