wing.module 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <?php
  2. use Drupal\wing\Plugin\Core\Entity\State;
  3. /**
  4. * @file
  5. * Workflow - New Generation
  6. *
  7. * - States are entities
  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 entity_reference 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_bundle_info().
  33. */
  34. function wing_entity_bundle_info() {
  35. $bundles = array();
  36. foreach (wing_get_workflows() as $workflow => $title) {
  37. $bundles['wing_state'][$type] = array(
  38. 'label' => $title,
  39. 'admin' => array(
  40. // Place the Field UI paths for comments one level below the
  41. // corresponding paths for nodes, so that they appear in the same set
  42. // of local tasks. Note that the paths use a different placeholder name
  43. // and thus a different menu loader callback, so that Field UI page
  44. // callbacks get a comment bundle name from the node type in the URL.
  45. // See comment_node_type_load() and comment_menu_alter().
  46. 'path' => 'admin/content/wing/manage/%wing_workflow',
  47. 'bundle argument' => 4,
  48. 'real path' => 'admin/content/wing/manage/' . $workflow. '/comment',
  49. ),
  50. );
  51. }
  52. return $bundles;
  53. }
  54. /**
  55. * Implements hook_entity_view_mode().
  56. */
  57. function wing_entity_view_mode_info() {
  58. $ret = array(
  59. 'wing_state' => array(
  60. 'full' => array(
  61. 'label' => t('Full'),
  62. 'custom settings' => FALSE,
  63. ),
  64. 'summary' => array(
  65. 'label' => t('Summary'),
  66. 'custom settings' => FALSE,
  67. ),
  68. 'simple' => array(
  69. 'label' => t('Simple'),
  70. 'custom settings' => FALSE,
  71. ),
  72. ),
  73. );
  74. dsm($ret, __FUNCTION__);
  75. return $ret;
  76. }
  77. /**
  78. * Implements hook_field_extra_fields().
  79. */
  80. function wing_field_extra_fields() {
  81. $ret = array();
  82. foreach (wing_get_workflows() as $workflow => $title) {
  83. $ret['wing_state'][$workflow]['workflow'] = array(
  84. 'display' => array(
  85. 'label' => t('Workflow name'),
  86. 'description' => t('The workflow to which the state belongs'),
  87. 'weight' => -9,
  88. 'visible' => FALSE,
  89. ),
  90. );
  91. }
  92. dsm($ret, __FUNCTION__);
  93. return $ret;
  94. }
  95. /**
  96. * Helper to retrive the list or workflows or a specific workflow.
  97. *
  98. * @param string $workflow
  99. */
  100. function wing_get_workflows($workflow = NULL) {
  101. $workflows = config('wing')->get('workflows');
  102. if (isset($workflow)) {
  103. $ret = isset($workflows[$workflow]) ? $workflows[$workflow] : FALSE;
  104. }
  105. else {
  106. $ret = (array) $workflows;
  107. }
  108. dsm($ret, __FUNCTION__ . "($workflow)");
  109. return $ret;
  110. }
  111. /**
  112. * Implements hook_help().
  113. */
  114. function wing_help($path, $arg) {
  115. switch ($path) {
  116. case 'admin/help#wing':
  117. $ret = '<h3>' . t('About') . '</h3>'
  118. . t('Wing is a new workflow system redesigned from the ground up for Drupal 8.
  119. States are entities, Workflows are their bundles, and any fieldable entity type
  120. (not just nodes) can be subjected to a workflow by adding an entity_reference to
  121. a Wing state field to its field list.');
  122. break;
  123. default:
  124. $ret = NULL;
  125. }
  126. return $ret;
  127. }
  128. /**
  129. * Implements hook_menu().
  130. */
  131. function wing_menu() {
  132. $items = array();
  133. $items['admin/content/wing'] = array(
  134. 'access arguments' => array('administer wing'),
  135. 'description' => 'Report general Wing information',
  136. 'file' => 'wing.admin.inc',
  137. 'page callback' => 'wing_page_info',
  138. 'title' => 'Wing',
  139. 'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
  140. 'weight' => 23, // 'W'
  141. );
  142. // Tabs begin here.
  143. $items['admin/content/wing/info'] = array(
  144. 'title' => 'Info',
  145. 'type' => MENU_DEFAULT_LOCAL_TASK,
  146. );
  147. $items['admin/content/wing/overview'] = array(
  148. 'title' => 'States',
  149. 'access arguments' => array('administer wing'),
  150. 'description' => 'List and edit workflow states',
  151. 'file' => 'wing.pages.inc',
  152. 'page callback' => 'wing_overview',
  153. 'title' => 'Wing',
  154. 'type' => MENU_LOCAL_TASK,
  155. );
  156. $items['admin/content/wing/%wing_state'] = array(
  157. 'access arguments' => array('administer wing'),
  158. 'page arguments' => array(3),
  159. 'page callback' => 'wing_state_page',
  160. 'title' => 'State permalink',
  161. );
  162. $items['admin/content/wing/%wing_state/view'] = array(
  163. 'title' => 'View state',
  164. 'type' => MENU_DEFAULT_LOCAL_TASK,
  165. );
  166. $items['admin/content/wing/%wing_state/edit'] = array(
  167. 'title' => 'Edit',
  168. 'page callback' => 'wing_state_edit_page',
  169. 'page arguments' => array(3),
  170. 'access callback' => 'wing_state_access',
  171. 'access arguments' => array('edit', 3),
  172. 'type' => MENU_LOCAL_TASK,
  173. );
  174. $items['admin/content/wing/%wing_state/delete'] = array(
  175. 'title' => 'Delete',
  176. 'page callback' => 'wing_state_confirm_delete_page',
  177. 'page arguments' => array(3),
  178. 'access arguments' => array('administer wing'),
  179. 'type' => MENU_LOCAL_TASK,
  180. 'file' => 'wing.admin.inc',
  181. 'weight' => 20,
  182. );
  183. $items['admin/content/wing/settings'] = array(
  184. 'title' => 'Settings',
  185. 'type' => MENU_LOCAL_TASK,
  186. 'page callback' => 'drupal_get_form',
  187. 'page arguments' => array('wing_settings_form'),
  188. 'file' => 'wing.admin.inc',
  189. 'access arguments' => array('administer wing'),
  190. 'weight' => 99,
  191. );
  192. return $items;
  193. }
  194. /**
  195. * TODO implement
  196. *
  197. * @param string $op
  198. * @param Drupal\wing\Plugin\Core\Entity\State $state
  199. *
  200. * @return boolean
  201. */
  202. function wing_state_access($op, State $state) {
  203. }
  204. /**
  205. * Entity URI callback.
  206. */
  207. function wing_uri(State $state) {
  208. return array(
  209. 'path' => 'admin/content/wing/' . $state->id(),
  210. );
  211. }
  212. /**
  213. * Menu loader for workflow.
  214. *
  215. * @param string $workflow
  216. *
  217. * @return boolean
  218. */
  219. function wing_workflow_load($workflow) {
  220. $ret = wing_get_workflows($workflow);
  221. dsm($ret, __FUNCTION__);
  222. return $ret;
  223. }
  224. function WIPWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWww() {}
  225. /**
  226. * Implements hook_entity_info().
  227. *
  228. * Workflow is the bundle entity for state, but this concept is obsolete in D8,
  229. * so we ignore it.
  230. */
  231. function Zwing_entity_info() {
  232. $defaults = array(
  233. 'entity keys' => array(
  234. 'label' => 'title',
  235. 'module' => 'module',
  236. 'name' => 'machine_name',
  237. 'status' => 'status',
  238. ),
  239. 'exportable' => TRUE,
  240. 'fieldable' => FALSE,
  241. 'label callback' => 'entity_class_label',
  242. 'module' => 'wing',
  243. 'uri callback' => 'entity_class_uri',
  244. );
  245. $ret = array();
  246. $type = 'wing_workflow';
  247. $class = 'WingWorkflow';
  248. $ret[$type] = array_merge_recursive(array(
  249. 'access callback' => "{$type}_access",
  250. 'base table' => $type,
  251. 'controller class' => "{$class}Controller",
  252. 'entity class' => $class,
  253. 'entity keys' => array(
  254. 'id' => 'wid',
  255. ),
  256. 'export' => array(
  257. 'default hook' => "default_{$type}s",
  258. ),
  259. 'features controller class' => "{$class}FeaturesController",
  260. 'label' => t('Wing: Workflow'),
  261. 'load hook' => "{$type}_load", // Enable hook_wing_workflow_load().
  262. 'views controller class' => "{$class}ViewsController",
  263. ), $defaults);
  264. $type = 'wing_state';
  265. $class = 'WingState';
  266. $ret[$type] = array_merge_recursive(array(
  267. 'access callback' => '{$type}_access',
  268. 'base table' => $type,
  269. 'bundle keys' => array('bundle' => 'workflow'),
  270. 'bundles' => array(),
  271. 'controller class' => "{$class}Controller",
  272. 'entity class' => $class,
  273. 'entity keys' => array(
  274. 'id' => 'sid',
  275. 'bundle' => 'workflow',
  276. ),
  277. 'export' => array(
  278. 'default_hook' => "default_{$type}s",
  279. ),
  280. 'features controller class' => "{$class}FeaturesController",
  281. 'label' => t('Wing: State'),
  282. 'load hook' => "{$type}_load", // Enable hook_wing_state_load().
  283. 'views controller class' => "{$class}ViewsController",
  284. ), $defaults);
  285. return $ret;
  286. }
  287. /**
  288. * Implements hook_entity_info_alter().
  289. *
  290. * Sort initial Wing entity info keys for easier debugging.
  291. */
  292. function Zwing_entity_info_alter(&$info) {
  293. ksort($info['wing_state']);
  294. ksort($info['wing_workflow']);
  295. }
  296. /**
  297. * Implements hook_field_info().
  298. *
  299. * Define "wing_transition" as a UI-less field.
  300. */
  301. function Zwing_field_info() {
  302. $ret = array(
  303. 'wing_transition' => array(
  304. 'label' => t('Wing: Transition'),
  305. 'description' => t('Store access from one workflow state to another.'),
  306. 'settings' => array(),
  307. 'instance_settings' => array(),
  308. 'default_widget' => 'text_textfield',
  309. 'default_formatter' => 'text_default',
  310. // 'default_widget' => 'wing_transition_widget',
  311. // 'default_formatter' => 'wing_transition_default',
  312. // 'no_ui' => FALSE,
  313. ),
  314. );
  315. dsm($ret, __FUNCTION__);
  316. return $ret;
  317. }
  318. /**
  319. * Implements hook_field_widget_info().
  320. */
  321. function Zwing_field_widget_info() {
  322. $ret = array(
  323. 'text_textfield' => array(
  324. 'label' => t('Text field'),
  325. 'field types' => array('text'),
  326. 'settings' => array('size' => 60),
  327. 'behaviors' => array(
  328. 'multiple values' => FIELD_BEHAVIOR_DEFAULT,
  329. 'default value' => FIELD_BEHAVIOR_DEFAULT,
  330. ),
  331. ),
  332. );
  333. return $ret;
  334. }
  335. /**
  336. * Implements hook_field_widget_info_alter().
  337. */
  338. function Zwing_field_widget_info_alter(&$info) {
  339. if (module_exists('text')) {
  340. $info['text_textfield']['field types'][] = 'wing_transition';
  341. }
  342. }
  343. /**
  344. * Implements hook_permission().
  345. */
  346. function Zwing_permission() {
  347. $ret = array(
  348. 'administer wing' => array(
  349. 'title' => t('Administer Wing'),
  350. 'description' => t('Perform administration tasks for Wing.'),
  351. ),
  352. );
  353. return $ret;
  354. }
  355. /**
  356. * Entity access callback for wing_state.
  357. *
  358. * @param string $op
  359. * 'create', 'update', 'delete' or 'view'
  360. * @param WingState $entity
  361. * @param stdClass $account
  362. * @param string $entity_type
  363. *
  364. * @return boolean
  365. */
  366. function Zwing_state_access($op, $entity, $account, $entity_type) {
  367. // dsm(get_defined_vars(), __FUNCTION__);
  368. return TRUE;
  369. }
  370. /**
  371. * Implements hook_view_api().
  372. */
  373. function Zwing_views_api() {
  374. $path = drupal_get_path('module', 'wing');
  375. $ret = array(
  376. 'api' => 3,
  377. 'path' => "$path/views",
  378. 'template path' => "$path/themes",
  379. );
  380. return $ret;
  381. }
  382. /**
  383. * Entity access callback for wing_workflow.
  384. *
  385. * @param string $op
  386. * 'create', 'update', 'delete' or 'view'
  387. * @param WingWorkflow $entity
  388. * @param stdClass $account
  389. * @param string $entity_type
  390. *
  391. * @return boolean
  392. */
  393. function Zwing_workflow_access($op, $entity, $account, $entity_type) {
  394. $s_entity = isset($entity) ? "$entity" : 'NULL';
  395. $s_account = isset($account) ? $account->uid : "'<anonymous>'";
  396. // dsm(__FUNCTION__ . "('$op', $s_entity, $s_account, '$entity_type')");
  397. return TRUE;
  398. }
  399. function Zwing_workflow_exists($machine_name) {
  400. $ret = entity_load_multiple_by_name('wing_workflow', array($machine_name));
  401. dsm($ret, __FUNCTION__);
  402. return $ret;
  403. }