deploy_uuid.module

Tracking 6.x-1.x branch
  1. drupal
    1. 6 contributions/deploy/modules/deploy_uuid/deploy_uuid.module

Deployment UUID management

I am incredibly torn on how I have architected this. There is obviously a great deal of code in here that may or may not be useful depending on what modules you have installed or enabled (comments, filefields, etc.) From that standpoint, it makes sense to move all this code into the separate modules (comment_deploy, fielfield_deploy, etc.) On the other hand if I do that, then the remote server (most likely the production site) has to actually enable all those modules, increasing its code weight quite a bit. Whereas this way the production server can simply enable deploy_uuid and the services and be done with it. How this is managed is one of the stickiest problems I have, and the only solution I can come upt with is creating node_deploy_uuid, filefield_deploy_uuid, etc. Which blows but maybe that's where this has to go.

Suddenly wishing I had hook_module_enable() and hook_module_disable(). Then I could manage this behind the scenes.

Functions & methods

NameDescription
deploy_uuid_commentImplementation of hook_comment(),
deploy_uuid_create_uuidStandard function to create a unique identifier.
deploy_uuid_file_deleteImplementation of hook_file_delete().
deploy_uuid_file_insertImplementation of hook_file_insert().
deploy_uuid_file_loadImplementation of hook_file_load()
deploy_uuid_form_alterImplementation of hook_form_alter(),
deploy_uuid_get_comment_uuid
deploy_uuid_get_files_uuid
deploy_uuid_get_keyReturn the unique key of an item, given its UUID.
deploy_uuid_get_node_uuid
deploy_uuid_get_term_uuid
deploy_uuid_get_user_uuid
deploy_uuid_get_vocabulary_uuid
deploy_uuid_nodeapiImplementation of hook_nodeapi(),
deploy_uuid_taxonomyImplementation of hook_taxonomy().
deploy_uuid_userImplementation of hook_user().

File

View source
  1. <?php
  2. /**
  3. * @file
  4. *
  5. * Deployment UUID management
  6. *
  7. * I am incredibly torn on how I have architected this.
  8. * There is obviously a great deal of code in here that may or may not be useful
  9. * depending on what modules you have installed or enabled (comments, filefields,
  10. * etc.) From that standpoint, it makes sense to move all this code into the
  11. * separate modules (comment_deploy, fielfield_deploy, etc.) On the other hand if
  12. * I do that, then the remote server (most likely the production site) has to actually
  13. * enable all those modules, increasing its code weight quite a bit. Whereas this way
  14. * the production server can simply enable deploy_uuid and the services and be done with
  15. * it. How this is managed is one of the stickiest problems I have, and the only solution
  16. * I can come upt with is creating node_deploy_uuid, filefield_deploy_uuid, etc. Which
  17. * blows but maybe that's where this has to go.
  18. *
  19. * Suddenly wishing I had hook_module_enable() and hook_module_disable(). Then I could
  20. * manage this behind the scenes.
  21. */
  22. /**
  23. * Implementation of hook_file_load()
  24. *
  25. * Add the UUID to file objects on load.
  26. */
  27. function deploy_uuid_file_load(&$file) {
  28. // Ensure that $file is an object.
  29. if (!is_object($file)) {
  30. $file = (object) $file;
  31. }
  32. $uuid = deploy_uuid_get_files_uuid($file->fid);
  33. if ($uuid) {
  34. $file->uuid = $uuid;
  35. }
  36. }
  37. /**
  38. * Implementation of hook_file_insert().
  39. *
  40. * Add files UUID to appropriate table.
  41. */
  42. function deploy_uuid_file_insert($file) {
  43. // Ensure that $file is an object.
  44. if (!is_object($file)) {
  45. $file = (object) $file;
  46. }
  47. if ($file->uuid) {
  48. db_query("INSERT INTO {files_uuid} (fid, uuid) VALUES (%d, '%s')", $file->fid, $file->uuid);
  49. }
  50. else {
  51. db_query("INSERT INTO {files_uuid} (fid, uuid) VALUES (%d, '%s')", $file->fid, deploy_uuid_create_uuid());
  52. }
  53. }
  54. /**
  55. * Implementation of hook_file_delete().
  56. *
  57. * Delete files UUID from appropriate table.
  58. */
  59. function deploy_uuid_file_delete($file) {
  60. // Ensure that $file is an object.
  61. if (!is_object($file)) {
  62. $file = (object) $file;
  63. }
  64. db_query("DELETE FROM {files_uuid} WHERE fid = %d", $file->fid);
  65. }
  66. /**
  67. * Implementation of hook_comment(),
  68. *
  69. * This all relates to managing the mapped cid->uuid mapping.
  70. *
  71. * $a1 Dependent on the action being performed.
  72. *
  73. * * For "validate","update","insert", passes in an array of form values submitted by the user.
  74. * * For all other operations, passes in the comment the action is being performed on.
  75. *
  76. * $op What kind of action is being performed. Possible values:
  77. *
  78. * * "insert": The comment is being inserted.
  79. * * "update": The comment is being updated.
  80. * * "view": The comment is being viewed. This hook can be used to add additional data to the comment before theming.
  81. * * "validate": The user has just finished editing the comment and is trying to preview or submit it. This hook can be used to check or even modify the node. Errors should be set with form_set_error().
  82. * * "publish": The comment is being published by the moderator.
  83. * * "unpublish": The comment is being unpublished by the moderator.
  84. * * "delete": The comment is being deleted by the moderator.
  85. */
  86. function deploy_uuid_comment(&$a1, $op) {
  87. switch ($op) {
  88. // Make sure that a new entry gets made in the node_uuid table when new content
  89. // is added. NOTE the fallthrough to 'update' which is intentional.
  90. case 'insert':
  91. if (!empty($a1['uuid'])) {
  92. db_query("INSERT INTO {comments_uuid} (cid, uuid) VALUES (%d, '%s')", $a1['cid'], $a1['uuid']);
  93. }
  94. else {
  95. db_query("INSERT INTO {comments_uuid} (cid, uuid) VALUES (%d, '%s')", $a1['cid'], deploy_uuid_create_uuid());
  96. }
  97. break;
  98. // Clean up node_uuid table when content is deleted.
  99. case 'delete':
  100. db_query("DELETE FROM {comments_uuid} WHERE cid = %d", $a1->cid);
  101. break;
  102. }
  103. }
  104. /**
  105. * Implementation of hook_taxonomy().
  106. *
  107. * $op What is being done to $array. Possible values:
  108. *
  109. * * "delete"
  110. * * "insert"
  111. * * "update"
  112. *
  113. * $type What manner of item $array is. Possible values:
  114. *
  115. * * "term"
  116. * * "vocabulary"
  117. *
  118. * $array The item on which $op is being performed. Possible values:
  119. *
  120. * * for vocabularies, 'insert' and 'update' ops: $form_values from taxonomy_form_vocabulary_submit()
  121. * * for vocabularies, 'delete' op: $vocabulary from taxonomy_get_vocabulary() cast to an array
  122. * * for terms, 'insert' and 'update' ops: $form_values from taxonomy_form_term_submit()
  123. * * for terms, 'delete' op: $term from taxonomy_get_term() cast to an array
  124. */
  125. function deploy_uuid_taxonomy($op, $type, $array = NULL) {
  126. switch ($op) {
  127. case 'insert':
  128. // The only case in which we would have a term or vocabulary come through insert with a uuid
  129. // already in place is the case where it's being deployed from a remote source. In this case,
  130. // keep the existing uuid. Otherwise, create a new one.
  131. if ($type == 'term') {
  132. if (isset($array['uuid'])) {
  133. db_query("INSERT INTO {term_data_uuid} (tid, uuid) VALUES (%d, '%s')", $array['tid'], $array['uuid']);
  134. }
  135. else {
  136. db_query("INSERT INTO {term_data_uuid} (tid, uuid) VALUES (%d, '%s')", $array['tid'], deploy_uuid_create_uuid());
  137. }
  138. }
  139. else {
  140. if (isset($array['uuid'])) {
  141. db_query("INSERT INTO {vocabulary_uuid} (vid, uuid) VALUES (%d, '%s')", $array['vid'], $array['uuid']);
  142. }
  143. else {
  144. db_query("INSERT INTO {vocabulary_uuid} (vid, uuid) VALUES (%d, '%s')", $array['vid'], deploy_uuid_create_uuid());
  145. }
  146. }
  147. break;
  148. // When a term or vocabulary is deleted, clean out its associated UUID.
  149. case 'delete':
  150. if ($type == 'term') {
  151. db_query("DELETE FROM {term_data_uuid} WHERE tid = %d", $array['tid']);
  152. }
  153. else {
  154. db_query("DELETE FROM {vocabulary_uuid} WHERE vid = %d", $array['vid']);
  155. }
  156. break;
  157. }
  158. }
  159. /**
  160. * Implementation of hook_user().
  161. *
  162. * This mostly relates to managing the mapped uid->uuid mapping. There is some
  163. * non-uuid-related code below, which I decided to keep in this module anyways
  164. * for the purposes of code organization.
  165. */
  166. function deploy_uuid_user($op, &$edit, &$account, $category = NULL) {
  167. switch ($op) {
  168. case 'update':
  169. // Users submitted through deployment contain the original password, which has been MD5 hashed.
  170. // Unforutnately when this user object is passed through user_save, this password is then itself
  171. // MD5 hashed. So in this situation, we need to do an update to the user table forcing the
  172. // password back to its original value.
  173. if ($edit['deploy']) {
  174. db_query("UPDATE {users} SET pass = '%s' WHERE uid = %d", $edit['pass'], $account->uid);
  175. }
  176. break;
  177. case 'after update':
  178. break;
  179. case 'load':
  180. // If the user has an accompanying uuid, then add it to the $account object.
  181. // This makes things easier and cleaner than always having a uuid field and
  182. // having it sometimes be empty.
  183. $uuid = db_result(db_query("SELECT uuid FROM {users_uuid} WHERE uid = %d", $account->uid));
  184. if ($uuid) {
  185. $account->uuid = $uuid;
  186. }
  187. break;
  188. case 'insert':
  189. // The only case in which we would have a node come through insert with a uuid already in place
  190. // is the case where it's being deployed from a remote source. In this case, keep the existing
  191. // uuid. Otherwise, create a new one.
  192. if (!empty($edit['uuid'])) {
  193. db_query("INSERT INTO {users_uuid} (uid, uuid) VALUES (%d, '%s')", $account->uid, $edit['uuid']);
  194. }
  195. else {
  196. db_query("INSERT INTO {users_uuid} (uid, uuid) VALUES (%d, '%s')", $account->uid, deploy_uuid_create_uuid());
  197. }
  198. // Users submitted through deployment contain the original password, which has been MD5 hashed.
  199. // Unforutnately when this user object is passed through user_save, this password is then itself
  200. // MD5 hashed. So in this situation, we need to do an update to the user table forcing the
  201. // password back to its original value.
  202. if ($edit['deploy']) {
  203. db_query("UPDATE {users} SET pass = '%s' WHERE uid = %d", $edit['pass'], $account->uid);
  204. }
  205. break;
  206. case 'delete':
  207. db_query("DELETE FROM {users_uuid} WHERE uid = %d", $account->uid);
  208. break;
  209. }
  210. }
  211. /**
  212. * Implementation of hook_form_alter(),
  213. *
  214. * Add the UUID into all node edit fields so that drupal_executes and form submissions
  215. * handle this data properly. If you don't do this, then the uuid gets lost during
  216. * a node save from drupal_execute(). Same goes for the user register form.
  217. */
  218. function deploy_uuid_form_alter(&$form, $form_state, $form_id) {
  219. if (strpos($form_id, 'node_form') !== FALSE) {
  220. $node = $form['#node'];
  221. $form['uuid'] = array(
  222. '#type' => 'hidden',
  223. '#default_value' => isset($node->uuid) ? $node->uuid : '',
  224. );
  225. }
  226. if (strpos($form_id, 'user_register') !== FALSE) {
  227. $form['uuid'] = array(
  228. '#type' => 'hidden',
  229. '#default_value' => '',
  230. );
  231. $form['deploy'] = array(
  232. '#type' => 'hidden',
  233. '#default_value' => '',
  234. );
  235. }
  236. }
  237. /**
  238. * Implementation of hook_nodeapi(),
  239. *
  240. * This mostly relates to managing the mapped nid->uuid mapping. There is some
  241. * non-uuid-related code below, which I decided to keep in this module anyways
  242. * for the purposes of code organization.
  243. *
  244. * When a node is deployed, it needs its changed property maintained from one
  245. * server to the next. Otherwise there can be situations where the live server thinks
  246. * it has a newer version than staging, when in fact it doesn't. This situation can
  247. * be exacerbated by time zone differences between the two servers. This is why we jump
  248. * through all the hoops below in order to save the existing changed timestamp from the
  249. * pushed in node to save back into the record later. I will write a more detailed
  250. * explanation of the how/why of this later.
  251. */
  252. function deploy_uuid_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  253. //watchdog($op, print_r($node, TRUE));
  254. static $node_deploy = FALSE;
  255. static $deploy_changed = FALSE;
  256. switch ($op) {
  257. // Get the uuid into the node object (if present.)
  258. case 'load':
  259. $uuid = db_result(db_query("SELECT uuid FROM {node_uuid} WHERE nid = %d", $node->nid));
  260. if ($uuid) {
  261. return array('uuid' => $uuid);
  262. }
  263. break;
  264. case 'prepare':
  265. if ($node->deploy) {
  266. $node_deploy = TRUE;
  267. }
  268. break;
  269. case 'presave':
  270. if ($node_deploy) {
  271. $deploy_changed = $node->changed;
  272. }
  273. break;
  274. // Make sure that a new entry gets made in the node_uuid table when new content
  275. // is added.
  276. case 'insert':
  277. if ($node->uuid) {
  278. db_query("INSERT INTO {node_uuid} (nid, uuid) VALUES (%d, '%s')", $node->nid, $node->uuid);
  279. }
  280. else {
  281. db_query("INSERT INTO {node_uuid} (nid, uuid) VALUES (%d, '%s')", $node->nid, deploy_uuid_create_uuid());
  282. }
  283. if ($deploy_changed) {
  284. db_query("UPDATE {node} SET changed = %d WHERE nid = %d", $deploy_changed, $node->nid);
  285. }
  286. break;
  287. case 'update':
  288. if ($deploy_changed) {
  289. db_query("UPDATE {node} SET changed = %d WHERE nid = %d", $deploy_changed, $node->nid);
  290. }
  291. break;
  292. // Clean up node_uuid table when content is deleted.
  293. case 'delete':
  294. db_query("DELETE FROM {node_uuid} WHERE nid = %d", $node->nid);
  295. break;
  296. }
  297. }
  298. /**
  299. * Return the unique key of an item, given its UUID.
  300. *
  301. * I need to come up with a new way to manage this. I am torn by the
  302. * desire to have a single generic function to manage this, and the
  303. * desire to not have so many parameters that you may as well just build
  304. * the SQL yourself. However, the whole if/then to get around nodes
  305. * vs other content types is ugly too so I don't know.
  306. *
  307. * @return array
  308. * Array with the uuid, key, and possibly also a changed date depending
  309. * on the type of information requested.
  310. **/
  311. function deploy_uuid_get_key($uuid, $module) {
  312. // Nodes return their changed date along with their identifying information
  313. // to give node_deploy() information to judge whether or not a dependency
  314. // should be pushed.
  315. if ($module == 'node') {
  316. $result = db_query("SELECT n.nid, u.uuid, n.changed FROM {node} n INNER JOIN {node_uuid} u ON n.nid = u.nid WHERE u.uuid = '%s'", $uuid);
  317. }
  318. else {
  319. $result = db_query("SELECT * FROM {%s} WHERE uuid = '%s'", $module . '_uuid', $uuid);
  320. }
  321. return db_fetch_array($result);
  322. }
  323. function deploy_uuid_get_term_uuid($tid) {
  324. return db_result(db_query("SELECT uuid FROM {term_data_uuid} WHERE tid = %d", $tid));
  325. }
  326. function deploy_uuid_get_vocabulary_uuid($vid) {
  327. return db_result(db_query("SELECT uuid FROM {vocabulary_uuid} WHERE vid = %d", $vid));
  328. }
  329. function deploy_uuid_get_node_uuid($nid) {
  330. return db_result(db_query("SELECT u.uuid, n.changed FROM {node_uuid} u INNER JOIN {node} n on u.nid = n.nid WHERE n.nid = %d", $nid));
  331. }
  332. function deploy_uuid_get_user_uuid($uid) {
  333. return db_result(db_query("SELECT uuid FROM {users_uuid} WHERE uid = %d", $uid));
  334. }
  335. function deploy_uuid_get_comment_uuid($cid) {
  336. return db_result(db_query("SELECT uuid FROM {comments_uuid} WHERE cid = %d", $cid));
  337. }
  338. function deploy_uuid_get_files_uuid($fid) {
  339. return db_result(db_query("SELECT uuid FROM {files_uuid} WHERE fid = %d", $fid));
  340. }
  341. /**
  342. * Standard function to create a unique identifier.
  343. *
  344. * Useful to have in a function in case we decide to change the generation
  345. * method down the road.
  346. *
  347. * @return string
  348. * UUID
  349. **/
  350. function deploy_uuid_create_uuid() {
  351. return uniqid(rand(), TRUE);
  352. }